Added EventSource to Hosting
This commit is contained in:
parent
42594afd42
commit
4abb48e1aa
|
|
@ -43,6 +43,8 @@ namespace Microsoft.AspNetCore.Hosting.Internal
|
|||
_diagnosticSource.Write("Microsoft.AspNetCore.Hosting.BeginRequest", new { httpContext = httpContext, timestamp = startTimestamp });
|
||||
}
|
||||
|
||||
HostingEventSource.Log.RequestStart(httpContext.Request.Method, httpContext.Request.Path);
|
||||
|
||||
return new Context
|
||||
{
|
||||
HttpContext = httpContext,
|
||||
|
|
@ -78,8 +80,12 @@ namespace Microsoft.AspNetCore.Hosting.Internal
|
|||
{
|
||||
_diagnosticSource.Write("Microsoft.AspNetCore.Hosting.UnhandledException", new { httpContext = httpContext, timestamp = currentTimestamp, exception = exception });
|
||||
}
|
||||
|
||||
HostingEventSource.Log.UnhandledException();
|
||||
}
|
||||
|
||||
HostingEventSource.Log.RequestStop();
|
||||
|
||||
context.Scope?.Dispose();
|
||||
|
||||
_httpContextFactory.Dispose(httpContext);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Diagnostics.Tracing;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Hosting.Internal
|
||||
{
|
||||
[EventSource(Name = "Microsoft-AspNetCore-Hosting")]
|
||||
public sealed class HostingEventSource : EventSource
|
||||
{
|
||||
public static readonly HostingEventSource Log = new HostingEventSource();
|
||||
|
||||
private HostingEventSource() { }
|
||||
|
||||
// NOTE
|
||||
// - The 'Start' and 'Stop' suffixes on the following event names have special meaning in EventSource. They
|
||||
// enable creating 'activities'.
|
||||
// For more information, take a look at the following blog post:
|
||||
// https://blogs.msdn.microsoft.com/vancem/2015/09/14/exploring-eventsource-activity-correlation-and-causation-features/
|
||||
// - A stop event's event id must be next one after its start event.
|
||||
|
||||
[Event(1, Level = EventLevel.Informational)]
|
||||
public void HostStart()
|
||||
{
|
||||
WriteEvent(1);
|
||||
}
|
||||
|
||||
[Event(2, Level = EventLevel.Informational)]
|
||||
public void HostStop()
|
||||
{
|
||||
WriteEvent(2);
|
||||
}
|
||||
|
||||
[Event(3, Level = EventLevel.Informational)]
|
||||
public void RequestStart(string method, string path)
|
||||
{
|
||||
WriteEvent(3, method, path);
|
||||
}
|
||||
|
||||
[Event(4, Level = EventLevel.Informational)]
|
||||
public void RequestStop()
|
||||
{
|
||||
WriteEvent(4);
|
||||
}
|
||||
|
||||
[Event(5, Level = EventLevel.Error)]
|
||||
public void UnhandledException()
|
||||
{
|
||||
WriteEvent(5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -97,15 +97,15 @@ namespace Microsoft.AspNetCore.Hosting.Internal
|
|||
|
||||
public virtual void Start()
|
||||
{
|
||||
HostingEventSource.Log.HostStart();
|
||||
_logger = _applicationServices.GetRequiredService<ILogger<WebHost>>();
|
||||
_logger.Starting();
|
||||
|
||||
Initialize();
|
||||
|
||||
_applicationLifetime = _applicationServices.GetRequiredService<IApplicationLifetime>() as ApplicationLifetime;
|
||||
_logger = _applicationServices.GetRequiredService<ILogger<WebHost>>();
|
||||
var diagnosticSource = _applicationServices.GetRequiredService<DiagnosticSource>();
|
||||
var httpContextFactory = _applicationServices.GetRequiredService<IHttpContextFactory>();
|
||||
|
||||
_logger.Starting();
|
||||
|
||||
Server.Start(new HostingApplication(_application, _logger, diagnosticSource, httpContextFactory));
|
||||
|
||||
_applicationLifetime?.NotifyStarted();
|
||||
|
|
@ -247,6 +247,8 @@ namespace Microsoft.AspNetCore.Hosting.Internal
|
|||
(_hostingServiceProvider as IDisposable)?.Dispose();
|
||||
(_applicationServices as IDisposable)?.Dispose();
|
||||
_applicationLifetime?.NotifyStopped();
|
||||
|
||||
HostingEventSource.Log.HostStop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,9 @@ namespace Microsoft.AspNetCore.Hosting.Tests
|
|||
// Arrange
|
||||
var httpContextFactory = new HttpContextFactory(new DefaultObjectPoolProvider(), Options.Create(new FormOptions()), new HttpContextAccessor());
|
||||
var hostingApplication = new HostingApplication(ctx => Task.FromResult(0), new NullScopeLogger(), new NoopDiagnosticSource(), httpContextFactory);
|
||||
var context = hostingApplication.CreateContext(new FeatureCollection());
|
||||
var features = new FeatureCollection();
|
||||
features.Set<IHttpRequestFeature>(new HttpRequestFeature());
|
||||
var context = hostingApplication.CreateContext(features);
|
||||
|
||||
// Act/Assert
|
||||
hostingApplication.DisposeContext(context, null);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,227 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.Tracing;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Hosting.Internal
|
||||
{
|
||||
public class HostingEventSourceTests
|
||||
{
|
||||
[Fact]
|
||||
public void MatchesNameAndGuid()
|
||||
{
|
||||
// Arrange & Act
|
||||
var eventSourceType = typeof(WebHost).GetTypeInfo().Assembly.GetType(
|
||||
"Microsoft.AspNetCore.Hosting.Internal.HostingEventSource",
|
||||
throwOnError: true,
|
||||
ignoreCase: false);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(eventSourceType);
|
||||
Assert.Equal("Microsoft-AspNetCore-Hosting", EventSource.GetName(eventSourceType));
|
||||
Assert.Equal(Guid.Parse("9e620d2a-55d4-5ade-deb7-c26046d245a8"), EventSource.GetGuid(eventSourceType));
|
||||
Assert.NotEmpty(EventSource.GenerateManifest(eventSourceType, "assemblyPathToIncludeInManifest"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HostStart()
|
||||
{
|
||||
// Arrange
|
||||
var expectedEventId = 1;
|
||||
var eventListener = new TestEventListener(expectedEventId);
|
||||
var hostingEventSource = HostingEventSource.Log;
|
||||
eventListener.EnableEvents(hostingEventSource, EventLevel.Informational);
|
||||
|
||||
// Act
|
||||
hostingEventSource.HostStart();
|
||||
|
||||
// Assert
|
||||
var eventData = eventListener.EventData;
|
||||
Assert.NotNull(eventData);
|
||||
Assert.Equal(expectedEventId, eventData.EventId);
|
||||
#if NETCOREAPP1_1
|
||||
Assert.Equal("HostStart", eventData.EventName);
|
||||
#endif
|
||||
Assert.Equal(EventLevel.Informational, eventData.Level);
|
||||
Assert.Same(hostingEventSource, eventData.EventSource);
|
||||
Assert.Null(eventData.Message);
|
||||
Assert.Empty(eventData.Payload);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HostStop()
|
||||
{
|
||||
// Arrange
|
||||
var expectedEventId = 2;
|
||||
var eventListener = new TestEventListener(expectedEventId);
|
||||
var hostingEventSource = HostingEventSource.Log;
|
||||
eventListener.EnableEvents(hostingEventSource, EventLevel.Informational);
|
||||
|
||||
// Act
|
||||
hostingEventSource.HostStop();
|
||||
|
||||
// Assert
|
||||
var eventData = eventListener.EventData;
|
||||
Assert.NotNull(eventData);
|
||||
Assert.Equal(expectedEventId, eventData.EventId);
|
||||
#if NETCOREAPP1_1
|
||||
Assert.Equal("HostStop", eventData.EventName);
|
||||
#endif
|
||||
Assert.Equal(EventLevel.Informational, eventData.Level);
|
||||
Assert.Same(hostingEventSource, eventData.EventSource);
|
||||
Assert.Null(eventData.Message);
|
||||
Assert.Empty(eventData.Payload);
|
||||
}
|
||||
|
||||
public static TheoryData<DefaultHttpContext, string[]> RequestStartData
|
||||
{
|
||||
get
|
||||
{
|
||||
var variations = new TheoryData<DefaultHttpContext, string[]>();
|
||||
|
||||
var context = new DefaultHttpContext();
|
||||
context.Request.Method = "GET";
|
||||
context.Request.Path = "/Home/Index";
|
||||
variations.Add(
|
||||
context,
|
||||
new string[]
|
||||
{
|
||||
"GET",
|
||||
"/Home/Index"
|
||||
});
|
||||
|
||||
context = new DefaultHttpContext();
|
||||
context.Request.Method = "POST";
|
||||
context.Request.Path = "/";
|
||||
variations.Add(
|
||||
context,
|
||||
new string[]
|
||||
{
|
||||
"POST",
|
||||
"/"
|
||||
});
|
||||
|
||||
return variations;
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(RequestStartData))]
|
||||
public void RequestStart(DefaultHttpContext httpContext, string[] expected)
|
||||
{
|
||||
// Arrange
|
||||
var expectedEventId = 3;
|
||||
var eventListener = new TestEventListener(expectedEventId);
|
||||
var hostingEventSource = HostingEventSource.Log;
|
||||
eventListener.EnableEvents(hostingEventSource, EventLevel.Informational);
|
||||
|
||||
// Act
|
||||
hostingEventSource.RequestStart(httpContext.Request.Method, httpContext.Request.Path);
|
||||
|
||||
// Assert
|
||||
var eventData = eventListener.EventData;
|
||||
Assert.NotNull(eventData);
|
||||
Assert.Equal(expectedEventId, eventData.EventId);
|
||||
#if NETCOREAPP1_1
|
||||
Assert.Equal("RequestStart", eventData.EventName);
|
||||
#endif
|
||||
Assert.Equal(EventLevel.Informational, eventData.Level);
|
||||
Assert.Same(hostingEventSource, eventData.EventSource);
|
||||
Assert.Null(eventData.Message);
|
||||
|
||||
var payloadList = eventData.Payload;
|
||||
Assert.Equal(expected.Length, payloadList.Count);
|
||||
for (var i = 0; i < expected.Length; i++)
|
||||
{
|
||||
Assert.Equal(expected[i], payloadList[i]);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RequestStop()
|
||||
{
|
||||
// Arrange
|
||||
var expectedEventId = 4;
|
||||
var eventListener = new TestEventListener(expectedEventId);
|
||||
var hostingEventSource = HostingEventSource.Log;
|
||||
eventListener.EnableEvents(hostingEventSource, EventLevel.Informational);
|
||||
|
||||
// Act
|
||||
hostingEventSource.RequestStop();
|
||||
|
||||
// Assert
|
||||
var eventData = eventListener.EventData;
|
||||
Assert.Equal(expectedEventId, eventData.EventId);
|
||||
#if NETCOREAPP1_1
|
||||
Assert.Equal("RequestStop", eventData.EventName);
|
||||
#endif
|
||||
Assert.Equal(EventLevel.Informational, eventData.Level);
|
||||
Assert.Same(hostingEventSource, eventData.EventSource);
|
||||
Assert.Null(eventData.Message);
|
||||
Assert.Equal(0, eventData.Payload.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UnhandledException()
|
||||
{
|
||||
// Arrange
|
||||
var expectedEventId = 5;
|
||||
var eventListener = new TestEventListener(expectedEventId);
|
||||
var hostingEventSource = HostingEventSource.Log;
|
||||
eventListener.EnableEvents(hostingEventSource, EventLevel.Informational);
|
||||
|
||||
// Act
|
||||
hostingEventSource.UnhandledException();
|
||||
|
||||
// Assert
|
||||
var eventData = eventListener.EventData;
|
||||
Assert.Equal(expectedEventId, eventData.EventId);
|
||||
#if NETCOREAPP1_1
|
||||
Assert.Equal("UnhandledException", eventData.EventName);
|
||||
#endif
|
||||
Assert.Equal(EventLevel.Error, eventData.Level);
|
||||
Assert.Same(hostingEventSource, eventData.EventSource);
|
||||
Assert.Null(eventData.Message);
|
||||
Assert.Equal(0, eventData.Payload.Count);
|
||||
}
|
||||
|
||||
private static Exception GetException()
|
||||
{
|
||||
try
|
||||
{
|
||||
throw new InvalidOperationException("An invalid operation has occurred");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ex;
|
||||
}
|
||||
}
|
||||
|
||||
private class TestEventListener : EventListener
|
||||
{
|
||||
private readonly int _eventId;
|
||||
|
||||
public TestEventListener(int eventId)
|
||||
{
|
||||
_eventId = eventId;
|
||||
}
|
||||
|
||||
public EventWrittenEventArgs EventData { get; private set; }
|
||||
|
||||
protected override void OnEventWritten(EventWrittenEventArgs eventData)
|
||||
{
|
||||
// The tests here run in parallel and since the single publisher instance (HostingEventingSource)
|
||||
// notifies all listener instances in these tests, capture the EventData that a test is explicitly
|
||||
// looking for and not give back other tests' data.
|
||||
if (eventData.EventId == _eventId)
|
||||
{
|
||||
EventData = eventData;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue