public void InitializerPopulatesTraceStateOnRequestAndDependencyTelemetry() { Activity a = new Activity("dummy") .Start() .GenerateW3CContext(); a.SetTracestate("key=value"); string expectedTrace = a.GetTraceId(); string expectedSpanId = a.GetSpanId(); RequestTelemetry request = new RequestTelemetry(); DependencyTelemetry dependency = new DependencyTelemetry(); TraceTelemetry trace = new TraceTelemetry(); var initializer = new W3COperationCorrelationTelemetryInitializer(); initializer.Initialize(request); initializer.Initialize(dependency); initializer.Initialize(trace); Assert.AreEqual(expectedTrace, request.Context.Operation.Id); Assert.AreEqual($"|{expectedTrace}.{expectedSpanId}.", request.Id); Assert.AreEqual("key=value", request.Properties[W3CConstants.TracestateTag]); Assert.AreEqual("key=value", dependency.Properties[W3CConstants.TracestateTag]); Assert.IsFalse(trace.Properties.Any()); }
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()); W3COperationCorrelationTelemetryInitializer.UpdateTelemetry(result, currentActivity, 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(StringUtilities.GenerateTraceId()); // end of workaround } currentActivity.Start(); }
/// <summary> /// The function that needs to be called before sending a request to the server. Creates and initializes dependency telemetry item. /// </summary> /// <param name="telemetryClient">Telemetry client object to initialize the context of the telemetry item.</param> internal static DependencyTelemetry BeginTracking(TelemetryClient telemetryClient) { var telemetry = new DependencyTelemetry(); telemetry.Start(); Activity activity; Activity currentActivity = Activity.Current; // On .NET46 without profiler, outgoing requests are instrumented with reflection hook in DiagnosticSource //// see https://github.com/dotnet/corefx/blob/master/src/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/HttpHandlerDiagnosticListener.cs // it creates an Activity and injects standard 'Request-Id' and 'Correlation-Context' headers itself, so we should not start Activity in this case if (currentActivity != null && currentActivity.OperationName == "System.Net.Http.Desktop.HttpRequestOut") { activity = currentActivity; // OperationCorrelationTelemetryInitializer will initialize telemetry as a child of current activity: // But we need to initialize dependency telemetry from the current Activity: // Activity was created for this dependency in the Http Desktop DiagnosticSource var context = telemetry.Context; context.Operation.Id = activity.RootId; context.Operation.ParentId = activity.ParentId; foreach (var item in activity.Baggage) { if (!telemetry.Properties.ContainsKey(item.Key)) { telemetry.Properties.Add(item); } } telemetryClient.Initialize(telemetry); } else { telemetryClient.Initialize(telemetry); // Every operation must have its own Activity // if dependency is tracked with profiler of event source, we need to generate a proper Id for it // in case of HTTP it will be propagated into the requert header. // So, we will create a new Activity for the dependency, just to generate an Id. activity = new Activity(DependencyActivityName); // 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 == null) { activity.SetParentId(StringUtilities.GenerateTraceId()); } // end of workaround activity.Start(); } // telemetry is initialized from current Activity (root and parent Id, but not the Id) telemetry.Id = activity.Id; // set operation root Id in case there was no parent activity (e.g. HttpRequest in background thread) if (string.IsNullOrEmpty(telemetry.Context.Operation.Id)) { telemetry.Context.Operation.Id = activity.RootId; } #pragma warning disable 612, 618 if (IsW3CEnabled) { W3COperationCorrelationTelemetryInitializer.UpdateTelemetry(telemetry, activity, true); } #pragma warning restore 612, 618 PretendProfilerIsAttached = false; return(telemetry); }