Esempio n. 1
0
        /// <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    = ActivityShim.Current;
                ActivityShim newActivity        = default;
                string       originalParentId   = currentActivity.ParentId;
                string       legacyRootId       = null;
                bool         traceParentPresent = false;
                var          headers            = httpContext.Request.Headers;

                // 3 possibilities when TelemetryConfiguration.EnableW3CCorrelation = true
                // 1. No incoming headers. originalParentId will be null. Simply use the Activity as such.
                // 2. Incoming Request-ID Headers. originalParentId will be request-id, but Activity ignores this for ID calculations.
                //    If incoming ID is W3C compatible, ignore current Activity. Create new one with parent set to incoming W3C compatible rootid.
                //    If incoming ID is not W3C compatible, we can use Activity as such, but need to store originalParentID in custom property 'legacyRootId'
                // 3. Incoming TraceParent header.
                //    3a - 2.XX Need to ignore current Activity, and create new from incoming W3C TraceParent header.
                //    3b - 3.XX Use Activity as such because 3.XX is W3C Aware.

                // Another 3 possibilities when TelemetryConfiguration.EnableW3CCorrelation = false
                // 1. No incoming headers. originalParentId will be null. Simply use the Activity as such.
                // 2. Incoming Request-ID Headers. originalParentId will be request-id, Activity uses this for ID calculations.
                // 3. Incoming TraceParent header. Will simply Ignore W3C headers, and Current Activity used as such.

                // Attempt to find parent from incoming W3C Headers which 2.XX Hosting is unaware of.
                if (this.aspNetCoreMajorVersion != AspNetCoreMajorVersion.Three &&
                    currentActivity.IdFormat == ActivityIdFormat.W3C &&
                    headers.TryGetValue(W3CConstants.TraceParentHeader, out StringValues traceParentValues) &&
                    traceParentValues != StringValues.Empty)
                {
                    var parentTraceParent = StringUtilities.EnforceMaxLength(
                        traceParentValues.First(),
                        InjectionGuardConstants.TraceParentHeaderMaxLength);
                    originalParentId   = parentTraceParent;
                    traceParentPresent = true;
                    // AspNetCoreEventSource.Instance.HostingListenerInformational(this.aspNetCoreMajorVersion, "Retrieved trace parent from headers.");
                }

                // Scenario #1. No incoming correlation headers.
                if (originalParentId == null)
                {
                    // Nothing to do here.
                    // AspNetCoreEventSource.Instance.HostingListenerInformational(this.aspNetCoreMajorVersion, "OriginalParentId is null.");
                }
                else if (traceParentPresent)
                {
                    // Scenario #3. W3C-TraceParent
                    // We need to ignore the Activity created by Hosting, as it did not take W3CTraceParent into consideration.
                    newActivity = new ActivityShim(ActivityCreatedByHostingDiagnosticListener);
                    newActivity.SetParentId(originalParentId);
                    // AspNetCoreEventSource.Instance.HostingListenerInformational(this.aspNetCoreMajorVersion, "Ignoring original Activity from Hosting to create new one using traceparent header retrieved by sdk.");

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

                    // scenario #3b Use Activity created by Hosting layer when W3C Headers Present.
                    // but ignore parent if user disabled w3c.
                    if (currentActivity.IdFormat != ActivityIdFormat.W3C)
                    {
                        originalParentId = null;
                    }
                }
                else
                {
                    // Scenario #2. RequestID
                    if (currentActivity.IdFormat == ActivityIdFormat.W3C)
                    {
                        if (TryGetW3CCompatibleTraceId(originalParentId, out var traceId))
                        {
                            newActivity = new ActivityShim(ActivityCreatedByHostingDiagnosticListener);
                            newActivity.SetParentId(ActivityTraceId.CreateFromString(traceId), default(ActivitySpanId), ActivityTraceFlags.None);
                            // AspNetCoreEventSource.Instance.HostingListenerInformational(this.aspNetCoreMajorVersion, "Ignoring original Activity from Hosting to create new one using w3c compatible request-id.");

                            foreach (var bag in currentActivity.Baggage)
                            {
                                newActivity.AddBaggage(bag.Key, bag.Value);
                            }
                        }
                        else
                        {
                            // store rootIdFromOriginalParentId in custom Property
                            legacyRootId = ExtractOperationIdFromRequestId(originalParentId);
                            // AspNetCoreEventSource.Instance.HostingListenerInformational(this.aspNetCoreMajorVersion, "Incoming Request-ID is not W3C Compatible, and hence will be ignored for ID generation, but stored in custom property legacy_rootID.");
                        }
                    }
                }

                if (!newActivity.IsDefault)
                {
                    newActivity.Start();
                    currentActivity = newActivity;
                }

                // Read Correlation-Context is all scenarios irrespective of presence of either request-id or traceparent headers.
                ReadCorrelationContext(httpContext.Request.Headers, currentActivity);

                var requestTelemetry = this.InitializeRequestTelemetry(httpContext, currentActivity, Stopwatch.GetTimestamp(), legacyRootId);

                requestTelemetry.Context.Operation.ParentId =
                    GetParentId(currentActivity, originalParentId, requestTelemetry.Context.Operation.Id);

                this.AddAppIdToResponseIfRequired(httpContext, requestTelemetry);
            }
        }