From a776a5ef601509c0e3b0cc3e3d7cb7fe599d909a Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Tue, 19 Mar 2019 18:13:45 -0700 Subject: [PATCH 01/12] Remove DiagnosticAdapter and use DiagnosticListener directly --- .../HostingDiagnosticListener.cs | 114 +++++++++++++++--- .../IApplicationInsightDiagnosticListener.cs | 6 +- .../Implementation/MvcDiagnosticsListener.cs | 62 ++++++---- .../Implementation/PropertyFetcher.cs | 76 ++++++++++++ .../Extensions/HttpRequestExtensions.cs | 4 +- ...soft.ApplicationInsights.AspNetCore.csproj | 2 - .../RequestTrackingTelemetryModule.cs | 2 +- .../OperationNameTelemetryInitializerTests.cs | 12 +- 8 files changed, 226 insertions(+), 52 deletions(-) create mode 100644 src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/PropertyFetcher.cs diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs index ae58fb36..2983d130 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs @@ -1,4 +1,6 @@ -namespace Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners +using System.Collections.Generic; + +namespace Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners { using System; using System.Diagnostics; @@ -7,6 +9,7 @@ using System.Net.Http.Headers; using System.Text; using Extensibility.Implementation.Tracing; + using Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners.Implementation; using Microsoft.ApplicationInsights.AspNetCore.Extensions; using Microsoft.ApplicationInsights.Common; using Microsoft.ApplicationInsights.DataContracts; @@ -14,7 +17,6 @@ using Microsoft.ApplicationInsights.Extensibility.Implementation; using Microsoft.ApplicationInsights.Extensibility.W3C; using Microsoft.AspNetCore.Http; - using Microsoft.Extensions.DiagnosticAdapter; using Microsoft.Extensions.Primitives; /// @@ -38,6 +40,24 @@ internal class HostingDiagnosticListener : IApplicationInsightDiagnosticListener private static readonly ActiveSubsciptionManager SubscriptionManager = new ActiveSubsciptionManager(); private const string ActivityCreatedByHostingDiagnosticListener = "ActivityCreatedByHostingDiagnosticListener"; + #region fetchers + + // fetch is unique per event and per property + private readonly PropertyFetcher httpContextFetcherStart = new PropertyFetcher("HttpContext"); + private readonly PropertyFetcher httpContextFetcherStop = new PropertyFetcher("HttpContext"); + private readonly PropertyFetcher httpContextFetcherBeginRequest = new PropertyFetcher("httpContext"); + private readonly PropertyFetcher httpContextFetcherEndRequest = new PropertyFetcher("httpContext"); + private readonly PropertyFetcher httpContextFetcherDiagExceptionUnhandled = new PropertyFetcher("httpContext"); + private readonly PropertyFetcher httpContextFetcherDiagExceptionHandled = new PropertyFetcher("httpContext"); + private readonly PropertyFetcher httpContextFetcherHostingExceptionUnhandled = new PropertyFetcher("httpContext"); + private readonly PropertyFetcher exceptionFetcherDiagExceptionUnhandled = new PropertyFetcher("exception"); + private readonly PropertyFetcher exceptionFetcherDiagExceptionHandled = new PropertyFetcher("exception"); + private readonly PropertyFetcher exceptionFetcherHostingExceptionUnhandled = new PropertyFetcher("exception"); + + private readonly PropertyFetcher timestampFetcherBeginRequest = new PropertyFetcher("timestamp"); + private readonly PropertyFetcher timestampFetcherEndRequest = new PropertyFetcher("timestamp"); + #endregion + /// /// Initializes a new instance of the class. /// @@ -72,19 +92,9 @@ public void OnSubscribe() /// public string ListenerName { get; } = "Microsoft.AspNetCore"; - /// - /// Diagnostic event handler method for 'Microsoft.AspNetCore.Hosting.HttpRequestIn' event. - /// - [DiagnosticName("Microsoft.AspNetCore.Hosting.HttpRequestIn")] - public void OnHttpRequestIn() - { - // do nothing, just enable the diagnostic source - } - /// /// Diagnostic event handler method for 'Microsoft.AspNetCore.Hosting.HttpRequestIn.Start' event. /// - [DiagnosticName("Microsoft.AspNetCore.Hosting.HttpRequestIn.Start")] public void OnHttpRequestInStart(HttpContext httpContext) { if (this.client.IsEnabled()) @@ -176,7 +186,6 @@ public void OnHttpRequestInStart(HttpContext httpContext) /// /// Diagnostic event handler method for 'Microsoft.AspNetCore.Hosting.HttpRequestIn.Stop' event. /// - [DiagnosticName("Microsoft.AspNetCore.Hosting.HttpRequestIn.Stop")] public void OnHttpRequestInStop(HttpContext httpContext) { EndRequest(httpContext, Stopwatch.GetTimestamp()); @@ -185,7 +194,6 @@ public void OnHttpRequestInStop(HttpContext httpContext) /// /// Diagnostic event handler method for 'Microsoft.AspNetCore.Hosting.BeginRequest' event. /// - [DiagnosticName("Microsoft.AspNetCore.Hosting.BeginRequest")] public void OnBeginRequest(HttpContext httpContext, long timestamp) { if (this.client.IsEnabled() && !this.enableNewDiagnosticEvents) @@ -282,7 +290,6 @@ public void OnBeginRequest(HttpContext httpContext, long timestamp) /// /// Diagnostic event handler method for 'Microsoft.AspNetCore.Hosting.EndRequest' event. /// - [DiagnosticName("Microsoft.AspNetCore.Hosting.EndRequest")] public void OnEndRequest(HttpContext httpContext, long timestamp) { if (!this.enableNewDiagnosticEvents) @@ -294,7 +301,6 @@ public void OnEndRequest(HttpContext httpContext, long timestamp) /// /// Diagnostic event handler method for 'Microsoft.AspNetCore.Hosting.UnhandledException' event. /// - [DiagnosticName("Microsoft.AspNetCore.Hosting.UnhandledException")] public void OnHostingException(HttpContext httpContext, Exception exception) { this.OnException(httpContext, exception); @@ -310,7 +316,6 @@ public void OnHostingException(HttpContext httpContext, Exception exception) /// /// Diagnostic event handler method for 'Microsoft.AspNetCore.Hosting.HandledException' event. /// - [DiagnosticName("Microsoft.AspNetCore.Diagnostics.HandledException")] public void OnDiagnosticsHandledException(HttpContext httpContext, Exception exception) { this.OnException(httpContext, exception); @@ -319,7 +324,6 @@ public void OnDiagnosticsHandledException(HttpContext httpContext, Exception exc /// /// Diagnostic event handler method for 'Microsoft.AspNetCore.Diagnostics.UnhandledException' event. /// - [DiagnosticName("Microsoft.AspNetCore.Diagnostics.UnhandledException")] public void OnDiagnosticsUnhandledException(HttpContext httpContext, Exception exception) { this.OnException(httpContext, exception); @@ -559,5 +563,79 @@ public void Dispose() { SubscriptionManager.Detach(this); } + + public void OnNext(KeyValuePair value) + { + if (value.Key == "Microsoft.AspNetCore.Hosting.HttpRequestIn.Start") + { + if (this.httpContextFetcherStart.Fetch(value.Value) is HttpContext context) + { + this.OnHttpRequestInStart(context); + } + } + else if (value.Key == "Microsoft.AspNetCore.Hosting.HttpRequestIn.Stop") + { + if (this.httpContextFetcherStop.Fetch(value.Value) is HttpContext context) + { + this.OnHttpRequestInStop(context); + } + } + else if (value.Key == "Microsoft.AspNetCore.Hosting.BeginRequest") + { + var httpContext = this.httpContextFetcherBeginRequest.Fetch(value.Value) as HttpContext; + var timestamp = this.timestampFetcherBeginRequest.Fetch(value.Value) as long?; + if (httpContext != null && timestamp.HasValue) + { + this.OnBeginRequest(httpContext, timestamp.Value); + } + } + else if (value.Key == "Microsoft.AspNetCore.Hosting.EndRequest") + { + var httpContext = this.httpContextFetcherEndRequest.Fetch(value.Value) as HttpContext; + var timestamp = this.timestampFetcherEndRequest.Fetch(value.Value) as long?; + if (httpContext != null && timestamp.HasValue) + { + this.OnEndRequest(httpContext, timestamp.Value); + } + } + else if (value.Key == "Microsoft.AspNetCore.Diagnostics.UnhandledException") + { + var httpContext = this.httpContextFetcherDiagExceptionUnhandled.Fetch(value.Value) as HttpContext; + var exception = this.exceptionFetcherDiagExceptionUnhandled.Fetch(value.Value) as Exception; + if (httpContext != null && exception != null) + { + this.OnDiagnosticsUnhandledException(httpContext, exception); + } + } + else if (value.Key == "Microsoft.AspNetCore.Diagnostics.HandledException") + { + var httpContext = this.httpContextFetcherDiagExceptionHandled.Fetch(value.Value) as HttpContext; + var exception = this.exceptionFetcherDiagExceptionHandled.Fetch(value.Value) as Exception; + if (httpContext != null && exception != null) + { + this.OnDiagnosticsHandledException(httpContext, exception); + } + } + else if (value.Key == "Microsoft.AspNetCore.Hosting.UnhandledException") + { + var httpContext = this.httpContextFetcherHostingExceptionUnhandled.Fetch(value.Value) as HttpContext; + var exception = this.exceptionFetcherHostingExceptionUnhandled.Fetch(value.Value) as Exception; + if (httpContext != null && exception != null) + { + this.OnHostingException(httpContext, exception); + } + } + } + + /// + public void OnError(Exception error) + { + } + + /// + public void OnCompleted() + { + } + } } \ No newline at end of file diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/IApplicationInsightDiagnosticListener.cs b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/IApplicationInsightDiagnosticListener.cs index 95aec59f..97ed4b51 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/IApplicationInsightDiagnosticListener.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/IApplicationInsightDiagnosticListener.cs @@ -1,11 +1,13 @@ -namespace Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners +using System.Collections.Generic; + +namespace Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners { using System; /// /// Base diagnostic listener type for Application Insight /// - internal interface IApplicationInsightDiagnosticListener : IDisposable + internal interface IApplicationInsightDiagnosticListener : IDisposable, IObserver> { /// /// Gets a value indicating which listener this instance should be subscribed to diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/MvcDiagnosticsListener.cs b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/MvcDiagnosticsListener.cs index 81811608..70b5df30 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/MvcDiagnosticsListener.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/MvcDiagnosticsListener.cs @@ -1,3 +1,5 @@ +using Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners.Implementation; + namespace Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners { using System; @@ -5,7 +7,6 @@ namespace Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners using System.Linq; using Microsoft.ApplicationInsights.DataContracts; using Microsoft.AspNetCore.Http; - using Microsoft.Extensions.DiagnosticAdapter; /// /// implementation that listens for evens specific to AspNetCore Mvc layer @@ -15,17 +16,20 @@ public class MvcDiagnosticsListener : IApplicationInsightDiagnosticListener /// public string ListenerName { get; } = "Microsoft.AspNetCore"; + private readonly PropertyFetcher httpContextFetcher = new PropertyFetcher("httpContext"); + private readonly PropertyFetcher routeDataFetcher = new PropertyFetcher("routeData"); + private readonly PropertyFetcher routeValuesFetcher = new PropertyFetcher("Values"); + /// /// Diagnostic event handler method for 'Microsoft.AspNetCore.Mvc.BeforeAction' event /// - [DiagnosticName("Microsoft.AspNetCore.Mvc.BeforeAction")] - public void OnBeforeAction(HttpContext httpContext, IRouteData routeData) + public void OnBeforeAction(HttpContext httpContext, IDictionary routeValues) { var telemetry = httpContext.Features.Get(); if (telemetry != null && string.IsNullOrEmpty(telemetry.Name)) { - string name = this.GetNameFromRouteContext(routeData); + string name = this.GetNameFromRouteContext(routeValues); if (!string.IsNullOrEmpty(name)) { @@ -35,19 +39,12 @@ public void OnBeforeAction(HttpContext httpContext, IRouteData routeData) } } - /// - public void OnSubscribe() - { - } - - private string GetNameFromRouteContext(IRouteData routeData) + private string GetNameFromRouteContext(IDictionary routeValues) { string name = null; - if (routeData.Values.Count > 0) + if (routeValues.Count > 0) { - var routeValues = routeData.Values; - object controller; routeValues.TryGetValue("controller", out controller); string controllerString = (controller == null) ? string.Empty : controller.ToString(); @@ -98,19 +95,40 @@ private string GetNameFromRouteContext(IRouteData routeData) return name; } - public void Dispose() + /// + public void OnSubscribe() { } - /// - /// Proxy interface for RouteData class from Microsoft.AspNetCore.Routing.Abstractions - /// - public interface IRouteData + /// + public void OnNext(KeyValuePair value) + { + if (value.Key == "Microsoft.AspNetCore.Mvc.BeforeAction") + { + var context = httpContextFetcher.Fetch(value.Value) as HttpContext; + var routeData = routeDataFetcher.Fetch(value.Value); + var routeValues = routeValuesFetcher.Fetch(routeData) as IDictionary; + + if (context != null && routeValues != null) + { + this.OnBeforeAction(context, routeValues); + } + } + } + + /// + public void OnError(Exception error) + { + } + + /// + public void OnCompleted() + { + } + + /// + public void Dispose() { - /// - /// Gets the set of values produced by routes on the current routing path. - /// - IDictionary Values { get; } } } } \ No newline at end of file diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/PropertyFetcher.cs b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/PropertyFetcher.cs new file mode 100644 index 00000000..a234138d --- /dev/null +++ b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/PropertyFetcher.cs @@ -0,0 +1,76 @@ +namespace Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners.Implementation +{ + using System; + using System.Reflection; + + // see https://github.com/dotnet/corefx/blob/master/src/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/DiagnosticSourceEventSource.cs + /// + /// Efficient implementation of fetching properties of anonymous types with reflection. + /// + internal class PropertyFetcher + { + private readonly string propertyName; + private PropertyFetch innerFetcher; + + public PropertyFetcher(string propertyName) + { + this.propertyName = propertyName; + } + + public object Fetch(object obj) + { + if (this.innerFetcher == null) + { + this.innerFetcher = PropertyFetch.FetcherForProperty(obj.GetType().GetTypeInfo().GetDeclaredProperty(this.propertyName)); + } + + return this.innerFetcher?.Fetch(obj); + } + + private class PropertyFetch + { + /// + /// Create a property fetcher from a .NET Reflection PropertyInfo class that + /// represents a property of a particular type. + /// + public static PropertyFetch FetcherForProperty(PropertyInfo propertyInfo) + { + if (propertyInfo == null) + { + // returns null on any fetch. + return new PropertyFetch(); + } + + var typedPropertyFetcher = typeof(TypedFetchProperty<,>); + var instantiatedTypedPropertyFetcher = typedPropertyFetcher.GetTypeInfo().MakeGenericType( + propertyInfo.DeclaringType, propertyInfo.PropertyType); + return (PropertyFetch)Activator.CreateInstance(instantiatedTypedPropertyFetcher, propertyInfo); + } + + /// + /// Given an object, fetch the property that this propertyFetch represents. + /// + public virtual object Fetch(object obj) + { + return null; + } + + private class TypedFetchProperty : PropertyFetch + { + private readonly Func propertyFetch; + + public TypedFetchProperty(PropertyInfo property) + { + this.propertyFetch = + (Func) + property.GetMethod.CreateDelegate(typeof(Func)); + } + + public override object Fetch(object obj) + { + return this.propertyFetch((TObject)obj); + } + } + } + } +} diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/Extensions/HttpRequestExtensions.cs b/src/Microsoft.ApplicationInsights.AspNetCore/Extensions/HttpRequestExtensions.cs index 66479425..a5b0fd18 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/Extensions/HttpRequestExtensions.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/Extensions/HttpRequestExtensions.cs @@ -1,4 +1,6 @@ -namespace Microsoft.ApplicationInsights.AspNetCore.Extensions +using Microsoft.AspNetCore.Http.Extensions; + +namespace Microsoft.ApplicationInsights.AspNetCore.Extensions { using System; using System.Text; diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/Microsoft.ApplicationInsights.AspNetCore.csproj b/src/Microsoft.ApplicationInsights.AspNetCore/Microsoft.ApplicationInsights.AspNetCore.csproj index afa21aea..07f3488d 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/Microsoft.ApplicationInsights.AspNetCore.csproj +++ b/src/Microsoft.ApplicationInsights.AspNetCore/Microsoft.ApplicationInsights.AspNetCore.csproj @@ -89,7 +89,6 @@ - @@ -97,7 +96,6 @@ - diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/RequestTrackingTelemetryModule.cs b/src/Microsoft.ApplicationInsights.AspNetCore/RequestTrackingTelemetryModule.cs index fb3e3313..088c2d03 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/RequestTrackingTelemetryModule.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/RequestTrackingTelemetryModule.cs @@ -105,7 +105,7 @@ void IObserver.OnNext(DiagnosticListener value) { if (applicationInsightDiagnosticListener.ListenerName == value.Name) { - subs.Add(value.SubscribeWithAdapter(applicationInsightDiagnosticListener)); + subs.Add(value.Subscribe(applicationInsightDiagnosticListener)); applicationInsightDiagnosticListener.OnSubscribe(); } } diff --git a/test/Microsoft.ApplicationInsights.AspNetCore.Tests/TelemetryInitializers/OperationNameTelemetryInitializerTests.cs b/test/Microsoft.ApplicationInsights.AspNetCore.Tests/TelemetryInitializers/OperationNameTelemetryInitializerTests.cs index 10fd3927..27d25e65 100644 --- a/test/Microsoft.ApplicationInsights.AspNetCore.Tests/TelemetryInitializers/OperationNameTelemetryInitializerTests.cs +++ b/test/Microsoft.ApplicationInsights.AspNetCore.Tests/TelemetryInitializers/OperationNameTelemetryInitializerTests.cs @@ -86,7 +86,7 @@ public void InitializeSetsTelemetryOperationNameToControllerFromActionContext() var telemetryListener = new DiagnosticListener(TestListenerName); var initializer = new MvcDiagnosticsListener(); - telemetryListener.SubscribeWithAdapter(initializer); + telemetryListener.Subscribe(initializer); telemetryListener.Write("Microsoft.AspNetCore.Mvc.BeforeAction", new { httpContext = contextAccessor.HttpContext, routeData = actionContext.RouteData }); @@ -107,7 +107,7 @@ public void InitializeSetsTelemetryOperationNameToControllerAndActionFromActionC var telemetryListener = new DiagnosticListener(TestListenerName); var initializer = new MvcDiagnosticsListener(); - telemetryListener.SubscribeWithAdapter(initializer); + telemetryListener.Subscribe(initializer); telemetryListener.Write("Microsoft.AspNetCore.Mvc.BeforeAction", new { httpContext = contextAccessor.HttpContext, routeData = actionContext.RouteData }); @@ -127,7 +127,7 @@ public void InitializeSetsTelemetryOperationNameToPageFromActionContext() var telemetryListener = new DiagnosticListener(TestListenerName); var initializer = new MvcDiagnosticsListener(); - telemetryListener.SubscribeWithAdapter(initializer); + telemetryListener.Subscribe(initializer); telemetryListener.Write("Microsoft.AspNetCore.Mvc.BeforeAction", new { httpContext = contextAccessor.HttpContext, routeData = actionContext.RouteData }); @@ -149,7 +149,7 @@ public void InitializeSetsTelemetryOperationNameToControllerAndActionAndParamete var telemetryListener = new DiagnosticListener(TestListenerName); var initializer = new MvcDiagnosticsListener(); - telemetryListener.SubscribeWithAdapter(initializer); + telemetryListener.Subscribe(initializer); telemetryListener.Write("Microsoft.AspNetCore.Mvc.BeforeAction", new { httpContext = contextAccessor.HttpContext, routeData = actionContext.RouteData }); @@ -173,7 +173,7 @@ public void InitializeSortsParameters() var telemetryListener = new DiagnosticListener(TestListenerName); var initializer = new MvcDiagnosticsListener(); - telemetryListener.SubscribeWithAdapter(initializer); + telemetryListener.Subscribe(initializer); telemetryListener.Write("Microsoft.AspNetCore.Mvc.BeforeAction", new { httpContext = contextAccessor.HttpContext, routeData = actionContext.RouteData }); @@ -194,7 +194,7 @@ public void InitializeDoesNotIncludeRouteGroupKeyInParametersList() var contextAccessor = HttpContextAccessorHelper.CreateHttpContextAccessor(new RequestTelemetry(), actionContext); var telemetryListener = new DiagnosticListener(TestListenerName); var initializer = new MvcDiagnosticsListener(); - telemetryListener.SubscribeWithAdapter(initializer); + telemetryListener.Subscribe(initializer); telemetryListener.Write("Microsoft.AspNetCore.Mvc.BeforeAction", new { httpContext = contextAccessor.HttpContext, routeData = actionContext.RouteData }); From 82f492c9bb494cb80963a32c4d3bc54fa1a33de1 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Tue, 19 Mar 2019 18:17:49 -0700 Subject: [PATCH 02/12] minor fixes --- .../Implementation/HostingDiagnosticListener.cs | 5 ++--- .../Implementation/MvcDiagnosticsListener.cs | 3 +-- .../Extensions/HttpRequestExtensions.cs | 4 +--- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs index 2983d130..65b5a238 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs @@ -1,8 +1,7 @@ -using System.Collections.Generic; - -namespace Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners +namespace Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners { using System; + using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/MvcDiagnosticsListener.cs b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/MvcDiagnosticsListener.cs index 70b5df30..48c25853 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/MvcDiagnosticsListener.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/MvcDiagnosticsListener.cs @@ -1,10 +1,9 @@ -using Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners.Implementation; - namespace Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners { using System; using System.Collections.Generic; using System.Linq; + using Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners.Implementation; using Microsoft.ApplicationInsights.DataContracts; using Microsoft.AspNetCore.Http; diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/Extensions/HttpRequestExtensions.cs b/src/Microsoft.ApplicationInsights.AspNetCore/Extensions/HttpRequestExtensions.cs index a5b0fd18..66479425 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/Extensions/HttpRequestExtensions.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/Extensions/HttpRequestExtensions.cs @@ -1,6 +1,4 @@ -using Microsoft.AspNetCore.Http.Extensions; - -namespace Microsoft.ApplicationInsights.AspNetCore.Extensions +namespace Microsoft.ApplicationInsights.AspNetCore.Extensions { using System; using System.Text; From 44e550e6e411925129c5725a4e666a2af51e6551 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Wed, 20 Mar 2019 11:36:51 -0700 Subject: [PATCH 03/12] switch --- .../HostingDiagnosticListener.cs | 116 +++++++++--------- .../IApplicationInsightDiagnosticListener.cs | 5 +- 2 files changed, 61 insertions(+), 60 deletions(-) diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs index 65b5a238..f90b2d27 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs @@ -565,64 +565,66 @@ public void Dispose() public void OnNext(KeyValuePair value) { - if (value.Key == "Microsoft.AspNetCore.Hosting.HttpRequestIn.Start") - { - if (this.httpContextFetcherStart.Fetch(value.Value) is HttpContext context) - { - this.OnHttpRequestInStart(context); - } - } - else if (value.Key == "Microsoft.AspNetCore.Hosting.HttpRequestIn.Stop") - { - if (this.httpContextFetcherStop.Fetch(value.Value) is HttpContext context) - { - this.OnHttpRequestInStop(context); - } - } - else if (value.Key == "Microsoft.AspNetCore.Hosting.BeginRequest") - { - var httpContext = this.httpContextFetcherBeginRequest.Fetch(value.Value) as HttpContext; - var timestamp = this.timestampFetcherBeginRequest.Fetch(value.Value) as long?; - if (httpContext != null && timestamp.HasValue) - { - this.OnBeginRequest(httpContext, timestamp.Value); - } - } - else if (value.Key == "Microsoft.AspNetCore.Hosting.EndRequest") - { - var httpContext = this.httpContextFetcherEndRequest.Fetch(value.Value) as HttpContext; - var timestamp = this.timestampFetcherEndRequest.Fetch(value.Value) as long?; - if (httpContext != null && timestamp.HasValue) - { - this.OnEndRequest(httpContext, timestamp.Value); - } - } - else if (value.Key == "Microsoft.AspNetCore.Diagnostics.UnhandledException") - { - var httpContext = this.httpContextFetcherDiagExceptionUnhandled.Fetch(value.Value) as HttpContext; - var exception = this.exceptionFetcherDiagExceptionUnhandled.Fetch(value.Value) as Exception; - if (httpContext != null && exception != null) - { - this.OnDiagnosticsUnhandledException(httpContext, exception); - } - } - else if (value.Key == "Microsoft.AspNetCore.Diagnostics.HandledException") - { - var httpContext = this.httpContextFetcherDiagExceptionHandled.Fetch(value.Value) as HttpContext; - var exception = this.exceptionFetcherDiagExceptionHandled.Fetch(value.Value) as Exception; - if (httpContext != null && exception != null) - { - this.OnDiagnosticsHandledException(httpContext, exception); - } - } - else if (value.Key == "Microsoft.AspNetCore.Hosting.UnhandledException") + HttpContext httpContext = null; + Exception exception = null; + long? timestamp = null; + + switch (value.Key) { - var httpContext = this.httpContextFetcherHostingExceptionUnhandled.Fetch(value.Value) as HttpContext; - var exception = this.exceptionFetcherHostingExceptionUnhandled.Fetch(value.Value) as Exception; - if (httpContext != null && exception != null) - { - this.OnHostingException(httpContext, exception); - } + case "Microsoft.AspNetCore.Hosting.HttpRequestIn.Start": + httpContext = this.httpContextFetcherStart.Fetch(value.Value) as HttpContext; + if (httpContext != null) + { + this.OnHttpRequestInStart(httpContext); + } + break; + case "Microsoft.AspNetCore.Hosting.HttpRequestIn.Stop": + httpContext = this.httpContextFetcherStop.Fetch(value.Value) as HttpContext; + if (httpContext != null) + { + this.OnHttpRequestInStop(httpContext); + } + break; + case "Microsoft.AspNetCore.Hosting.BeginRequest": + httpContext = this.httpContextFetcherBeginRequest.Fetch(value.Value) as HttpContext; + timestamp = this.timestampFetcherBeginRequest.Fetch(value.Value) as long?; + if (httpContext != null && timestamp.HasValue) + { + this.OnBeginRequest(httpContext, timestamp.Value); + } + break; + case "Microsoft.AspNetCore.Hosting.EndRequest": + httpContext = this.httpContextFetcherEndRequest.Fetch(value.Value) as HttpContext; + timestamp = this.timestampFetcherEndRequest.Fetch(value.Value) as long?; + if (httpContext != null && timestamp.HasValue) + { + this.OnEndRequest(httpContext, timestamp.Value); + } + break; + case "Microsoft.AspNetCore.Diagnostics.UnhandledException": + httpContext = this.httpContextFetcherDiagExceptionUnhandled.Fetch(value.Value) as HttpContext; + exception = this.exceptionFetcherDiagExceptionUnhandled.Fetch(value.Value) as Exception; + if (httpContext != null && exception != null) + { + this.OnDiagnosticsUnhandledException(httpContext, exception); + } + break; + case "Microsoft.AspNetCore.Diagnostics.HandledException": + httpContext = this.httpContextFetcherDiagExceptionHandled.Fetch(value.Value) as HttpContext; + exception = this.exceptionFetcherDiagExceptionHandled.Fetch(value.Value) as Exception; + if (httpContext != null && exception != null) + { + this.OnDiagnosticsHandledException(httpContext, exception); + } + break; + case "Microsoft.AspNetCore.Hosting.UnhandledException": + httpContext = this.httpContextFetcherHostingExceptionUnhandled.Fetch(value.Value) as HttpContext; + exception = this.exceptionFetcherHostingExceptionUnhandled.Fetch(value.Value) as Exception; + if (httpContext != null && exception != null) + { + this.OnHostingException(httpContext, exception); + } + break; } } diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/IApplicationInsightDiagnosticListener.cs b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/IApplicationInsightDiagnosticListener.cs index 97ed4b51..6714874e 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/IApplicationInsightDiagnosticListener.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/IApplicationInsightDiagnosticListener.cs @@ -1,8 +1,7 @@ -using System.Collections.Generic; - -namespace Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners +namespace Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners { using System; + using System.Collections.Generic; /// /// Base diagnostic listener type for Application Insight From ac85c0cb47c131ffbefcda6488fa5000956a7b34 Mon Sep 17 00:00:00 2001 From: Dmitry-Matveev Date: Wed, 20 Mar 2019 16:55:42 -0700 Subject: [PATCH 04/12] Initialize IKey --- .../Implementation/HostingDiagnosticListener.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs index ae58fb36..b9b74ef8 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs @@ -343,7 +343,7 @@ private RequestTelemetry InitializeRequestTelemetry(HttpContext httpContext, Act } } - this.client.Initialize(requestTelemetry); + this.client.InitializeInstrumentationKey(requestTelemetry); requestTelemetry.Source = GetAppIdFromRequestHeader(httpContext.Request.Headers, requestTelemetry.Context.InstrumentationKey); @@ -363,7 +363,7 @@ private string GetAppIdFromRequestHeader(IHeaderDictionary requestHeaders, strin { headerCorrelationId = StringUtilities.EnforceMaxLength(headerCorrelationId, InjectionGuardConstants.AppIdMaxLength); if (string.IsNullOrEmpty(instrumentationKey)) - { + {In return headerCorrelationId; } From bf33cad2ae3ebe8251eae451caae068df66c0b5f Mon Sep 17 00:00:00 2001 From: Dmitry-Matveev Date: Wed, 20 Mar 2019 17:02:00 -0700 Subject: [PATCH 05/12] Fix typo --- .../Implementation/HostingDiagnosticListener.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs index 9bc7dad1..d25dc7b2 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs @@ -366,7 +366,7 @@ private string GetAppIdFromRequestHeader(IHeaderDictionary requestHeaders, strin { headerCorrelationId = StringUtilities.EnforceMaxLength(headerCorrelationId, InjectionGuardConstants.AppIdMaxLength); if (string.IsNullOrEmpty(instrumentationKey)) - {In + { return headerCorrelationId; } From 328778008289ea9af72b496dbea5c9cff214b704 Mon Sep 17 00:00:00 2001 From: Dmitry-Matveev Date: Fri, 29 Mar 2019 17:45:20 -0700 Subject: [PATCH 06/12] GetUri with Concat --- .../Extensions/HttpRequestExtensions.cs | 24 ++++--------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/Extensions/HttpRequestExtensions.cs b/src/Microsoft.ApplicationInsights.AspNetCore/Extensions/HttpRequestExtensions.cs index 66479425..1230e15a 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/Extensions/HttpRequestExtensions.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/Extensions/HttpRequestExtensions.cs @@ -28,26 +28,12 @@ public static Uri GetUri(this HttpRequest request) { throw new ArgumentException("Http request Scheme is not specified"); } - - string hostName = request.Host.HasValue ? request.Host.ToString() : UnknownHostName; - var builder = new StringBuilder(); - - builder.Append(request.Scheme) - .Append("://") - .Append(hostName); - - if (true == request.Path.HasValue) - { - builder.Append(request.Path.Value); - } - - if (true == request.QueryString.HasValue) - { - builder.Append(request.QueryString); - } - - return new Uri(builder.ToString()); + return new Uri(string.Concat(request.Scheme, + "://", + request.Host.HasValue ? request.Host.Value : UnknownHostName, + request.Path.HasValue ? request.Path.Value : "", + request.QueryString.HasValue ? request.QueryString.Value : "")); } } } From 2e3f01a405c00c8c4dce8204e4dfa3e0d01995ad Mon Sep 17 00:00:00 2001 From: Dmitry-Matveev Date: Tue, 9 Apr 2019 16:48:05 -0700 Subject: [PATCH 07/12] Set Header fixes, use Properties for AspNetCoreEnv. --- .../Implementation/HeadersUtilities.cs | 24 ++++++++++++++++++- .../Implementation/HttpHeadersUtilities.cs | 2 +- ...pNetCoreEnvironmentTelemetryInitializer.cs | 6 ++--- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HeadersUtilities.cs b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HeadersUtilities.cs index a10865af..658d7a3e 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HeadersUtilities.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HeadersUtilities.cs @@ -5,6 +5,7 @@ namespace Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners using System.Linq; using System.Text.RegularExpressions; using Microsoft.ApplicationInsights.Common; + using Microsoft.Extensions.Primitives; /// /// Generic functions that can be used to get and set Http headers. @@ -20,7 +21,7 @@ internal static class HeadersUtilities public static string GetHeaderKeyValue(IEnumerable headerValues, string keyName) { if (headerValues != null) - { + { foreach (string keyNameValue in headerValues) { string[] keyNameValueParts = keyNameValue.Trim().Split('='); @@ -56,6 +57,27 @@ public static IEnumerable SetHeaderKeyValue(IEnumerable headerVa .Concat(newHeaderKeyValue); } + internal static StringValues SetHeaderKeyValue(string[] currentHeaders, string key, string value) + { + if (currentHeaders != null) + { + for (int index = 0; index < currentHeaders.Length; index++) + { + if (HeaderMatchesKey(currentHeaders[index], key)) + { + currentHeaders[index] = string.Concat(key, "=", value); + return currentHeaders; + } + } + + return StringValues.Concat(currentHeaders, string.Concat(key, "=", value)); + } + else + { + return string.Concat(key, "=", value); + } + } + /// /// Check if the header contains the key, case insensitve, ignore leading and trailing whitepsaces. /// diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HttpHeadersUtilities.cs b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HttpHeadersUtilities.cs index 4a8bc3ea..0dff7bc7 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HttpHeadersUtilities.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HttpHeadersUtilities.cs @@ -94,7 +94,7 @@ internal static void SetHeaderKeyValue(IHeaderDictionary headers, string headerN throw new ArgumentNullException(nameof(headers)); } - headers[headerName] = new StringValues(HeadersUtilities.SetHeaderKeyValue(headers[headerName].AsEnumerable(), keyName, keyValue).ToArray()); + headers[headerName] = HeadersUtilities.SetHeaderKeyValue(headers[headerName], keyName, keyValue); } internal static string[] SafeGetCommaSeparatedHeaderValues(IHeaderDictionary headers, string headerName, int maxLength, int maxItems) diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/TelemetryInitializers/AspNetCoreEnvironmentTelemetryInitializer.cs b/src/Microsoft.ApplicationInsights.AspNetCore/TelemetryInitializers/AspNetCoreEnvironmentTelemetryInitializer.cs index c42565d3..1867aec2 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/TelemetryInitializers/AspNetCoreEnvironmentTelemetryInitializer.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/TelemetryInitializers/AspNetCoreEnvironmentTelemetryInitializer.cs @@ -23,10 +23,10 @@ public AspNetCoreEnvironmentTelemetryInitializer(IHostingEnvironment environment /// public void Initialize(ITelemetry telemetry) - { - if (environment != null && !telemetry.Context.GlobalProperties.ContainsKey(AspNetCoreEnvironmentPropertyName)) + { + if (environment != null && !telemetry.Context.Properties.ContainsKey(AspNetCoreEnvironmentPropertyName)) { - telemetry.Context.GlobalProperties.Add(AspNetCoreEnvironmentPropertyName, environment.EnvironmentName); + telemetry.Context.Properties.Add(AspNetCoreEnvironmentPropertyName, environment.EnvironmentName); } } } From a3fd4932411fbab198b2bb3213f32effe74ea4b3 Mon Sep 17 00:00:00 2001 From: Dmitry-Matveev Date: Wed, 10 Apr 2019 15:21:04 -0700 Subject: [PATCH 08/12] SetHeader fixes --- .../Implementation/HeadersUtilities.cs | 12 +------- .../Implementation/HttpHeadersUtilities.cs | 17 ----------- .../HeadersUtilitiesTest.cs | 28 +++++++++---------- 3 files changed, 14 insertions(+), 43 deletions(-) diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HeadersUtilities.cs b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HeadersUtilities.cs index 658d7a3e..2794f9d4 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HeadersUtilities.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HeadersUtilities.cs @@ -39,7 +39,7 @@ public static string GetHeaderKeyValue(IEnumerable headerValues, string /// /// Given the provided list of header value strings, return a comma-separated list of key /// name/value pairs with the provided keyName and keyValue. If the initial header value - /// strings contains the key name, then the original key value should be replaced with the + /// string contains the key name, then the original key value should be replaced with the /// provided key value. If the initial header value strings don't contain the key name, /// then the key name/value pair should be added to the comma-separated list and returned. /// @@ -47,16 +47,6 @@ public static string GetHeaderKeyValue(IEnumerable headerValues, string /// The name of the key to add. /// The value of the key to add. /// The result of setting the provided key name/value pair into the provided headerValues. - public static IEnumerable SetHeaderKeyValue(IEnumerable headerValues, string keyName, string keyValue) - { - string[] newHeaderKeyValue = new[] { string.Format(CultureInfo.InvariantCulture, "{0}={1}", keyName.Trim(), keyValue.Trim()) }; - return headerValues == null || !headerValues.Any() - ? newHeaderKeyValue - : headerValues - .Where(headerValue => !HeaderMatchesKey(headerValue, keyName)) - .Concat(newHeaderKeyValue); - } - internal static StringValues SetHeaderKeyValue(string[] currentHeaders, string key, string value) { if (currentHeaders != null) diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HttpHeadersUtilities.cs b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HttpHeadersUtilities.cs index 0dff7bc7..d1002896 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HttpHeadersUtilities.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HttpHeadersUtilities.cs @@ -65,28 +65,11 @@ internal static bool ContainsRequestContextKeyValue(IHeaderDictionary headers, s return !string.IsNullOrEmpty(GetHeaderKeyValue(headers, RequestResponseHeaders.RequestContextHeader, keyName)); } - internal static void SetRequestContextKeyValue(HttpHeaders headers, string keyName, string keyValue) - { - SetHeaderKeyValue(headers, RequestResponseHeaders.RequestContextHeader, keyName, keyValue); - } - internal static void SetRequestContextKeyValue(IHeaderDictionary headers, string keyName, string keyValue) { SetHeaderKeyValue(headers, RequestResponseHeaders.RequestContextHeader, keyName, keyValue); } - internal static void SetHeaderKeyValue(HttpHeaders headers, string headerName, string keyName, string keyValue) - { - if (headers == null) - { - throw new ArgumentNullException(nameof(headers)); - } - - IEnumerable headerValues = GetHeaderValues(headers, headerName); - headers.Remove(headerName); - headers.Add(headerName, HeadersUtilities.SetHeaderKeyValue(headerValues, keyName, keyValue)); - } - internal static void SetHeaderKeyValue(IHeaderDictionary headers, string headerName, string keyName, string keyValue) { if (headers == null) diff --git a/test/Microsoft.ApplicationInsights.AspNetCore.Tests/HeadersUtilitiesTest.cs b/test/Microsoft.ApplicationInsights.AspNetCore.Tests/HeadersUtilitiesTest.cs index a771b0aa..2a6c63fd 100644 --- a/test/Microsoft.ApplicationInsights.AspNetCore.Tests/HeadersUtilitiesTest.cs +++ b/test/Microsoft.ApplicationInsights.AspNetCore.Tests/HeadersUtilitiesTest.cs @@ -1,7 +1,6 @@ namespace Microsoft.ApplicationInsights.AspNetCore.Tests { using System.Collections.Generic; - using System.Linq; using DiagnosticListeners; using Xunit; @@ -30,36 +29,35 @@ public void ShouldReturnNullWhenKeyNotExists() [Fact] public void ShouldReturnHeadersWhenNoHeaderValues() { - IEnumerable newHeaders = HeadersUtilities.SetHeaderKeyValue(null, "Key", "Value"); + string[] newHeaders = HeadersUtilities.SetHeaderKeyValue(null, "Key", "Value"); Assert.NotNull(newHeaders); - Assert.Equal(1, newHeaders.Count()); - Assert.Equal("Key=Value", newHeaders.First()); + Assert.Single(newHeaders); + Assert.Equal("Key=Value", newHeaders[0]); } [Fact] public void ShouldAppendHeaders() { - IEnumerable existing = new List() { "ExistKey=ExistValue" }; - IEnumerable result = HeadersUtilities.SetHeaderKeyValue(existing, "NewKey", "NewValue"); + string[] existing = new string[] { "ExistKey=ExistValue" }; + string[] result = HeadersUtilities.SetHeaderKeyValue(existing, "NewKey", "NewValue"); Assert.NotNull(result); - Assert.Equal(2, result.Count()); - Assert.NotNull(result.FirstOrDefault(headerValue => headerValue.Equals("ExistKey=ExistValue"))); - Assert.NotNull(result.FirstOrDefault(headerValue => headerValue.Equals("NewKey=NewValue"))); + Assert.Equal(2, result.Length); + Assert.Equal("ExistKey=ExistValue", result[0]); + Assert.Equal("NewKey=NewValue", result[0]); } [Fact] public void ShouldUpdateExistingHeader() { - IEnumerable existing = new List() { "ExistKey=ExistValue", "NoiseKey=NoiseValue" }; - IEnumerable result = HeadersUtilities.SetHeaderKeyValue(existing, "ExistKey", "NewValue"); + string[] existing = new string[] { "ExistKey=ExistValue", "NoiseKey=NoiseValue" }; + string[] result = HeadersUtilities.SetHeaderKeyValue(existing, "ExistKey", "NewValue"); Assert.NotNull(result); - Assert.Equal(2, result.Count()); - Assert.Null(result.FirstOrDefault(headerValue => headerValue.Equals("ExistKey=ExistValue"))); - Assert.NotNull(result.FirstOrDefault(headerValue => headerValue.Equals("ExistKey=NewValue"))); - Assert.NotNull(result.FirstOrDefault(headerValue => headerValue.Equals("NoiseKey=NoiseValue"))); + Assert.Equal(2, result.Length); + Assert.Equal("ExistKey=NewValue", result[0]); + Assert.Equal("NoiseKey=NoiseValue", result[0]); } } } From c039272df9d4ea77e952f5905018cb4040164a11 Mon Sep 17 00:00:00 2001 From: Dmitry-Matveev Date: Wed, 10 Apr 2019 16:24:17 -0700 Subject: [PATCH 09/12] Test Fixes - 1 --- .../HeadersUtilitiesTest.cs | 4 ++-- .../AspNetCoreEnvironmentTelemetryInitializerTests.cs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/Microsoft.ApplicationInsights.AspNetCore.Tests/HeadersUtilitiesTest.cs b/test/Microsoft.ApplicationInsights.AspNetCore.Tests/HeadersUtilitiesTest.cs index 2a6c63fd..fe066f8b 100644 --- a/test/Microsoft.ApplicationInsights.AspNetCore.Tests/HeadersUtilitiesTest.cs +++ b/test/Microsoft.ApplicationInsights.AspNetCore.Tests/HeadersUtilitiesTest.cs @@ -45,7 +45,7 @@ public void ShouldAppendHeaders() Assert.NotNull(result); Assert.Equal(2, result.Length); Assert.Equal("ExistKey=ExistValue", result[0]); - Assert.Equal("NewKey=NewValue", result[0]); + Assert.Equal("NewKey=NewValue", result[1]); } [Fact] @@ -57,7 +57,7 @@ public void ShouldUpdateExistingHeader() Assert.NotNull(result); Assert.Equal(2, result.Length); Assert.Equal("ExistKey=NewValue", result[0]); - Assert.Equal("NoiseKey=NoiseValue", result[0]); + Assert.Equal("NoiseKey=NoiseValue", result[1]); } } } diff --git a/test/Microsoft.ApplicationInsights.AspNetCore.Tests/TelemetryInitializers/AspNetCoreEnvironmentTelemetryInitializerTests.cs b/test/Microsoft.ApplicationInsights.AspNetCore.Tests/TelemetryInitializers/AspNetCoreEnvironmentTelemetryInitializerTests.cs index 783199dc..7fa681fd 100644 --- a/test/Microsoft.ApplicationInsights.AspNetCore.Tests/TelemetryInitializers/AspNetCoreEnvironmentTelemetryInitializerTests.cs +++ b/test/Microsoft.ApplicationInsights.AspNetCore.Tests/TelemetryInitializers/AspNetCoreEnvironmentTelemetryInitializerTests.cs @@ -19,10 +19,10 @@ public void InitializeDoesNotOverrideExistingProperty() { var initializer = new AspNetCoreEnvironmentTelemetryInitializer(new HostingEnvironment() { EnvironmentName = "Production"}); var telemetry = new RequestTelemetry(); - telemetry.Context.GlobalProperties.Add("AspNetCoreEnvironment", "Development"); + telemetry.Context.Properties.Add("AspNetCoreEnvironment", "Development"); initializer.Initialize(telemetry); - Assert.Equal("Development", telemetry.Context.GlobalProperties["AspNetCoreEnvironment"]); + Assert.Equal("Development", telemetry.Context.Properties["AspNetCoreEnvironment"]); } [Fact] @@ -32,7 +32,7 @@ public void InitializeSetsCurrentEnvironmentNameToProperty() var telemetry = new RequestTelemetry(); initializer.Initialize(telemetry); - Assert.Equal("Production", telemetry.Context.GlobalProperties["AspNetCoreEnvironment"]); + Assert.Equal("Production", telemetry.Context.Properties["AspNetCoreEnvironment"]); } } } From 03d7d25f184503d211c3abdd7ffad77252fc774d Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Wed, 10 Apr 2019 19:06:46 -0700 Subject: [PATCH 10/12] fix tests --- .../HostingDiagnosticListener.cs | 34 ++++++++++++++----- .../HostingDiagnosticListenerTest.cs | 4 --- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs index d25dc7b2..d0081195 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs @@ -161,7 +161,15 @@ public void OnHttpRequestInStart(HttpContext httpContext) // with W3C support on .NET https://github.com/dotnet/corefx/issues/30331 newActivity = new Activity(ActivityCreatedByHostingDiagnosticListener); - newActivity.SetParentId(StringUtilities.GenerateTraceId()); + if (this.enableW3CHeaders) + { + newActivity.GenerateW3CContext(); + newActivity.SetParentId(newActivity.GetTraceId()); + } + else + { + newActivity.SetParentId(W3CUtilities.GenerateTraceId()); + } // end of workaround } @@ -257,7 +265,9 @@ public void OnBeginRequest(HttpContext httpContext, long timestamp) InjectionGuardConstants.RequestHeaderMaxLength); } } - else if(!activity.IsW3CActivity()) + + // no headers + else if (originalParentId == null) { // As a first step in supporting W3C protocol in ApplicationInsights, // we want to generate Activity Ids in the W3C compatible format. @@ -266,8 +276,16 @@ public void OnBeginRequest(HttpContext httpContext, long timestamp) // So if there is no current Activity (i.e. there were no Request-Id header in the incoming request), we'll override ParentId on // the current Activity by the properly formatted one. This workaround should go away // with W3C support on .NET https://github.com/dotnet/corefx/issues/30331 - - activity.SetParentId(StringUtilities.GenerateTraceId()); + + if (this.enableW3CHeaders) + { + activity.GenerateW3CContext(); + activity.SetParentId(activity.GetTraceId()); + } + else + { + activity.SetParentId(W3CUtilities.GenerateTraceId()); + } // end of workaround } @@ -337,6 +355,10 @@ private RequestTelemetry InitializeRequestTelemetry(HttpContext httpContext, Act requestTelemetry.Context.Operation.Id = activity.RootId; requestTelemetry.Id = activity.Id; } + else + { + activity.UpdateTelemetry(requestTelemetry, false); + } foreach (var prop in activity.Baggage) { @@ -490,10 +512,6 @@ private void SetW3CContext(IHeaderDictionary requestHeaders, Activity activity, InjectionGuardConstants.TraceParentHeaderMaxLength); activity.SetTraceparent(parentTraceParent); } - else - { - activity.GenerateW3CContext(); - } string[] traceStateValues = HttpHeadersUtilities.SafeGetCommaSeparatedHeaderValues(requestHeaders, W3C.W3CConstants.TraceStateHeader, InjectionGuardConstants.TraceStateHeaderMaxLength, InjectionGuardConstants.TraceStateMaxPairs); diff --git a/test/Microsoft.ApplicationInsights.AspNetCore.Tests/HostingDiagnosticListenerTest.cs b/test/Microsoft.ApplicationInsights.AspNetCore.Tests/HostingDiagnosticListenerTest.cs index 87ccc82f..bec25163 100644 --- a/test/Microsoft.ApplicationInsights.AspNetCore.Tests/HostingDiagnosticListenerTest.cs +++ b/test/Microsoft.ApplicationInsights.AspNetCore.Tests/HostingDiagnosticListenerTest.cs @@ -836,10 +836,6 @@ public void OnBeginRequestWithW3CSupportAndNoHeadersIsTrackedCorrectly(bool isAs var activityInitializedByW3CHeader = Activity.Current; - if (!isAspNetCore2) - { - Assert.Null(activityInitializedByW3CHeader.ParentId); - } Assert.NotNull(activityInitializedByW3CHeader.GetTraceId()); Assert.Equal(32, activityInitializedByW3CHeader.GetTraceId().Length); Assert.Equal(16, activityInitializedByW3CHeader.GetSpanId().Length); From 293c29a43f6d06080e6f488c4f95211af71ad222 Mon Sep 17 00:00:00 2001 From: Dmitry-Matveev Date: Thu, 11 Apr 2019 14:25:55 -0700 Subject: [PATCH 11/12] Keep Public vs. Internal --- .../DiagnosticListeners/Implementation/HeadersUtilities.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HeadersUtilities.cs b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HeadersUtilities.cs index 2794f9d4..d99c3233 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HeadersUtilities.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HeadersUtilities.cs @@ -47,7 +47,7 @@ public static string GetHeaderKeyValue(IEnumerable headerValues, string /// The name of the key to add. /// The value of the key to add. /// The result of setting the provided key name/value pair into the provided headerValues. - internal static StringValues SetHeaderKeyValue(string[] currentHeaders, string key, string value) + public static StringValues SetHeaderKeyValue(string[] currentHeaders, string key, string value) { if (currentHeaders != null) { From ff059fd70b72fe91f499a4ae632e600d2160a929 Mon Sep 17 00:00:00 2001 From: Dmitry-Matveev Date: Thu, 11 Apr 2019 14:40:21 -0700 Subject: [PATCH 12/12] Changelog update --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 866a2a67..ca68c918 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - [Enables Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider by default. If ApplicationInsightsLoggerProvider was enabled previously using ILoggerFactory extension method, please remove it to prevent duplicate logs.](https://github.com/Microsoft/ApplicationInsights-aspnetcore/issues/854) - [Remove reference to Microsoft.Extensions.DiagnosticAdapter and use DiagnosticSource subscription APIs directly](https://github.com/Microsoft/ApplicationInsights-aspnetcore/pull/852) - [Fix: NullReferenceException in ApplicationInsightsLogger.Log when exception contains a Data entry with a null value](https://github.com/Microsoft/ApplicationInsights-aspnetcore/issues/848) +- [Performance fixes for GetUri, SetKeyHeaderValue, ConcurrentDictionary use and Telemetry Initializers](https://github.com/Microsoft/ApplicationInsights-aspnetcore/pull/864) ## Version 2.7.0-beta2 - Added NetStandard2.0 target.