From 78dc7e3f4f9e9d9540fd53dc884f2445a3f1b4c6 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Tue, 10 Sep 2019 10:23:36 -0700 Subject: [PATCH] Set tracestate and sampling decision even if operation id is set (#1211) --- ...ionCorrelationTelemetryInitializerTests.cs | 32 +++++++ ...perationCorrelationTelemetryInitializer.cs | 95 ++++++++++--------- 2 files changed, 83 insertions(+), 44 deletions(-) diff --git a/Test/Microsoft.ApplicationInsights.Test/Shared/Extensibility/OperationCorrelationTelemetryInitializerTests.cs b/Test/Microsoft.ApplicationInsights.Test/Shared/Extensibility/OperationCorrelationTelemetryInitializerTests.cs index c3ec3e16c1..436cc5c346 100644 --- a/Test/Microsoft.ApplicationInsights.Test/Shared/Extensibility/OperationCorrelationTelemetryInitializerTests.cs +++ b/Test/Microsoft.ApplicationInsights.Test/Shared/Extensibility/OperationCorrelationTelemetryInitializerTests.cs @@ -300,6 +300,21 @@ public void InitializeWithActivityRecorded() currentActivity.Stop(); } + [TestMethod] + public void InitializeWithActivityRecordedOperationIdSet() + { + var currentActivity = new Activity("test"); + currentActivity.ActivityTraceFlags |= ActivityTraceFlags.Recorded; + currentActivity.Start(); + var request = new RequestTelemetry(); + request.Context.Operation.Id = ActivityTraceId.CreateRandom().ToHexString(); + + (new OperationCorrelationTelemetryInitializer()).Initialize(request); + + Assert.AreEqual(SamplingDecision.SampledIn, request.ProactiveSamplingDecision); + currentActivity.Stop(); + } + [TestMethod] public void InitializeWithActivityNotRecorded() { @@ -413,5 +428,22 @@ public void InitializeOnActivityWithTracestateNotOperationTelemetry() // does not throw (new OperationCorrelationTelemetryInitializer()).Initialize(telemetry); } + + [TestMethod] + public void InitializeOnActivityWithTracestateAndOperationIdSet() + { + Activity parent = new Activity("parent") + { + TraceStateString = "some=state" + }; + parent.Start(); + + var telemetry = new DependencyTelemetry(); + telemetry.Context.Operation.Id = ActivityTraceId.CreateRandom().ToHexString(); + (new OperationCorrelationTelemetryInitializer()).Initialize(telemetry); + + Assert.IsTrue(telemetry.Properties.ContainsKey("tracestate")); + Assert.AreEqual("some=state", telemetry.Properties["tracestate"]); + } } } \ No newline at end of file diff --git a/src/Microsoft.ApplicationInsights/Extensibility/OperationCorrelationTelemetryInitializer.cs b/src/Microsoft.ApplicationInsights/Extensibility/OperationCorrelationTelemetryInitializer.cs index 89ea56deb5..0b343f8a83 100644 --- a/src/Microsoft.ApplicationInsights/Extensibility/OperationCorrelationTelemetryInitializer.cs +++ b/src/Microsoft.ApplicationInsights/Extensibility/OperationCorrelationTelemetryInitializer.cs @@ -29,65 +29,72 @@ public void Initialize(ITelemetry telemetryItem) isActivityAvailable = ActivityExtensions.TryRun(() => { var currentActivity = Activity.Current; - if (currentActivity != null && string.IsNullOrEmpty(itemOperationContext.Id)) + if (currentActivity != null) { - if (currentActivity.IdFormat == ActivityIdFormat.W3C) + // we are going to set tracestate property on requests and dependencies only + if (currentActivity.IdFormat == ActivityIdFormat.W3C && + !string.IsNullOrEmpty(currentActivity.TraceStateString) && + telemetryItem is OperationTelemetry && + telemetryProp != null && + !telemetryProp.Properties.ContainsKey(TracestatePropertyKey)) { - // Set OperationID to Activity.TraceId - // itemOperationContext.Id = currentActivity.RootId; // check if this can be used - itemOperationContext.Id = currentActivity.TraceId.ToHexString(); - - // Set OperationParentID to ID of parent, constructed as !traceid.spanid. - // ID for auto collected Request,Dependency are constructed as !traceid.spanid, so parentid must be set to the same format. - // While it is possible to set SpanID as the ID for auto collected Request,Dependency we have to stick to this format - // to maintain compatibility. This limitation may go away in the future. - if (string.IsNullOrEmpty(itemOperationContext.ParentId)) - { - itemOperationContext.ParentId = W3CUtilities.FormatTelemetryId(itemOperationContext.Id, currentActivity.SpanId.ToHexString()); - } + telemetryProp.Properties.Add(TracestatePropertyKey, currentActivity.TraceStateString); + } - // we are going to set tracestate property on requests and dependencies only - if (!string.IsNullOrEmpty(currentActivity.TraceStateString) && - telemetryItem is OperationTelemetry && - telemetryProp != null && - !telemetryProp.Properties.ContainsKey(TracestatePropertyKey)) - { - telemetryProp.Properties.Add(TracestatePropertyKey, currentActivity.TraceStateString); - } + // update proactive sampling decision if Activity is recorded + // sampling processor may change the decision + if (currentActivity.Recorded && + telemetryItem is ISupportAdvancedSampling supportSamplingTelemetry && + supportSamplingTelemetry.ProactiveSamplingDecision == SamplingDecision.None) + { + supportSamplingTelemetry.ProactiveSamplingDecision = SamplingDecision.SampledIn; } - else + + if (string.IsNullOrEmpty(itemOperationContext.Id)) { - itemOperationContext.Id = currentActivity.RootId; + if (currentActivity.IdFormat == ActivityIdFormat.W3C) + { + // Set OperationID to Activity.TraceId + // itemOperationContext.Id = currentActivity.RootId; // check if this can be used + itemOperationContext.Id = currentActivity.TraceId.ToHexString(); - if (string.IsNullOrEmpty(itemOperationContext.ParentId)) + // Set OperationParentID to ID of parent, constructed as !traceid.spanid. + // ID for auto collected Request,Dependency are constructed as !traceid.spanid, so parentid must be set to the same format. + // While it is possible to set SpanID as the ID for auto collected Request,Dependency we have to stick to this format + // to maintain compatibility. This limitation may go away in the future. + if (string.IsNullOrEmpty(itemOperationContext.ParentId)) + { + itemOperationContext.ParentId = W3CUtilities.FormatTelemetryId(itemOperationContext.Id, + currentActivity.SpanId.ToHexString()); + } + } + else { - itemOperationContext.ParentId = currentActivity.Id; + itemOperationContext.Id = currentActivity.RootId; + + if (string.IsNullOrEmpty(itemOperationContext.ParentId)) + { + itemOperationContext.ParentId = currentActivity.Id; + } } - } - foreach (var baggage in currentActivity.Baggage) - { - if (telemetryProp != null && !telemetryProp.Properties.ContainsKey(baggage.Key)) + foreach (var baggage in currentActivity.Baggage) { - telemetryProp.Properties.Add(baggage); + if (telemetryProp != null && !telemetryProp.Properties.ContainsKey(baggage.Key)) + { + telemetryProp.Properties.Add(baggage); + } } - } - if (string.IsNullOrEmpty(itemOperationContext.Name)) - { - string operationName = currentActivity.GetOperationName(); - if (!string.IsNullOrEmpty(operationName)) + if (string.IsNullOrEmpty(itemOperationContext.Name)) { - itemOperationContext.Name = operationName; + string operationName = currentActivity.GetOperationName(); + if (!string.IsNullOrEmpty(operationName)) + { + itemOperationContext.Name = operationName; + } } } - - if (currentActivity.Recorded && - telemetryItem is ISupportAdvancedSampling supportSamplingTelemetry && - supportSamplingTelemetry.ProactiveSamplingDecision == SamplingDecision.None) - { - supportSamplingTelemetry.ProactiveSamplingDecision = SamplingDecision.SampledIn; - } } });