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
        }
Пример #3
0
        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);
        }
Пример #5
0
        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);
        }
Пример #8
0
 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));
        }
Пример #11
0
        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;
            }
        }
Пример #12
0
        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);
        }
Пример #14
0
        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));
        }
Пример #15
0
        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);
        }
Пример #17
0
        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();
        }
Пример #18
0
        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();
        }
Пример #19
0
        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");
            }
        }
Пример #21
0
        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);
        }
Пример #23
0
        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));
            }
        }
Пример #24
0
        //// 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));
        }