private void ValidateTelemetry <T>(T telemetry, Activity activity, bool isW3C = true) where T : OperationTelemetry { Assert.AreEqual(activity.OperationName, telemetry.Name); if (isW3C) { Assert.AreEqual(W3CUtilities.FormatTelemetryId(activity.TraceId.ToHexString(), activity.SpanId.ToHexString()), telemetry.Id); } else { Assert.AreEqual(activity.Id, telemetry.Id); } Assert.AreEqual(activity.ParentId, telemetry.Context.Operation.ParentId); Assert.AreEqual(activity.RootId, telemetry.Context.Operation.Id); foreach (var baggage in activity.Baggage) { Assert.IsTrue(telemetry.Properties.ContainsKey(baggage.Key)); Assert.AreEqual(baggage.Value, telemetry.Properties[baggage.Key]); } foreach (var tag in activity.Tags) { Assert.IsTrue(telemetry.Properties.ContainsKey(tag.Key)); Assert.AreEqual(tag.Value, telemetry.Properties[tag.Key]); } }
public void UpdateValidDependencyTelemetryWithForceFalse() { var traceId = W3CUtilities.GenerateTraceId(); var parentSpanId = W3CUtilities.GenerateSpanId(); var spanId = W3CUtilities.GenerateSpanId(); var telemetry = new DependencyTelemetry(); telemetry.Context.Operation.Id = traceId; telemetry.Context.Operation.ParentId = $"|{traceId}.{parentSpanId}."; telemetry.Id = $"|{traceId}.{spanId}."; var a = new Activity("foo").Start(); a.SetTraceparent($"00-{traceId}-{spanId}-01"); a.UpdateTelemetry(telemetry, false); Assert.AreEqual(traceId, telemetry.Context.Operation.Id); #if NET45 || NET46 Assert.AreEqual($"|{traceId}.{parentSpanId}.", telemetry.Context.Operation.ParentId); Assert.AreEqual($"|{traceId}.{spanId}.", telemetry.Id); #else Assert.AreEqual($"|{traceId}.{spanId}.", telemetry.Context.Operation.ParentId); Assert.AreEqual($"|{traceId}.{a.GetSpanId()}.", telemetry.Id); #endif }
public override void OnEvent(KeyValuePair <string, object> evnt, DiagnosticListener ignored) { Activity currentActivity = Activity.Current; switch (evnt.Key) { case "Microsoft.Azure.ServiceBus.ProcessSession.Start": case "Microsoft.Azure.ServiceBus.Process.Start": // if Activity is W3C, but there is a parent id which is not W3C. if (currentActivity.IdFormat == ActivityIdFormat.W3C && !string.IsNullOrEmpty(currentActivity.ParentId) && currentActivity.ParentSpanId == default) { // if hierarchical parent has compatible rootId, reuse it and keep legacy parentId if (W3CUtilities.TryGetTraceId(currentActivity.ParentId, out var traceId)) { #pragma warning disable CA2000 // Dispose objects before losing scope // Since we don't know when it will finish, we will not dispose var backCompatActivity = new Activity(currentActivity.OperationName); #pragma warning restore CA2000 // Dispose objects before losing scope backCompatActivity.SetParentId(ActivityTraceId.CreateFromString(traceId), default, currentActivity.ActivityTraceFlags); backCompatActivity.Start(); backCompatActivity.AddTag("__legacyParentId", currentActivity.ParentId); foreach (var tag in currentActivity.Tags) { backCompatActivity.AddTag(tag.Key, tag.Value); } foreach (var baggage in currentActivity.Baggage) { backCompatActivity.AddBaggage(baggage.Key, baggage.Value); } }
//// netcoreapp 2.0 event /// <summary> /// Handler for Activity start event (outgoing request is about to be sent). /// </summary> internal void OnActivityStart(HttpRequestMessage request) { // Even though we have the IsEnabled filter to reject ApplicationInsights URLs before any events are fired, if there // are multiple subscribers and one subscriber returns true to IsEnabled then all subscribers will receive the event. if (this.applicationInsightsUrlFilter.IsApplicationInsightsUrl(request.RequestUri)) { return; } var currentActivity = Activity.Current; if (currentActivity == null) { DependencyCollectorEventSource.Log.CurrentActivityIsNull(HttpOutStartEventName); return; } // As a first step in supporting W3C protocol in ApplicationInsights, // we want to generate Activity Ids in the W3C compatible format. // While .NET changes to Activity are pending, we want to ensure trace starts with W3C compatible Id // as early as possible, so that everyone has a chance to upgrade and have compatibility with W3C systems once they arrive. // So if there is no parent Activity (i.e. this request has happened in the background, without parent scope), we'll override // the current Activity with the one with properly formatted Id. This workaround should go away // with W3C support on .NET https://github.com/dotnet/corefx/issues/30331 (TODO) if (currentActivity.Parent == null && currentActivity.ParentId == null) { currentActivity.UpdateParent(W3CUtilities.GenerateTraceId()); } // end of workaround DependencyCollectorEventSource.Log.HttpCoreDiagnosticSourceListenerStart(currentActivity.Id); this.InjectRequestHeaders(request, this.configuration.InstrumentationKey); }
public void StartStopRespectsUserProvidedIdsInvalidOperationId() { var customOperationId = "customOperationId"; var customParentId = "customParentId"; var dependency = new DependencyTelemetry(); dependency.Context.Operation.Id = customOperationId; dependency.Context.Operation.ParentId = customParentId; using (var operation = this.telemetryClient.StartOperation <DependencyTelemetry>(dependency)) { Assert.IsNotNull(Activity.Current); Assert.IsTrue(W3CUtilities.IsCompatibleW3CTraceId(Activity.Current.TraceId.ToHexString())); Assert.AreEqual(customParentId, operation.Telemetry.Context.Operation.ParentId); } Assert.AreEqual(1, this.sendItems.Count); Assert.IsTrue(this.sendItems.Single() is DependencyTelemetry); Assert.AreNotEqual(customOperationId, dependency.Context.Operation.Id); Assert.AreEqual(customParentId, dependency.Context.Operation.ParentId); Assert.IsTrue(dependency.Properties.TryGetValue("ai_legacyRootId", out var actualLegacyRootId)); Assert.AreEqual(customOperationId, actualLegacyRootId); }
internal static RequestTelemetry CreateRequestTelemetryPrivate( this HttpContext platformContext) { if (platformContext == null) { throw new ArgumentNullException(nameof(platformContext)); } var result = new RequestTelemetry(); var currentActivity = Activity.Current; var requestContext = result.Context.Operation; if (currentActivity == null) { // if there was no BeginRequest, ASP.NET HttpModule did not have a chance to set current activity (and will never do it). currentActivity = new Activity(ActivityHelpers.RequestActivityItemName); if (ActivityHelpers.IsW3CTracingEnabled) { ActivityHelpers.ExtractW3CContext(platformContext.Request, currentActivity); ActivityHelpers.ExtractTracestate(platformContext.Request, currentActivity, result); // length enforced in SetW3CContext currentActivity.SetParentId(currentActivity.GetTraceId()); currentActivity.UpdateTelemetry(result, true); SetLegacyContextIds(platformContext.Request, result); } else if (currentActivity.Extract(platformContext.Request.Headers)) { requestContext.ParentId = currentActivity.ParentId; } else if (ActivityHelpers.TryParseCustomHeaders(platformContext.Request, out var rootId, out var parentId)) { currentActivity.SetParentId(rootId); if (!string.IsNullOrEmpty(parentId)) { currentActivity.SetParentId(rootId); if (!string.IsNullOrEmpty(parentId)) { requestContext.ParentId = parentId; } } } else { // As a first step in supporting W3C protocol in ApplicationInsights, // we want to generate Activity Ids in the W3C compatible format. // While .NET changes to Activity are pending, we want to ensure trace starts with W3C compatible Id // as early as possible, so that everyone has a chance to upgrade and have compatibility with W3C systems once they arrive. // 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 currentActivity.SetParentId(W3CUtilities.GenerateTraceId()); // end of workaround } currentActivity.Start(); }
protected void SetCommonProperties(string eventName, object eventPayload, Activity activity, OperationTelemetry telemetry) { telemetry.Name = this.GetOperationName(eventName, eventPayload, activity); telemetry.Duration = activity.Duration; telemetry.Timestamp = activity.StartTimeUtc; if (activity.IdFormat == ActivityIdFormat.W3C) { var traceId = activity.TraceId.ToHexString(); telemetry.Context.Operation.Id = traceId; if (string.IsNullOrEmpty(telemetry.Context.Operation.ParentId)) { if (activity.ParentSpanId != default) { telemetry.Context.Operation.ParentId = W3CUtilities.FormatTelemetryId(traceId, activity.ParentSpanId.ToHexString()); } else if (!string.IsNullOrEmpty(activity.ParentId)) { // W3C activity with non-W3C parent must keep parentId telemetry.Context.Operation.ParentId = activity.ParentId; } } telemetry.Id = W3CUtilities.FormatTelemetryId(traceId, activity.SpanId.ToHexString()); // TODO[tracestate]: remove, this is done in base SDK if (!string.IsNullOrEmpty(activity.TraceStateString) && !telemetry.Properties.ContainsKey(W3CConstants.TracestatePropertyKey)) { telemetry.Properties.Add(W3CConstants.TracestatePropertyKey, activity.TraceStateString); } } else { telemetry.Id = activity.Id; telemetry.Context.Operation.Id = activity.RootId; telemetry.Context.Operation.ParentId = activity.ParentId; } foreach (var item in activity.Tags) { if (!telemetry.Properties.ContainsKey(item.Key)) { telemetry.Properties[item.Key] = item.Value; } } foreach (var item in activity.Baggage) { if (!telemetry.Properties.ContainsKey(item.Key)) { telemetry.Properties[item.Key] = item.Value; } } telemetry.Success = this.IsOperationSuccessful(eventName, eventPayload, activity); }
private static void InjectBackCompatibleRequestId(Activity currentActivity, HttpRequestHeaders requestHeaders) { if (!requestHeaders.Contains(RequestResponseHeaders.RequestIdHeader)) { requestHeaders.Add(RequestResponseHeaders.RequestIdHeader, W3CUtilities.FormatTelemetryId(currentActivity.TraceId.ToHexString(), currentActivity.SpanId.ToHexString())); } }
private void ValidateTelemetry <T>(T telemetry, Activity activity, bool isW3C = true, string legacyParentId = null) where T : OperationTelemetry { Assert.AreEqual(activity.OperationName, telemetry.Name); Assert.AreEqual( isW3C ? W3CUtilities.FormatTelemetryId(activity.TraceId.ToHexString(), activity.SpanId.ToHexString()) : activity.Id, telemetry.Id); if (isW3C) { if (activity.ParentSpanId != default && activity.ParentSpanId.ToHexString() != "0000000000000000") { Assert.AreEqual( W3CUtilities.FormatTelemetryId(activity.TraceId.ToHexString(), activity.ParentSpanId.ToHexString()), telemetry.Context.Operation.ParentId); } else { Assert.AreEqual(legacyParentId, telemetry.Context.Operation.ParentId); } Assert.AreEqual(activity.TraceId.ToHexString(), telemetry.Context.Operation.Id); } else { Assert.AreEqual(activity.ParentId, telemetry.Context.Operation.ParentId); Assert.AreEqual(activity.RootId, telemetry.Context.Operation.Id); } foreach (var baggage in activity.Baggage) { Assert.IsTrue(telemetry.Properties.ContainsKey(baggage.Key)); Assert.AreEqual(baggage.Value, telemetry.Properties[baggage.Key]); } foreach (var tag in activity.Tags) { Assert.IsTrue(telemetry.Properties.ContainsKey(tag.Key)); Assert.AreEqual(tag.Value, telemetry.Properties[tag.Key]); } if (activity.TraceStateString != null) { Assert.IsTrue(telemetry.Properties.TryGetValue("tracestate", out var tracestate)); Assert.AreEqual(activity.TraceStateString, tracestate); } else { Assert.IsFalse(telemetry.Properties.ContainsKey("tracestate")); } Assert.AreEqual(activity.Recorded ? SamplingDecision.SampledIn : SamplingDecision.None, (telemetry as ISupportAdvancedSampling).ProactiveSamplingDecision); }
/// <summary> /// Start operation creates an operation object with a respective telemetry item. /// </summary> /// <typeparam name="T">Type of the telemetry item.</typeparam> /// <param name="telemetryClient">Telemetry client object.</param> /// <param name="operationName">Name of the operation that customer is planning to propagate.</param> /// <param name="operationId">Operation ID to set in the new operation.</param> /// <param name="parentOperationId">Optional parent operation ID to set in the new operation.</param> /// <returns>Operation item object with a new telemetry item having current start time and timestamp.</returns> public static IOperationHolder <T> StartOperation <T>(this TelemetryClient telemetryClient, string operationName, string operationId, string parentOperationId = null) where T : OperationTelemetry, new() { if (telemetryClient == null) { throw new ArgumentNullException(nameof(telemetryClient)); } var operationTelemetry = new T(); if (string.IsNullOrEmpty(operationTelemetry.Name) && !string.IsNullOrEmpty(operationName)) { operationTelemetry.Name = operationName; } if (string.IsNullOrEmpty(operationTelemetry.Context.Operation.Id) && !string.IsNullOrEmpty(operationId)) { var isActivityAvailable = ActivityExtensions.TryRun(() => { if (Activity.DefaultIdFormat == ActivityIdFormat.W3C) { if (W3CUtilities.IsCompatibleW3CTraceId(operationId)) { // If the user provided operationid is W3C Compatible, use it. operationTelemetry.Context.Operation.Id = operationId; } else { // If user provided operationid is not W3C compatible, generate a new one instead. // and store supplied value inside customproperty. operationTelemetry.Context.Operation.Id = ActivityTraceId.CreateRandom().ToHexString(); operationTelemetry.Properties.Add(W3CConstants.LegacyRootIdProperty, operationId); } } else { operationTelemetry.Context.Operation.Id = operationId; } }); if (!isActivityAvailable) { operationTelemetry.Context.Operation.Id = operationId; } } if (string.IsNullOrEmpty(operationTelemetry.Context.Operation.ParentId) && !string.IsNullOrEmpty(parentOperationId)) { operationTelemetry.Context.Operation.ParentId = parentOperationId; } return(StartOperation(telemetryClient, operationTelemetry)); }
public override void OnEvent(KeyValuePair <string, object> evnt, DiagnosticListener ignored) { Activity currentActivity = Activity.Current; switch (evnt.Key) { case "Microsoft.Azure.ServiceBus.ProcessSession.Stop": case "Microsoft.Azure.ServiceBus.Process.Stop": // If we started auxiliary Activity before to override the Id with W3C compatible one, // now it's time to set end time on it if (currentActivity.Duration == TimeSpan.Zero) { currentActivity.SetEndTime(DateTime.UtcNow); } this.OnRequest(evnt.Key, evnt.Value, currentActivity); break; case "Microsoft.Azure.ServiceBus.Exception": break; default: if (evnt.Key.EndsWith(TelemetryDiagnosticSourceListener.ActivityStartNameSuffix, StringComparison.Ordinal)) { // As a first step in supporting W3C protocol in ApplicationInsights, // we want to generate Activity Ids in the W3C compatible format. // While .NET changes to Activity are pending, we want to ensure trace starts with W3C compatible Id // as early as possible, so that everyone has a chance to upgrade and have compatibility with W3C systems once they arrive. // So if there is no parent Activity (i.e. this request has happened in the background, without parent scope), we'll override // the current Activity with the one with properly formatted Id. This workaround should go away // with W3C support on .NET https://github.com/dotnet/corefx/issues/30331 (TODO) if (currentActivity.Parent == null && currentActivity.ParentId == null) { currentActivity.UpdateParent(W3CUtilities.GenerateTraceId()); } } else if (evnt.Key.EndsWith(TelemetryDiagnosticSourceListener.ActivityStopNameSuffix, StringComparison.Ordinal)) { // If we started auxiliary Activity before to override the Id with W3C compatible one, // now it's time to set end time on it if (currentActivity.Duration == TimeSpan.Zero) { currentActivity.SetEndTime(DateTime.UtcNow); } this.OnDependency(evnt.Key, evnt.Value, currentActivity); } break; } }
private void ValidateRootTelemetry(OperationTelemetry operationTelemetry, string expectedOperationId, string expectedId, string expectedOperationParentId, bool isW3C) { Assert.AreEqual(expectedOperationParentId, operationTelemetry.Context.Operation.ParentId); Assert.IsNotNull(operationTelemetry.Context.Operation.Id); Assert.AreEqual(expectedOperationId, operationTelemetry.Context.Operation.Id); if (isW3C) { Assert.IsTrue(W3CUtilities.IsCompatibleW3CTraceId(operationTelemetry.Context.Operation.Id)); } Assert.IsNotNull(operationTelemetry.Id); Assert.AreEqual(expectedId, operationTelemetry.Id); }
private static T ActivityToTelemetry <T>(Activity activity) where T : OperationTelemetry, new() { Debug.Assert(activity.Id != null, "Activity must be started prior calling this method"); var telemetry = new T { Name = activity.OperationName }; OperationContext operationContext = telemetry.Context.Operation; operationContext.Name = activity.GetOperationName(); if (activity.IdFormat == ActivityIdFormat.W3C) { operationContext.Id = activity.TraceId.ToHexString(); telemetry.Id = W3CUtilities.FormatTelemetryId(operationContext.Id, activity.SpanId.ToHexString()); if (string.IsNullOrEmpty(operationContext.ParentId) && activity.ParentSpanId != default) { operationContext.ParentId = W3CUtilities.FormatTelemetryId(operationContext.Id, activity.ParentSpanId.ToHexString()); } } else { operationContext.Id = activity.RootId; operationContext.ParentId = activity.ParentId; telemetry.Id = activity.Id; } foreach (var item in activity.Baggage) { if (!telemetry.Properties.ContainsKey(item.Key)) { telemetry.Properties.Add(item); } } foreach (var item in activity.Tags) { if (!telemetry.Properties.ContainsKey(item.Key)) { telemetry.Properties.Add(item); } } return(telemetry); }
private void ValidateRootTelemetry(OperationTelemetry operationTelemetry, string expectedOperationId = "", string expectedOperationParentId = null, bool isW3C = true) { Assert.AreEqual(expectedOperationParentId, operationTelemetry.Context.Operation.ParentId); Assert.IsNotNull(operationTelemetry.Context.Operation.Id); if (!string.IsNullOrEmpty(expectedOperationId)) { Assert.AreEqual(expectedOperationId, operationTelemetry.Context.Operation.Id); } if (isW3C) { Assert.IsTrue(W3CUtilities.IsCompatibleW3CTraceId(operationTelemetry.Context.Operation.Id)); } Assert.IsNotNull(operationTelemetry.Id); // ID is shaped like |TraceID.SpanID. Assert.IsTrue(operationTelemetry.Id.Contains(operationTelemetry.Context.Operation.Id)); }
public void InitializesTelemetryFromParentActivityW3C(string beforeEventName, string afterEventName) { var activity = new Activity("Current").AddBaggage("Stuff", "123"); activity.Start(); var operationId = Guid.NewGuid(); var sqlConnection = new SqlConnection(TestConnectionString); var sqlCommand = sqlConnection.CreateCommand(); sqlCommand.CommandText = "select * from orders"; var beforeExecuteEventData = new { OperationId = operationId, Command = sqlCommand, Timestamp = (long?)1000000L }; this.fakeSqlClientDiagnosticSource.Write( beforeEventName, beforeExecuteEventData); var afterExecuteEventData = new { OperationId = operationId, Command = sqlCommand, Timestamp = 2000000L }; this.fakeSqlClientDiagnosticSource.Write( afterEventName, afterExecuteEventData); var dependencyTelemetry = (DependencyTelemetry)this.sendItems.Single(); Assert.Equal(activity.TraceId.ToHexString(), dependencyTelemetry.Context.Operation.Id); Assert.Equal(W3CUtilities.FormatTelemetryId(activity.TraceId.ToHexString(), activity.SpanId.ToHexString()), dependencyTelemetry.Context.Operation.ParentId); Assert.Equal("123", dependencyTelemetry.Properties["Stuff"]); }
public void UpdateValidRequestTelemetryWithForceTrue() { var traceId = W3CUtilities.GenerateTraceId(); var parentSpanId = W3CUtilities.GenerateSpanId(); var spanId = W3CUtilities.GenerateSpanId(); var telemetry = new RequestTelemetry(); telemetry.Context.Operation.Id = traceId; telemetry.Context.Operation.ParentId = $"|{traceId}.{parentSpanId}."; telemetry.Id = $"|{traceId}.{spanId}."; var a = new Activity("foo").Start(); a.SetTraceparent($"00-{traceId}-{spanId}-01"); a.UpdateTelemetry(telemetry, true); Assert.AreEqual(traceId, telemetry.Context.Operation.Id); Assert.AreEqual($"|{traceId}.{spanId}.", telemetry.Context.Operation.ParentId); Assert.AreEqual($"|{traceId}.{a.GetSpanId()}.", telemetry.Id); }
public void InitializePopulatesOperationContextFromActivity() { // Arrange Activity activity = new Activity("somename"); activity.Start(); var telemetry = new DependencyTelemetry(); var originalTelemetryId = telemetry.Id; // Act var initializer = new OperationCorrelationTelemetryInitializer(); initializer.Initialize(telemetry); // Validate Assert.AreEqual(activity.TraceId.ToHexString(), telemetry.Context.Operation.Id, "OperationCorrelationTelemetryInitializer is expected to populate OperationID from Activity"); Assert.AreEqual(W3CUtilities.FormatTelemetryId(activity.TraceId.ToHexString(), activity.SpanId.ToHexString()), telemetry.Context.Operation.ParentId, "OperationCorrelationTelemetryInitializer is expected to populate Operation ParentID as |traceID.SpanId. from Activity"); Assert.AreEqual(originalTelemetryId, telemetry.Id, "OperationCorrelationTelemetryInitializer is not expected to modify Telemetry ID"); activity.Stop(); }
public void InitializeWithActivityWinsOverCallContext() { CallContextHelpers.SaveOperationContext(new OperationContextForCallContext { RootOperationId = "callContextRoot" }); var currentActivity = new Activity("test"); currentActivity.AddTag("OperationName", "operation"); currentActivity.AddBaggage("k1", "v1"); currentActivity.Start(); var telemetry = new RequestTelemetry(); (new OperationCorrelationTelemetryInitializer()).Initialize(telemetry); Assert.AreEqual(currentActivity.TraceId.ToHexString(), telemetry.Context.Operation.Id); Assert.AreEqual(W3CUtilities.FormatTelemetryId(currentActivity.TraceId.ToHexString(), currentActivity.SpanId.ToHexString()), telemetry.Context.Operation.ParentId); Assert.AreEqual("operation", telemetry.Context.Operation.Name); Assert.AreEqual(1, telemetry.Properties.Count); Assert.AreEqual("v1", telemetry.Properties["k1"]); currentActivity.Stop(); }
public void StartDependencyTrackingHandlesMultipleContextStoresInCurrentActivityW3C() { var operation = this.telemetryClient.StartOperation <DependencyTelemetry>("OperationName") as OperationHolder <DependencyTelemetry>; var currentActivity = Activity.Current; Assert.AreEqual(operation.Telemetry.Id, W3CUtilities.FormatTelemetryId(currentActivity.TraceId.ToHexString(), currentActivity.SpanId.ToHexString())); Assert.AreEqual(operation.Telemetry.Context.Operation.Name, this.GetOperationName(currentActivity)); var childOperation = this.telemetryClient.StartOperation <DependencyTelemetry>("OperationName") as OperationHolder <DependencyTelemetry>; var childActivity = Activity.Current; Assert.AreEqual(childOperation.Telemetry.Id, W3CUtilities.FormatTelemetryId(childActivity.TraceId.ToHexString(), childActivity.SpanId.ToHexString())); Assert.AreEqual(childOperation.Telemetry.Context.Operation.Name, this.GetOperationName(currentActivity)); Assert.IsNull(currentActivity.Parent); Assert.AreEqual(currentActivity, childActivity.Parent); this.telemetryClient.StopOperation(childOperation); Assert.AreEqual(currentActivity, Activity.Current); this.telemetryClient.StopOperation(operation); Assert.IsNull(Activity.Current); }
private static void InitializeTelemetry(DependencyTelemetry telemetry, Guid operationId, long timestamp) { telemetry.Start(timestamp); var activity = Activity.Current; if (activity != null) { // SQL Client does NOT create Activity. // We initialize SQL dependency using Activity from incoming Request // and it is the parent of the SQL dependency if (activity.IdFormat == ActivityIdFormat.W3C) { var traceId = activity.TraceId.ToHexString(); telemetry.Context.Operation.Id = traceId; telemetry.Context.Operation.ParentId = W3CUtilities.FormatTelemetryId(traceId, activity.SpanId.ToHexString()); } else { telemetry.Context.Operation.Id = activity.RootId; telemetry.Context.Operation.ParentId = activity.Id; } foreach (var item in activity.Baggage) { if (!telemetry.Properties.ContainsKey(item.Key)) { telemetry.Properties[item.Key] = item.Value; } } } else { telemetry.Context.Operation.Id = operationId.ToStringInvariant("N"); } }
public void InitializeSetsBaggage() { var currentActivity = new Activity("test"); currentActivity.AddTag("OperationName", "operation"); currentActivity.AddBaggage("k1", "v1"); currentActivity.AddBaggage("k2", "v2"); currentActivity.AddBaggage("existingkey", "exitingvalue"); currentActivity.Start(); var telemetry = new RequestTelemetry(); telemetry.Properties.Add("existingkey", "exitingvalue"); (new OperationCorrelationTelemetryInitializer()).Initialize(telemetry); Assert.AreEqual(currentActivity.TraceId.ToHexString(), telemetry.Context.Operation.Id); Assert.AreEqual(W3CUtilities.FormatTelemetryId(currentActivity.TraceId.ToHexString(), currentActivity.SpanId.ToHexString()), telemetry.Context.Operation.ParentId); Assert.AreEqual("operation", telemetry.Context.Operation.Name); Assert.AreEqual(3, telemetry.Properties.Count); Assert.AreEqual("v1", telemetry.Properties["k1"]); Assert.AreEqual("v2", telemetry.Properties["k2"]); Assert.AreEqual("exitingvalue", telemetry.Properties["existingkey"], "OperationCorrelationTelemetryInitializer should not override existing telemetry property bag"); currentActivity.Stop(); }
internal static RequestTelemetry CreateRequestTelemetryPrivate( this HttpContext platformContext) { if (platformContext == null) { throw new ArgumentNullException(nameof(platformContext)); } var currentActivity = Activity.Current; var result = new RequestTelemetry(); var requestContext = result.Context.Operation; string legacyParentId = null; string legacyRootId = null; var headers = platformContext.Request.Unvalidated.Headers; if (currentActivity == null) { // if there was no BeginRequest, ASP.NET HttpModule did not have a chance to set current activity yet // this could happen if ASP.NET TelemetryCorrelation module is not the first in the pipeline // and some module before it tracks telemetry. // The ASP.NET module will be invoked later with proper correlation ids. // But we only get one chance to create request telemetry and we have to create it when method is called to avoid breaking changes // The correlation will be BROKEN anyway as telemetry reported before ASP.NET TelemetryCorrelation HttpModule is called // will not be correlated properly to telemetry reported within the request // Here we simply maintaining backward compatibility with this behavior... #pragma warning disable CA2000 // Dispose objects before losing scope // Since we don't know when it will finish, we will not dispose currentActivity = new Activity(ActivityHelpers.RequestActivityItemName); #pragma warning restore CA2000 // Dispose objects before losing scope if (!currentActivity.Extract(headers)) { if (ActivityHelpers.ParentOperationIdHeaderName != null && ActivityHelpers.RootOperationIdHeaderName != null) { legacyRootId = StringUtilities.EnforceMaxLength(platformContext.Request.UnvalidatedGetHeader(ActivityHelpers.RootOperationIdHeaderName), InjectionGuardConstants.RequestHeaderMaxLength); legacyParentId = StringUtilities.EnforceMaxLength( platformContext.Request.UnvalidatedGetHeader(ActivityHelpers.ParentOperationIdHeaderName), InjectionGuardConstants.RequestHeaderMaxLength); currentActivity.SetParentId(legacyRootId); } headers.ReadActivityBaggage(currentActivity); } currentActivity.Start(); } if (currentActivity.IdFormat == ActivityIdFormat.W3C && currentActivity.ParentId != null && !currentActivity.ParentId.StartsWith("00-", StringComparison.Ordinal)) { if (W3CUtilities.TryGetTraceId(currentActivity.ParentId, out var traceId)) { legacyParentId = currentActivity.ParentId; #pragma warning disable CA2000 // Dispose objects before losing scope // Since we don't know when it will finish, we will not dispose currentActivity = CreateSubstituteActivityFromCompatibleRootId(currentActivity, traceId); #pragma warning restore CA2000 // Dispose objects before losing scope } else { legacyRootId = W3CUtilities.GetRootId(currentActivity.ParentId); legacyParentId = legacyParentId ?? GetLegacyParentId(currentActivity.ParentId, platformContext.Request); } } else if (currentActivity.IdFormat == ActivityIdFormat.Hierarchical && currentActivity.ParentId != null) { legacyParentId = GetLegacyParentId(currentActivity.ParentId, platformContext.Request); } if (currentActivity.IdFormat == ActivityIdFormat.W3C) { // we have Activity.Current, we need to properly initialize request telemetry and store it in HttpContext requestContext.Id = currentActivity.TraceId.ToHexString(); if (currentActivity.ParentSpanId != default && legacyParentId == null) { requestContext.ParentId = currentActivity.ParentSpanId.ToHexString(); } else { requestContext.ParentId = legacyParentId; if (legacyRootId != null) { result.Properties[W3CConstants.LegacyRootPropertyIdKey] = legacyRootId; } } result.Id = currentActivity.SpanId.ToHexString(); } else { // we have Activity.Current, we need to properly initialize request telemetry and store it in HttpContext requestContext.Id = currentActivity.RootId; requestContext.ParentId = legacyParentId ?? currentActivity.ParentId; result.Id = currentActivity.Id; } foreach (var item in currentActivity.Baggage) { if (!result.Properties.ContainsKey(item.Key)) { result.Properties.Add(item); } } // save current activity in case it will be lost (under the same name TelemetryCorrelation stores it) // TelemetryCorrelation will restore it when possible. platformContext.Items[ActivityHelpers.RequestActivityItemName] = currentActivity; platformContext.Items[RequestTrackingConstants.RequestTelemetryItemName] = result; WebEventSource.Log.WebTelemetryModuleRequestTelemetryCreated(); return(result); }
private void InjectRequestHeaders(HttpRequestMessage request, string instrumentationKey) { try { HttpRequestHeaders requestHeaders = request.Headers; if (requestHeaders != null && this.setComponentCorrelationHttpHeaders && !this.correlationDomainExclusionList.Contains(request.RequestUri.Host)) { string sourceApplicationId = null; try { if (!string.IsNullOrEmpty(instrumentationKey) && !HttpHeadersUtilities.ContainsRequestContextKeyValue(requestHeaders, RequestResponseHeaders.RequestContextCorrelationSourceKey) && (this.configuration.ApplicationIdProvider?.TryGetApplicationId(instrumentationKey, out sourceApplicationId) ?? false)) { HttpHeadersUtilities.SetRequestContextKeyValue(requestHeaders, RequestResponseHeaders.RequestContextCorrelationSourceKey, sourceApplicationId); } } catch (Exception e) { AppMapCorrelationEventSource.Log.UnknownError(ExceptionUtilities.GetExceptionDetailString(e)); } var currentActivity = Activity.Current; switch (this.httpInstrumentationVersion) { case HttpInstrumentationVersion.V1: // HttpClient does not add any headers // add W3C or Request-Id depending on Activity format // add correlation-context anyway if (currentActivity.IdFormat == ActivityIdFormat.W3C) { InjectW3CHeaders(currentActivity, requestHeaders); if (this.injectRequestIdInW3CMode) { InjectBackCompatibleRequestId(currentActivity, requestHeaders); } } else { if (!requestHeaders.Contains(RequestResponseHeaders.RequestIdHeader)) { requestHeaders.Add(RequestResponseHeaders.RequestIdHeader, currentActivity.Id); } } InjectCorrelationContext(requestHeaders, currentActivity); break; case HttpInstrumentationVersion.V2: // On V2, HttpClient adds Request-Id and Correlation-Context // but not W3C if (currentActivity.IdFormat == ActivityIdFormat.W3C) { // we are going to add W3C and Request-Id (in W3C-compatible format) // as a result HttpClient will not add Request-Id AND Correlation-Context InjectW3CHeaders(currentActivity, requestHeaders); if (this.injectRequestIdInW3CMode) { InjectBackCompatibleRequestId(currentActivity, requestHeaders); } InjectCorrelationContext(requestHeaders, currentActivity); } break; case HttpInstrumentationVersion.V3: // on V3, HttpClient adds either W3C or Request-Id depending on Activity format // and adds Correlation-Context if (currentActivity.IdFormat == ActivityIdFormat.W3C && this.injectRequestIdInW3CMode) { // we are going to override Request-Id to be in W3C compatible mode InjectBackCompatibleRequestId(currentActivity, requestHeaders); } break; } if (this.injectLegacyHeaders) { // Add the root ID (Activity.RootId works with W3C and Hierarchical format) string rootId = currentActivity.RootId; if (!string.IsNullOrEmpty(rootId) && !requestHeaders.Contains(RequestResponseHeaders.StandardRootIdHeader)) { requestHeaders.Add(RequestResponseHeaders.StandardRootIdHeader, rootId); } // Add the parent ID string parentId = currentActivity.IdFormat == ActivityIdFormat.W3C ? W3CUtilities.FormatTelemetryId(rootId, currentActivity.SpanId.ToHexString()) : currentActivity.Id; if (!string.IsNullOrEmpty(parentId) && !requestHeaders.Contains(RequestResponseHeaders.StandardParentIdHeader)) { requestHeaders.Add(RequestResponseHeaders.StandardParentIdHeader, parentId); } } } } catch (Exception e) { AppMapCorrelationEventSource.Log.UnknownError(ExceptionUtilities.GetExceptionDetailString(e)); } }
//// netcoreapp 2.0 event /// <summary> /// Handler for Activity stop event (response is received for the outgoing request). /// </summary> internal void OnActivityStop(HttpResponseMessage response, HttpRequestMessage request, TaskStatus requestTaskStatus) { // Even though we have the IsEnabled filter to reject ApplicationInsights URLs before any events are fired, if there // are multiple subscribers and one subscriber returns true to IsEnabled then all subscribers will receive the event. if (this.applicationInsightsUrlFilter.IsApplicationInsightsUrl(request.RequestUri)) { return; } Activity currentActivity = Activity.Current; if (currentActivity == null) { DependencyCollectorEventSource.Log.CurrentActivityIsNull(HttpOutStopEventName); return; } if (Activity.DefaultIdFormat == ActivityIdFormat.W3C && request.Headers.TryGetValues(W3C.W3CConstants.TraceParentHeader, out var parents) && parents.FirstOrDefault() != currentActivity.Id) { DependencyCollectorEventSource.Log.HttpRequestAlreadyInstrumented(); return; } DependencyCollectorEventSource.Log.HttpCoreDiagnosticSourceListenerStop(currentActivity.Id); Uri requestUri = request.RequestUri; var resourceName = request.Method.Method + " " + requestUri.AbsolutePath; DependencyTelemetry telemetry = new DependencyTelemetry(); telemetry.SetOperationDetail(RemoteDependencyConstants.HttpRequestOperationDetailName, request); // properly fill dependency telemetry operation context: OperationCorrelationTelemetryInitializer initializes child telemetry if (currentActivity.IdFormat == ActivityIdFormat.W3C) { var traceId = currentActivity.TraceId.ToHexString(); telemetry.Context.Operation.Id = traceId; if (currentActivity.ParentSpanId != default) { telemetry.Context.Operation.ParentId = W3CUtilities.FormatTelemetryId(traceId, currentActivity.ParentSpanId.ToHexString()); } telemetry.Id = W3CUtilities.FormatTelemetryId(traceId, currentActivity.SpanId.ToHexString()); } else { telemetry.Context.Operation.Id = currentActivity.RootId; telemetry.Context.Operation.ParentId = currentActivity.ParentId; telemetry.Id = currentActivity.Id; } foreach (var item in currentActivity.Baggage) { if (!telemetry.Properties.ContainsKey(item.Key)) { telemetry.Properties[item.Key] = item.Value; } } // TODO[tracestate]: remove, this is done in base SDK if (!string.IsNullOrEmpty(currentActivity.TraceStateString) && !telemetry.Properties.ContainsKey(W3CConstants.TracestatePropertyKey)) { telemetry.Properties.Add(W3CConstants.TracestatePropertyKey, currentActivity.TraceStateString); } this.client.Initialize(telemetry); // If we started auxiliary Activity before to override the Id with W3C compatible one, // now it's time to set end time on it if (currentActivity.Duration == TimeSpan.Zero) { currentActivity.SetEndTime(DateTime.UtcNow); } telemetry.Timestamp = currentActivity.StartTimeUtc; telemetry.Name = resourceName; telemetry.Target = DependencyTargetNameHelper.GetDependencyTargetName(requestUri); telemetry.Type = RemoteDependencyConstants.HTTP; telemetry.Data = requestUri.OriginalString; telemetry.Duration = currentActivity.Duration; if (response != null) { this.ParseResponse(response, telemetry); telemetry.SetOperationDetail(RemoteDependencyConstants.HttpResponseOperationDetailName, response); } else { if (this.pendingExceptions.TryRemove(currentActivity.Id, out Exception exception)) { telemetry.Properties[RemoteDependencyConstants.DependencyErrorPropertyKey] = exception.GetBaseException().Message; } telemetry.ResultCode = requestTaskStatus.ToString(); telemetry.Success = false; } this.client.TrackDependency(telemetry); }
public static string GenerateSpanId() { return(W3CUtilities.GenerateTraceId().Substring(0, 16)); }
public static string GenerateTraceId() { return(W3CUtilities.GenerateTraceId()); }
/// <summary> /// Diagnostic event handler method for 'Microsoft.AspNetCore.Hosting.BeginRequest' event. This is from 1.XX runtime. /// </summary> public void OnBeginRequest(HttpContext httpContext, long timestamp) { if (this.client.IsEnabled() && !this.enableNewDiagnosticEvents) { // It's possible to host multiple apps (ASP.NET Core or generic hosts) in the same process // Each of this apps has it's own HostingDiagnosticListener and corresponding Http listener. // We should ignore events for all of them except one if (!SubscriptionManager.IsActive(this)) { AspNetCoreEventSource.Instance.NotActiveListenerNoTracking( "Microsoft.AspNetCore.Hosting.BeginRequest", Activity.Current?.Id); return; } var activity = new Activity(ActivityCreatedByHostingDiagnosticListener); string sourceAppId = null; IHeaderDictionary requestHeaders = httpContext.Request.Headers; string originalParentId = null; // W3C if (this.enableW3CHeaders) { this.SetW3CContext(httpContext.Request.Headers, activity, out sourceAppId); var parentSpanId = activity.GetParentSpanId(); if (parentSpanId != null) { originalParentId = $"|{activity.GetTraceId()}.{parentSpanId}."; } // length enforced in SetW3CContext } // Request-Id if (requestHeaders.TryGetValue(RequestResponseHeaders.RequestIdHeader, out StringValues requestIdValues) && requestIdValues != StringValues.Empty) { var requestId = StringUtilities.EnforceMaxLength(requestIdValues.First(), InjectionGuardConstants.RequestHeaderMaxLength); activity.SetParentId(requestId); ReadCorrelationContext(requestHeaders, activity); if (originalParentId == null) { originalParentId = requestId; } } // 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. // While .NET changes to Activity are pending, we want to ensure trace starts with W3C compatible Id // as early as possible, so that everyone has a chance to upgrade and have compatibility with W3C systems once they arrive. // 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 if (this.enableW3CHeaders) { activity.GenerateW3CContext(); activity.SetParentId(activity.GetTraceId()); } else { activity.SetParentId(W3CUtilities.GenerateTraceId()); } // end of workaround } activity.Start(); var requestTelemetry = this.InitializeRequestTelemetry(httpContext, activity, timestamp); if (this.enableW3CHeaders && sourceAppId != null) { requestTelemetry.Source = sourceAppId; } // fix parent that may be modified by non-W3C operation correlation requestTelemetry.Context.Operation.ParentId = originalParentId; this.AddAppIdToResponseIfRequired(httpContext, requestTelemetry); } }
/// <summary> /// Diagnostic event handler method for 'Microsoft.AspNetCore.Hosting.HttpRequestIn.Start' event. This is from 2.XX runtime. /// </summary> public void OnHttpRequestInStart(HttpContext httpContext) { if (this.client.IsEnabled()) { // It's possible to host multiple apps (ASP.NET Core or generic hosts) in the same process // Each of this apps has it's own HostingDiagnosticListener and corresponding Http listener. // We should ignore events for all of them except one if (!SubscriptionManager.IsActive(this)) { AspNetCoreEventSource.Instance.NotActiveListenerNoTracking("Microsoft.AspNetCore.Hosting.HttpRequestIn.Start", Activity.Current?.Id); return; } if (Activity.Current == null) { AspNetCoreEventSource.Instance.LogHostingDiagnosticListenerOnHttpRequestInStartActivityNull(); return; } var currentActivity = Activity.Current; string sourceAppId = null; string originalParentId = currentActivity.ParentId; Activity newActivity = null; // W3C if (this.enableW3CHeaders) { this.SetW3CContext(httpContext.Request.Headers, currentActivity, out sourceAppId); var parentSpanId = currentActivity.GetParentSpanId(); if (parentSpanId != null) { originalParentId = $"|{currentActivity.GetTraceId()}.{parentSpanId}."; } } // no headers if (originalParentId == null) { // As a first step in supporting W3C protocol in ApplicationInsights, // we want to generate Activity Ids in the W3C compatible format. // While .NET changes to Activity are pending, we want to ensure trace starts with W3C compatible Id // as early as possible, so that everyone has a chance to upgrade and have compatibility with W3C systems once they arrive. // 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 newActivity = new Activity(ActivityCreatedByHostingDiagnosticListener); if (this.enableW3CHeaders) { newActivity.GenerateW3CContext(); newActivity.SetParentId(newActivity.GetTraceId()); } else { newActivity.SetParentId(W3CUtilities.GenerateTraceId()); } // end of workaround } if (newActivity != null) { newActivity.Start(); currentActivity = newActivity; } var requestTelemetry = this.InitializeRequestTelemetry(httpContext, currentActivity, Stopwatch.GetTimestamp()); if (this.enableW3CHeaders && sourceAppId != null) { requestTelemetry.Source = sourceAppId; } requestTelemetry.Context.Operation.ParentId = originalParentId; this.AddAppIdToResponseIfRequired(httpContext, requestTelemetry); } }
public void GenerateSpanIdGeneratesValidId() { var spanId = W3CUtilities.GenerateSpanId(); Assert.IsTrue(SpanIdRegex.IsMatch(spanId)); }
public void GenerateTraceIdGeneratesValidId() { var traceId = W3CUtilities.GenerateTraceId(); Assert.IsTrue(TraceIdRegex.IsMatch(traceId)); }