Skip to content
This repository has been archived by the owner on Jun 10, 2020. It is now read-only.

Commit

Permalink
Merge pull request #1013 from microsoft/tilee/merge_develop_to_master…
Browse files Browse the repository at this point in the history
…(prep2.12-beta1)

merge develop to master(prep2.12 beta1)
  • Loading branch information
TimothyMothra committed Oct 17, 2019
2 parents 198c760 + c5e4f79 commit 21fbff2
Show file tree
Hide file tree
Showing 70 changed files with 1,619 additions and 499 deletions.
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
# Changelog


## Version 2.12.0-beta1
- Skipping version numbers to keep in sync with Base SDK.
- [Fix Null/Empty Ikey from ApplicationInsightsServiceOptions overrding one from appsettings.json](https://github.com/microsoft/ApplicationInsights-aspnetcore/issues/989)
- [Provide ApplicationInsightsServiceOptions for easy disabling of any default TelemetryModules](https://github.com/microsoft/ApplicationInsights-aspnetcore/issues/988)
- [Added support for SDK Connection String](https://github.com/microsoft/ApplicationInsights-dotnet/issues/1221)
- [New RoleName initializer for Azure Web App to accurately populate RoleName.](https://github.com/microsoft/ApplicationInsights-dotnet-server/issues/1207)
- Update to Base/Web/Logging SDK to 2.12.0-beta1

## Version 2.8.2
- Updated Web SDK to 2.11.2

## Version 2.8.1
- Updated Web SDK to 2.11.1

## Version 2.8.0
- Updated Bask SDK/Web SDK/Logging Adaptor SDK to 2.11.0
- Updated Base SDK/Web SDK/Logging Adaptor SDK to 2.11.0
- Updated System.Diagnostics.DiagnosticSource to 4.6.0

## Version 2.8.0-beta3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@ internal class ExceptionUtilities
/// Get the string representation of this Exception with special handling for AggregateExceptions.
/// </summary>
/// <param name="ex">The exception to convert to a string.</param>
/// <returns></returns>
/// <returns>Returns a string representing the Exception message, and call stack.</returns>
internal static string GetExceptionDetailString(Exception ex)
{
var ae = ex as AggregateException;
if (ae != null)
if (ex is AggregateException ae)
{
return ae.Flatten().InnerException.ToInvariantString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public static StringValues SetHeaderKeyValue(string[] currentHeaders, string key
/// Http Headers only allow Printable US-ASCII characters.
/// Remove all other characters.
/// </summary>
/// <param name="input">String to be sanitized.</param>
/// <returns>sanitized string.</returns>
public static string SanitizeString(string input)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
/// </summary>
internal class HostingDiagnosticListener : IApplicationInsightDiagnosticListener
{
// Name of custom property to store the legacy RootId when operating in W3C mode. Backend/UI understands this property.
/// <summary>
/// Name of custom property to store the legacy RootId when operating in W3C mode. Backend/UI understands this property.
/// </summary>
internal const string LegacyRootIdProperty = "ai_legacyRootId";

private const string ActivityCreatedByHostingDiagnosticListener = "ActivityCreatedByHostingDiagnosticListener";
Expand All @@ -40,7 +42,7 @@ internal class HostingDiagnosticListener : IApplicationInsightDiagnosticListener
private static readonly ActiveSubsciptionManager SubscriptionManager = new ActiveSubsciptionManager();

/// <summary>
/// This class need to be aware of the AspNetCore major version.
/// This class need to be aware of the AspNetCore major version.
/// This will affect what DiagnosticSource events we receive.
/// To support AspNetCore 1.0,2.0,3.0 we listen to both old and new events.
/// If the running AspNetCore version is 2.0 or 3.0, both old and new events will be sent. In this case, we will ignore the old events.
Expand All @@ -59,8 +61,6 @@ internal class HostingDiagnosticListener : IApplicationInsightDiagnosticListener
private readonly bool trackExceptions;
private readonly bool enableW3CHeaders;

#region fetchers

// fetch is unique per event and per property
private readonly PropertyFetcher httpContextFetcherOnBeforeAction = new PropertyFetcher("httpContext");
private readonly PropertyFetcher routeDataFetcher = new PropertyFetcher("routeData");
Expand All @@ -79,7 +79,6 @@ internal class HostingDiagnosticListener : IApplicationInsightDiagnosticListener

private readonly PropertyFetcher timestampFetcherBeginRequest = new PropertyFetcher("timestamp");
private readonly PropertyFetcher timestampFetcherEndRequest = new PropertyFetcher("timestamp");
#endregion

private string lastIKeyLookedUp;
private string lastAppIdUsed;
Expand All @@ -99,7 +98,7 @@ internal class HostingDiagnosticListener : IApplicationInsightDiagnosticListener
bool injectResponseHeaders,
bool trackExceptions,
bool enableW3CHeaders,
AspNetCoreMajorVersion aspNetCoreMajorVersion )
AspNetCoreMajorVersion aspNetCoreMajorVersion)
{
this.aspNetCoreMajorVersion = aspNetCoreMajorVersion;
this.client = client ?? throw new ArgumentNullException(nameof(client));
Expand Down Expand Up @@ -153,8 +152,7 @@ public void OnBeforeAction(HttpContext httpContext, IDictionary<string, object>

if (telemetry != null && string.IsNullOrEmpty(telemetry.Name))
{
string name = this.GetNameFromRouteContext(routeValues);

string name = GetNameFromRouteContext(routeValues);
if (!string.IsNullOrEmpty(name))
{
name = httpContext.Request.Method + " " + name;
Expand Down Expand Up @@ -197,9 +195,9 @@ public void OnHttpRequestInStart(HttpContext httpContext)
// 2. Incoming Request-ID Headers. originalParentId will be request-id, but Activity ignores this for ID calculations.
// If incoming ID is W3C compatible, ignore current Activity. Create new one with parent set to incoming W3C compatible rootid.
// If incoming ID is not W3C compatible, we can use Activity as such, but need to store originalParentID in custom property 'legacyRootId'
// 3. Incoming TraceParent header.
// 3. Incoming TraceParent header.
// 3a - 2.XX Need to ignore current Activity, and create new from incoming W3C TraceParent header.
// 3b - 3.XX Use Activity as such because 3.XX is W3C Aware.
// 3b - 3.XX Use Activity as such because 3.XX is W3C Aware.

// Another 3 possibilities when TelemetryConfiguration.EnableW3CCorrelation = false
// 1. No incoming headers. originalParentId will be null. Simply use the Activity as such.
Expand Down Expand Up @@ -235,11 +233,12 @@ public void OnHttpRequestInStart(HttpContext httpContext)
AspNetCoreEventSource.Instance.HostingListenerInformational(this.aspNetCoreMajorVersion, "Ignoring original Activity from Hosting to create new one using traceparent header retrieved by sdk.");

// read and populate tracestate
ReadTraceState(httpContext.Request.Headers, newActivity);
ReadTraceState(httpContext.Request.Headers, newActivity);
}
else if (this.aspNetCoreMajorVersion == AspNetCoreMajorVersion.Three && headers.ContainsKey(W3CConstants.TraceParentHeader))
{
AspNetCoreEventSource.Instance.HostingListenerInformational(this.aspNetCoreMajorVersion, "Incoming request has traceparent. Using Activity created from Hosting.");

// scenario #3b Use Activity created by Hosting layer when W3C Headers Present.
// but ignore parent if user disabled w3c.
if (currentActivity.IdFormat != ActivityIdFormat.W3C)
Expand Down Expand Up @@ -270,7 +269,7 @@ public void OnHttpRequestInStart(HttpContext httpContext)
AspNetCoreEventSource.Instance.HostingListenerInformational(this.aspNetCoreMajorVersion, "Incoming Request-ID is not W3C Compatible, and hence will be ignored for ID generation, but stored in custom property legacy_rootID.");
}
}
}
}

if (newActivity != null)
{
Expand Down Expand Up @@ -330,7 +329,7 @@ public void OnBeginRequest(HttpContext httpContext, long timestamp)
activity.SetParentId(parentTraceParent);
originalParentId = parentTraceParent;

ReadTraceState(requestHeaders, activity);
ReadTraceState(requestHeaders, activity);
}

// Request-Id
Expand All @@ -353,7 +352,7 @@ public void OnBeginRequest(HttpContext httpContext, long timestamp)
else
{
activity.SetParentId(originalParentId);
}
}
}

// no headers
Expand Down Expand Up @@ -416,6 +415,7 @@ public void OnDiagnosticsUnhandledException(HttpContext httpContext, Exception e
this.OnException(httpContext, exception);
}

/// <inheritdoc />
public void Dispose()
{
SubscriptionManager.Detach(this);
Expand Down Expand Up @@ -541,7 +541,7 @@ public void OnCompleted()
{
}

private string GetParentId(Activity activity, string originalParentId, string operationId)
private static string GetParentId(Activity activity, string originalParentId, string operationId)
{
if (activity.IdFormat == ActivityIdFormat.W3C && activity.ParentSpanId != default)
{
Expand Down Expand Up @@ -654,7 +654,7 @@ private static void ReadTraceState(IHeaderDictionary requestHeaders, Activity ac
}
}

private string GetNameFromRouteContext(IDictionary<string, object> routeValues)
private static string GetNameFromRouteContext(IDictionary<string, object> routeValues)
{
string name = null;

Expand Down Expand Up @@ -745,7 +745,7 @@ private RequestTelemetry InitializeRequestTelemetry(HttpContext httpContext, Act
&& this.configuration != null
&& !string.IsNullOrEmpty(requestTelemetry.Context.Operation.Id)
&& SamplingScoreGenerator.GetSamplingScore(requestTelemetry.Context.Operation.Id) >= this.configuration.GetLastObservedSamplingPercentage(requestTelemetry.ItemTypeFlag))
{
{
requestTelemetry.ProactiveSamplingDecision = SamplingDecision.SampledOut;
AspNetCoreEventSource.Instance.TelemetryItemWasSampledOutAtHead(requestTelemetry.Context.Operation.Id);
}
Expand Down Expand Up @@ -826,7 +826,8 @@ private void SetAppIdInResponseHeader(HttpContext httpContext, RequestTelemetry

HttpHeadersUtilities.SetRequestContextKeyValue(
responseHeaders,
RequestResponseHeaders.RequestContextTargetKey, this.lastAppIdUsed);
RequestResponseHeaders.RequestContextTargetKey,
this.lastAppIdUsed);
}
}
}
Expand Down Expand Up @@ -879,8 +880,6 @@ private void EndRequest(HttpContext httpContext, long timestamp)

this.client.TrackRequest(telemetry);



// Stop what we started.
var activity = Activity.Current;
if (activity != null && activity.OperationName == ActivityCreatedByHostingDiagnosticListener)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,21 @@ namespace Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;

using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;

/// <summary>
/// This class contains several utility methods for working with Http Headers.
/// </summary>
internal static class HttpHeadersUtilities
{
/// <summary>
/// Get all values of a header by name.
/// </summary>
/// <param name="headers">Collection of Http Headers.</param>
/// <param name="headerName">Header name.</param>
/// <returns>Returns a collection of values matching the header name.</returns>
internal static IEnumerable<string> GetHeaderValues(IHeaderDictionary headers, string headerName)
{
IEnumerable<string> result = Enumerable.Empty<string>();
Expand All @@ -24,27 +33,59 @@ internal static IEnumerable<string> GetHeaderValues(IHeaderDictionary headers, s
return result;
}

/// <summary>
/// Get the Header Value matching a Name and Key.
/// </summary>
/// <param name="headers">Collection of Http Headers.</param>
/// <param name="headerName">Header name.</param>
/// <param name="keyName">Key name.</param>
/// <returns>The first key value, if it is found. If it is not found, then null.</returns>
internal static string GetHeaderKeyValue(IHeaderDictionary headers, string headerName, string keyName)
{
IEnumerable<string> headerValues = GetHeaderValues(headers, headerName);
return HeadersUtilities.GetHeaderKeyValue(headerValues, keyName);
}

/// <summary>
/// Get a key value from the Request Context header.
/// </summary>
/// <param name="headers">Collection of Http Headers.</param>
/// <param name="keyName">Key name.</param>
/// <returns>The first key value, if it is found. If it is not found, then null.</returns>
internal static string GetRequestContextKeyValue(IHeaderDictionary headers, string keyName)
{
return GetHeaderKeyValue(headers, RequestResponseHeaders.RequestContextHeader, keyName);
}

/// <summary>
/// Checks if a specified key exists in the Request Context Header.
/// </summary>
/// <param name="headers">Collection of Http Headers.</param>
/// <param name="keyName">Key name.</param>
/// <returns>Returns a boolean indicating if the key exists.</returns>
internal static bool ContainsRequestContextKeyValue(IHeaderDictionary headers, string keyName)
{
return !string.IsNullOrEmpty(GetHeaderKeyValue(headers, RequestResponseHeaders.RequestContextHeader, keyName));
}

/// <summary>
/// Sets a value on the Request Context Headers.
/// </summary>
/// <param name="headers">Collection of Http Headers.</param>
/// <param name="keyName">Key name to set.</param>
/// <param name="keyValue">Key value to set.</param>
internal static void SetRequestContextKeyValue(IHeaderDictionary headers, string keyName, string keyValue)
{
SetHeaderKeyValue(headers, RequestResponseHeaders.RequestContextHeader, keyName, keyValue);
}

/// <summary>
/// Sets a key value on the Http Headers.
/// </summary>
/// <param name="headers">Collection of Http Headers.</param>
/// <param name="headerName">Http Header name.</param>
/// <param name="keyName">Key name to set.</param>
/// <param name="keyValue">Key value to set.</param>
internal static void SetHeaderKeyValue(IHeaderDictionary headers, string headerName, string keyName, string keyValue)
{
if (headers == null)
Expand All @@ -55,6 +96,14 @@ internal static void SetHeaderKeyValue(IHeaderDictionary headers, string headerN
headers[headerName] = HeadersUtilities.SetHeaderKeyValue(headers[headerName], keyName, keyValue);
}

/// <summary>
/// Get the values from an Http Header.
/// </summary>
/// <param name="headers">Collection of Http Headers.</param>
/// <param name="headerName">Http header name.</param>
/// <param name="maxLength">Max length of return values.</param>
/// <param name="maxItems">Max count of return values.</param>
/// <returns>Returns an array of the Http values.</returns>
internal static string[] SafeGetCommaSeparatedHeaderValues(IHeaderDictionary headers, string headerName, int maxLength, int maxItems)
{
string[] traceStateValues = headers.GetCommaSeparatedValues(headerName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@
using System.Collections.Generic;

/// <summary>
/// Base diagnostic listener type for Application Insight
/// Base diagnostic listener type for Application Insight.
/// </summary>
internal interface IApplicationInsightDiagnosticListener : IDisposable, IObserver<KeyValuePair<string, object>>
{
/// <summary>
/// Gets a value indicating which listener this instance should be subscribed to
/// Gets a value indicating which listener this instance should be subscribed to.
/// </summary>
string ListenerName { get; }

/// <summary>
/// Notifies listener that it is subscribed to DiagnosticSource
/// Notifies listener that it is subscribed to DiagnosticSource.
/// </summary>
void OnSubscribe();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ namespace Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners
{
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners.Implementation;
using Microsoft.ApplicationInsights.AspNetCore.Extensibility.Implementation.Tracing;
Expand All @@ -12,6 +13,10 @@ namespace Microsoft.ApplicationInsights.AspNetCore.DiagnosticListeners
/// <see cref="IApplicationInsightDiagnosticListener"/> implementation that listens for events specific to AspNetCore Mvc layer.
/// </summary>
[Obsolete("This class was merged with HostingDiagnosticsListener to optimize Diagnostics Source subscription performance")]
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Class is obsolete.")]
[SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly", Justification = "Class is obsolete.")]
[SuppressMessage("StyleCop Documentation Rules", "SA1611:ElementParametersMustBeDocumented", Justification = "Class is obsolete.")]
[SuppressMessage("Microsoft.Usage", "CA1816:CallGCSuppressFinalizeCorrectly", Justification = "Class is obsolete.")]
public class MvcDiagnosticsListener : IApplicationInsightDiagnosticListener
{
private readonly PropertyFetcher httpContextFetcher = new PropertyFetcher("httpContext");
Expand All @@ -30,8 +35,7 @@ public void OnBeforeAction(HttpContext httpContext, IDictionary<string, object>

if (telemetry != null && string.IsNullOrEmpty(telemetry.Name))
{
string name = this.GetNameFromRouteContext(routeValues);

string name = GetNameFromRouteContext(routeValues);
if (!string.IsNullOrEmpty(name))
{
name = httpContext.Request.Method + " " + name;
Expand Down Expand Up @@ -83,7 +87,7 @@ public void Dispose()
{
}

private string GetNameFromRouteContext(IDictionary<string, object> routeValues)
private static string GetNameFromRouteContext(IDictionary<string, object> routeValues)
{
string name = null;

Expand Down

0 comments on commit 21fbff2

Please sign in to comment.