internal object OnBegin()

in WEB/Src/DependencyCollector/DependencyCollector/Implementation/HttpProcessing.cs [82:264]


        internal object OnBegin(object thisObj, bool injectCorrelationHeaders = true)
        {
            try
            {
                if (thisObj == null)
                {
                    DependencyCollectorEventSource.Log.NotExpectedCallback(0, "OnBeginHttp", "thisObj == null");
                    return null;
                }

                WebRequest webRequest = thisObj as WebRequest;
                if (webRequest == null)
                {
                    DependencyCollectorEventSource.Log.UnexpectedCallbackParameter("WebRequest");
                }

                var url = GetUrl(webRequest);
                if (url == null)
                {
                    DependencyCollectorEventSource.Log.NotExpectedCallback(thisObj.GetHashCode(), "OnBeginHttp",
                        "resourceName is empty");
                    return null;
                }

                string httpMethod = webRequest.Method;
                string resourceName = url.AbsolutePath;

                if (!string.IsNullOrEmpty(httpMethod))
                {
                    resourceName = httpMethod + " " + resourceName;
                }

                DependencyCollectorEventSource.Log.BeginCallbackCalled(thisObj.GetHashCode(), resourceName);

                if (this.applicationInsightsUrlFilter.IsApplicationInsightsUrl(url))
                {
                    // Not logging as we will be logging for all outbound AI calls
                    return null;
                }

                if (webRequest.Headers[W3C.W3CConstants.TraceParentHeader] != null && Activity.DefaultIdFormat == ActivityIdFormat.W3C)
                {
                    DependencyCollectorEventSource.Log.HttpRequestAlreadyInstrumented();
                    return null;
                }

                // If the object already exists, don't add again. This happens because either GetResponse or GetRequestStream could
                // be the starting point for the outbound call.
                DependencyTelemetry telemetry = null;
                var telemetryTuple = this.GetTupleForWebDependencies(webRequest);
                if (telemetryTuple?.Item1 != null)
                {
                    DependencyCollectorEventSource.Log.TrackingAnExistingTelemetryItemVerbose();
                    return null;
                }

                // Create and initialize a new telemetry object
                telemetry = ClientServerDependencyTracker.BeginTracking(this.telemetryClient);

                this.AddTupleForWebDependencies(webRequest, telemetry, false);

                if (string.IsNullOrEmpty(telemetry.Context.InstrumentationKey))
                {
                    // Instrumentation key is probably empty, because the context has not yet had a chance to associate the requestTelemetry to the telemetry client yet.
                    // and get they instrumentation key from all possible sources in the process. Let's do that now.
                    this.telemetryClient.InitializeInstrumentationKey(telemetry);
                }

                telemetry.Name = resourceName;
                telemetry.Target = DependencyTargetNameHelper.GetDependencyTargetName(url);
                telemetry.Type = RemoteDependencyConstants.HTTP;
                telemetry.Data = url.OriginalString;
                telemetry.SetOperationDetail(OperationDetailConstants.HttpRequestOperationDetailName, webRequest);

                Activity currentActivity = Activity.Current;
                // Add the source instrumentation key header if collection is enabled, the request host is not in the excluded list and the same header doesn't already exist
                if (this.setCorrelationHeaders && !this.correlationDomainExclusionList.Contains(url.Host))
                {
                    string applicationId = null;
                    try
                    {
                        if (!string.IsNullOrEmpty(telemetry.Context.InstrumentationKey)
                            && webRequest.Headers.GetNameValueHeaderValue(RequestResponseHeaders.RequestContextHeader,
                                RequestResponseHeaders.RequestContextCorrelationSourceKey) == null
                            && (this.configuration.ApplicationIdProvider?.TryGetApplicationId(
                                    telemetry.Context.InstrumentationKey, out applicationId) ?? false))
                        {
                            webRequest.Headers.SetNameValueHeaderValue(RequestResponseHeaders.RequestContextHeader,
                                RequestResponseHeaders.RequestContextCorrelationSourceKey, applicationId);
                        }
                    }
                    catch (Exception ex)
                    {
                        AppMapCorrelationEventSource.Log.SetCrossComponentCorrelationHeaderFailed(
                            ex.ToInvariantString());
                    }

                    if (this.injectLegacyHeaders)
                    {
                        // Add the root ID
                        var rootId = telemetry.Context.Operation.Id;
                        if (!string.IsNullOrEmpty(rootId) &&
                            webRequest.Headers[RequestResponseHeaders.StandardRootIdHeader] == null)
                        {
                            webRequest.Headers.Add(RequestResponseHeaders.StandardRootIdHeader, rootId);
                        }

                        // Add the parent ID
                        var parentId = telemetry.Id;
                        if (!string.IsNullOrEmpty(parentId))
                        {
                            if (webRequest.Headers[RequestResponseHeaders.StandardParentIdHeader] == null)
                            {
                                webRequest.Headers.Add(RequestResponseHeaders.StandardParentIdHeader, parentId);
                            }
                        }
                    }

                    if (currentActivity != null)
                    {
                        // ApplicationInsights only needs to inject W3C, potentially Request-Id and Correlation-Context
                        // headers for profiler instrumentation.
                        // in case of Http Desktop DiagnosticSourceListener they are injected in
                        // DiagnosticSource (with the System.Net.Http.Desktop.HttpRequestOut.Start event)
                        if (injectCorrelationHeaders)
                        {
                            if (currentActivity.IdFormat == ActivityIdFormat.W3C)
                            {
                                if (webRequest.Headers[W3C.W3CConstants.TraceParentHeader] == null)
                                {
                                    webRequest.Headers.Add(W3C.W3CConstants.TraceParentHeader, currentActivity.Id);
                                }

                                if (webRequest.Headers[W3C.W3CConstants.TraceStateHeader] == null &&
                                    !string.IsNullOrEmpty(currentActivity.TraceStateString))
                                {
                                    webRequest.Headers.Add(W3C.W3CConstants.TraceStateHeader,
                                        currentActivity.TraceStateString);
                                }
                            }
                            else
                            {
                                // Request-Id format
                                if (webRequest.Headers[RequestResponseHeaders.RequestIdHeader] == null)
                                {
                                    webRequest.Headers.Add(RequestResponseHeaders.RequestIdHeader, telemetry.Id);
                                }
                            }

                            InjectCorrelationContext(webRequest.Headers, currentActivity);
                        }
                    }
                }

                // Active bug in .NET Fx diagnostics hook: https://github.com/dotnet/corefx/pull/40777
                // Application Insights has to inject Request-Id to work it around
                if (currentActivity?.IdFormat == ActivityIdFormat.W3C)
                {
                    // if (this.injectRequestIdInW3CMode)
                    {
                        if (webRequest.Headers[RequestResponseHeaders.RequestIdHeader] == null)
                        {
                            webRequest.Headers.Add(RequestResponseHeaders.RequestIdHeader, string.Concat('|', telemetry.Context.Operation.Id, '.', telemetry.Id, '.'));
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                DependencyCollectorEventSource.Log.CallbackError(thisObj == null ? 0 : thisObj.GetHashCode(),
                    "OnBeginHttp", exception);
            }
            finally
            {
                Activity current = Activity.Current;
                if (current?.OperationName == ClientServerDependencyTracker.DependencyActivityName)
                {
                    current.Stop();
                }
            }

            return null;
        }