private void StartTelemetryIfFunctionInvocation()

in src/Microsoft.Azure.WebJobs.Logging.ApplicationInsights/ApplicationInsightsLogger.cs [496:591]


        private void StartTelemetryIfFunctionInvocation(IDictionary<string, object> stateValues)
        {
            if (stateValues == null)
            {
                return;
            }

            var allScopes = DictionaryLoggerScope.GetMergedStateDictionaryOrNull();
            // HTTP and ServiceBus triggers are tracked automatically by the ApplicationInsights SDK
            // In such case a current Activity is present.
            // We won't track and only stamp function specific details on the RequestTelemetry
            // created by SDK via Activity when function ends

            var currentActivity = Activity.Current;
            if (currentActivity == null ||
                // Activity is tracked, but Functions wants to ignore it:
                (allScopes != null && allScopes.ContainsKey("MS_IgnoreActivity")) ||
                // Functions create another RequestTrackingTelemetryModule to make sure first request is tracked (as ASP.NET Core starts before web jobs)
                // however at this point we may discover that RequestTrackingTelemetryModule is disabled by customer and even though Activity exists, request won't be tracked
                // So, if we've got AspNetCore Activity and EnableHttpTriggerExtendedInfoCollection is false - track request here.
                (!_loggerOptions.HttpAutoCollectionOptions.EnableHttpTriggerExtendedInfoCollection && IsHttpRequestActivity(currentActivity)))
            {
                string functionName = stateValues.GetValueOrDefault<string>(ScopeKeys.FunctionName);
                string functionInvocationId = stateValues.GetValueOrDefault<string>(ScopeKeys.FunctionInvocationId);
                string eventName = stateValues.GetValueOrDefault<string>(ScopeKeys.Event);

                // If we have the invocation id, function name, and event, we know it's a new function. That means
                // that we want to start a new operation and let App Insights track it for us.
                if (!string.IsNullOrEmpty(functionName) &&
                    !string.IsNullOrEmpty(functionInvocationId) &&
                    eventName == LogConstants.FunctionStartEvent)
                {
                    IOperationHolder<RequestTelemetry> operation;

                    // link represents context from the upstream service that is not necessarily immediate parent
                    // it is used by EventHubs to represent context in the message.
                    // if there is just one link, we'll use it as a parent as an optimization.
                    // if there is more than one, we'll populate them as custom properties
                    IEnumerable<Activity> links = allScopes?.GetValueOrDefault<IEnumerable<Activity>>("Links");
                    var activities = links as Activity[] ?? links?.ToArray();

                    if (activities != null)
                    {
                        if (activities.Length == 1)
                        {
                            operation = _telemetryClient.StartOperation<RequestTelemetry>(activities[0]);
                            operation.Telemetry.Name = functionName;
                        }
                        else
                        {
                            operation = CreateRequestFromLinks(activities, functionName);
                        }

                        if (this.TryGetAverageTimeInQueueForBatch(activities, operation.Telemetry.Timestamp, out long enqueuedTime))
                        {
                            operation.Telemetry.Metrics["timeSinceEnqueued"] = enqueuedTime;
                        }
                    }
                    else
                    {
                        operation = _telemetryClient.StartOperation<RequestTelemetry>(functionName);
                    }

                    var triggerDetails = stateValues.GetValueOrDefault<IDictionary<string, string>>(ScopeKeys.TriggerDetails);
                    if (triggerDetails != null)
                    {
                        triggerDetails.TryGetValue(LogConstants.TriggerDetailsEndpointKey, out var endpoint);
                        triggerDetails.TryGetValue(LogConstants.TriggerDetailsEntityNameKey, out var entity);

                        if (endpoint != null && entity != null)
                        {
                            operation.Telemetry.Source = endpoint.EndsWith("/") ? string.Concat(endpoint, entity) : string.Concat(endpoint, "/", entity);
                        }
                        else if (endpoint != null)
                        {
                            operation.Telemetry.Source = endpoint;
                        }
                        else if (entity != null)
                        {
                            operation.Telemetry.Source = entity;
                        }
                    }

                    // We'll need to store this operation context so we can stop it when the function completes
                    stateValues[OperationContext] = operation;
                }
            }
            // If there is a current activity, it is assumed that Application Insights will track it so we do not start an operation.
            // However, in some cases (such as Durable functions), this is not the case. This allows the scope to decide whether
            // an operation should be started, even when the current activity is not null.
            else if (allScopes != null && allScopes.ContainsKey("MS_TrackActivity"))
            {
                var operation = _telemetryClient.StartOperation<RequestTelemetry>(currentActivity);
                stateValues[OperationContext] = operation;
            }
        }