public void Initialize(ITelemetry telemetry)
        {
            if (telemetry == null)
            {
                return;
            }

            telemetry.Context.Cloud.RoleInstance = _roleInstanceName;

            // Zero out all IP addresses other than Requests
            if (!(telemetry is RequestTelemetry))
            {
                telemetry.Context.Location.Ip = LoggingConstants.ZeroIpAddress;
            }

            // Apply our special scope properties
            IDictionary <string, object> scopeProps = DictionaryLoggerScope.GetMergedStateDictionary() ?? new Dictionary <string, object>();

            Guid invocationId = scopeProps.GetValueOrDefault <Guid>(ScopeKeys.FunctionInvocationId);

            if (invocationId != default(Guid))
            {
                telemetry.Context.Operation.Id = invocationId.ToString();
            }

            telemetry.Context.Operation.Name = scopeProps.GetValueOrDefault <string>(ScopeKeys.FunctionName);
        }
Exemple #2
0
        private void LogFunctionResult(IEnumerable <KeyValuePair <string, object> > state, LogLevel logLevel, Exception exception)
        {
            IDictionary <string, object> scopeProps = DictionaryLoggerScope.GetMergedStateDictionary() ?? new Dictionary <string, object>();

            // log associated exception details
            KeyValuePair <string, object>[] stateProps = state as KeyValuePair <string, object>[] ?? state.ToArray();
            if (exception != null)
            {
                LogException(logLevel, stateProps, exception, null);
            }

            ApplyFunctionResultActivityTags(stateProps, scopeProps);

            IOperationHolder <RequestTelemetry> requestOperation = scopeProps.GetValueOrDefault <IOperationHolder <RequestTelemetry> >(OperationContext);

            if (requestOperation != null)
            {
                // We somehow never started the operation, perhaps, it was auto-tracked by the AI SDK
                // so there's no way to complete it.

                RequestTelemetry requestTelemetry = requestOperation.Telemetry;
                requestTelemetry.Success      = exception == null;
                requestTelemetry.ResponseCode = "0";

                // Note: we do not have to set Duration, StartTime, etc. These are handled by the call to Stop()
                _telemetryClient.StopOperation(requestOperation);
            }
        }
        // Applies custom scope properties; does not apply 'system' used properties
        private static void ApplyCustomScopeProperties(ISupportProperties telemetry)
        {
            var scopeProperties = DictionaryLoggerScope.GetMergedStateDictionary()
                                  .Where(p => !SystemScopeKeys.Contains(p.Key, StringComparer.Ordinal));

            ApplyProperties(telemetry, scopeProperties, LogConstants.CustomPropertyPrefix);
        }
        private void LogFunctionResult(IEnumerable <KeyValuePair <string, object> > values, Exception exception)
        {
            IDictionary <string, object> scopeProps = DictionaryLoggerScope.GetMergedStateDictionary() ?? new Dictionary <string, object>();

            RequestTelemetry requestTelemetry = new RequestTelemetry();

            requestTelemetry.Success      = exception == null;
            requestTelemetry.ResponseCode = "0";

            // Set ip address to zeroes. If we find HttpRequest details below, we will update this
            requestTelemetry.Context.Location.Ip = LoggingConstants.ZeroIpAddress;

            ApplyFunctionResultProperties(requestTelemetry, values);

            // Functions attaches the HttpRequest, which allows us to log richer request details.
            object request;

            if (scopeProps.TryGetValue(ApplicationInsightsScopeKeys.HttpRequest, out request))
            {
                ApplyHttpRequestProperties(requestTelemetry, request as HttpRequestMessage);
            }

            // log associated exception details
            if (exception != null)
            {
                ExceptionTelemetry exceptionTelemetry = new ExceptionTelemetry(exception);
                _telemetryClient.TrackException(exceptionTelemetry);
            }

            _telemetryClient.TrackRequest(requestTelemetry);
        }
        private void LogFunctionResult(IEnumerable <KeyValuePair <string, object> > values, LogLevel logLevel, Exception exception)
        {
            IDictionary <string, object> scopeProps = DictionaryLoggerScope.GetMergedStateDictionary() ?? new Dictionary <string, object>();

            RequestTelemetry requestTelemetry = scopeProps.GetValueOrDefault <RequestTelemetry>(OperationContext);

            // We somehow never started the operation, so there's no way to complete it.
            if (requestTelemetry == null)
            {
                throw new InvalidOperationException("No started telemetry was found.");
            }

            requestTelemetry.Success      = exception == null;
            requestTelemetry.ResponseCode = "0";

            // Set ip address to zeroes. If we find HttpRequest details below, we will update this
            requestTelemetry.Context.Location.Ip = LoggingConstants.ZeroIpAddress;

            ApplyFunctionResultProperties(requestTelemetry, values);

            // log associated exception details
            if (exception != null)
            {
                LogException(logLevel, values, exception, null);
            }

            // Note: we do not have to set Duration, StartTime, etc. These are handled by the call to Stop()
            requestTelemetry.Stop();
            _telemetryClient.TrackRequest(requestTelemetry);
        }
        public IDisposable BeginScope <TState>(TState state)
        {
            if (state == null)
            {
                throw new ArgumentNullException(nameof(state));
            }

            return(DictionaryLoggerScope.Push(state));
        }
Exemple #7
0
        public IDisposable BeginScope <TState>(TState state)
        {
            if (state == null)
            {
                throw new ArgumentNullException(nameof(state));
            }

            StartTelemetryIfFunctionInvocation(state as IDictionary <string, object>);

            return(DictionaryLoggerScope.Push(state));
        }
Exemple #8
0
        private void StartTelemetryIfFunctionInvocation(IDictionary <string, object> stateValues)
        {
            if (stateValues == null)
            {
                return;
            }

            // 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:
                DictionaryLoggerScope.GetMergedStateDictionary().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)
                {
                    RequestTelemetry request = new RequestTelemetry
                    {
                        Name = functionName
                    };

                    // We'll need to store this operation context so we can stop it when the function completes
                    IOperationHolder <RequestTelemetry> operation = _telemetryClient.StartOperation(request);

                    if (_loggerOptions.HttpAutoCollectionOptions.EnableW3CDistributedTracing)
                    {
                        // currently ApplicationInsights supports 2 parallel correlation schemes:
                        // legacy and W3C, they both appear in telemetry. UX handles all differences in operation Ids.
                        // This will be resolved in next .NET SDK on Activity level.
                        // This ensures W3C context is set on the Activity.
                        Activity.Current?.GenerateW3CContext();
                    }

                    stateValues[OperationContext] = operation;
                }
            }
        }
Exemple #9
0
        public void Initialize(ITelemetry telemetry)
        {
            if (telemetry == null)
            {
                return;
            }

            telemetry.Context.Cloud.RoleInstance = _roleInstanceName;

            // Zero out all IP addresses other than Requests
            if (!(telemetry is RequestTelemetry))
            {
                telemetry.Context.Location.Ip = LoggingConstants.ZeroIpAddress;
            }

            // Apply our special scope properties
            IDictionary <string, object> scopeProps = DictionaryLoggerScope.GetMergedStateDictionary() ?? new Dictionary <string, object>();

            telemetry.Context.Operation.Id   = scopeProps.GetValueOrDefault <string>(ScopeKeys.FunctionInvocationId);
            telemetry.Context.Operation.Name = scopeProps.GetValueOrDefault <string>(ScopeKeys.FunctionName);

            // Apply Category and LogLevel to all telemetry
            if (telemetry is ISupportProperties telemetryProps)
            {
                string category = scopeProps.GetValueOrDefault <string>(LogConstants.CategoryNameKey);
                if (category != null)
                {
                    telemetryProps.Properties[LogConstants.CategoryNameKey] = category;
                }

                LogLevel?logLevel = scopeProps.GetValueOrDefault <LogLevel?>(LogConstants.LogLevelKey);
                if (logLevel != null)
                {
                    telemetryProps.Properties[LogConstants.LogLevelKey] = logLevel.Value.ToString();
                }

                int?eventId = scopeProps.GetValueOrDefault <int?>(LogConstants.EventIdKey);
                if (eventId != null && eventId.HasValue && eventId.Value != 0)
                {
                    telemetryProps.Properties[LogConstants.EventIdKey] = eventId.Value.ToString();
                }
            }
        }
Exemple #10
0
        public static IDisposable Push(object state)
        {
            IDictionary <string, object> stateValues;

            if (state is IEnumerable <KeyValuePair <string, object> > stateEnum)
            {
                // Convert this to a dictionary as we have scenarios where we cannot have duplicates. In this
                // case, if there are dupes, the later entry wins.
                stateValues = new Dictionary <string, object>();
                foreach (var entry in stateEnum)
                {
                    stateValues[entry.Key] = entry.Value;
                }
            }
            else
            {
                // There's nothing we can do with other states.
                return(null);
            }

            Current = new DictionaryLoggerScope(new ReadOnlyDictionary <string, object>(stateValues), Current);
            return(new DisposableScope());
        }
Exemple #11
0
 public static IDisposable Push(object state)
 {
     Current = new DictionaryLoggerScope(state, Current);
     return(new DisposableScope());
 }
Exemple #12
0
 private DictionaryLoggerScope(object state, DictionaryLoggerScope parent)
 {
     _state = state;
     Parent = parent;
 }
        public void Initialize(ITelemetry telemetry)
        {
            if (telemetry == null)
            {
                return;
            }

            telemetry.Context.Cloud.RoleInstance = _roleInstanceName;

            RequestTelemetry request = telemetry as RequestTelemetry;

            // Zero out all IP addresses other than Requests
            if (request == null)
            {
                telemetry.Context.Location.Ip = LoggingConstants.ZeroIpAddress;
            }
            else
            {
                if (request.Context.Location.Ip == null)
                {
                    request.Context.Location.Ip = LoggingConstants.ZeroIpAddress;
                }
            }

            IDictionary <string, string> telemetryProps = telemetry.Context.Properties;

            // Apply our special scope properties
            IDictionary <string, object> scopeProps =
                DictionaryLoggerScope.GetMergedStateDictionary() ?? new Dictionary <string, object>();

            string invocationId = scopeProps.GetValueOrDefault <string>(ScopeKeys.FunctionInvocationId);

            if (invocationId != null)
            {
                telemetryProps[LogConstants.InvocationIdKey] = invocationId;
            }

            // this could be telemetry tracked in scope of function call - then we should apply the logger scope
            // or RequestTelemetry tracked by the WebJobs SDK or AppInsight SDK - then we should apply Activity.Tags
            if (request == null && scopeProps.Any())
            {
                telemetry.Context.Operation.Name = scopeProps.GetValueOrDefault <string>(ScopeKeys.FunctionName);

                // Apply Category and LogLevel to all telemetry
                string category = scopeProps.GetValueOrDefault <string>(LogConstants.CategoryNameKey);
                if (category != null)
                {
                    telemetryProps[LogConstants.CategoryNameKey] = category;
                }

                LogLevel?logLevel = scopeProps.GetValueOrDefault <LogLevel?>(LogConstants.LogLevelKey);
                if (logLevel != null)
                {
                    telemetryProps[LogConstants.LogLevelKey] = logLevel.Value.ToString();
                }

                int?eventId = scopeProps.GetValueOrDefault <int?>(LogConstants.EventIdKey);
                if (eventId != null && eventId.HasValue && eventId.Value != 0)
                {
                    telemetryProps[LogConstants.EventIdKey] = eventId.Value.ToString();
                }
            }
            // we may track traces/dependencies after function scope ends - we don't want to update those
            else if (request != null)
            {
                Activity currentActivity = Activity.Current;
                if (currentActivity != null) // should never be null, but we don't want to throw anyway
                {
                    // tags is a list, we'll enumerate it
                    foreach (var tag in currentActivity.Tags)
                    {
                        switch (tag.Key)
                        {
                        case LogConstants.NameKey:
                            request.Context.Operation.Name = tag.Value;
                            request.Name = tag.Value;
                            break;

                        default:
                            request.Properties[tag.Key] = tag.Value;
                            break;
                        }
                    }
                }
                else // workaround for https://github.com/Microsoft/ApplicationInsights-dotnet-server/issues/1038
                {
                    if (request.Properties.TryGetValue(LogConstants.NameKey, out var functionName))
                    {
                        request.Context.Operation.Name = functionName;
                        request.Name = functionName;
                    }
                }
            }
        }
        public void Initialize(ITelemetry telemetry)
        {
            if (telemetry == null)
            {
                return;
            }

            telemetry.Context.Cloud.RoleInstance = _roleInstanceName;

            RequestTelemetry request = telemetry as RequestTelemetry;

            // Zero out all IP addresses other than Requests
            if (request == null)
            {
                telemetry.Context.Location.Ip = LoggingConstants.ZeroIpAddress;
            }
            else
            {
                if (request.Context.Location.Ip == null)
                {
                    request.Context.Location.Ip = LoggingConstants.ZeroIpAddress;
                }
            }

            IDictionary <string, string> telemetryProps = telemetry.Context.Properties;

            // Apply our special scope properties
            IDictionary <string, object> scopeProps =
                DictionaryLoggerScope.GetMergedStateDictionary() ?? new Dictionary <string, object>();

            string invocationId = scopeProps.GetValueOrDefault <string>(ScopeKeys.FunctionInvocationId);

            if (invocationId != null)
            {
                telemetryProps[LogConstants.InvocationIdKey] = invocationId;
            }

            // this could be telemetry tracked in scope of function call - then we should apply the logger scope
            // or RequestTelemetry tracked by the WebJobs SDK or AppInsight SDK - then we should apply Activity.Tags
            if (request == null && scopeProps.Any())
            {
                telemetry.Context.Operation.Name = scopeProps.GetValueOrDefault <string>(ScopeKeys.FunctionName);

                // Apply Category and LogLevel to all telemetry
                string category = scopeProps.GetValueOrDefault <string>(LogConstants.CategoryNameKey);
                if (category != null)
                {
                    telemetryProps[LogConstants.CategoryNameKey] = category;
                }

                LogLevel?logLevel = scopeProps.GetValueOrDefault <LogLevel?>(LogConstants.LogLevelKey);
                if (logLevel != null)
                {
                    telemetryProps[LogConstants.LogLevelKey] = logLevel.Value.ToString();
                }

                int?eventId = scopeProps.GetValueOrDefault <int?>(LogConstants.EventIdKey);
                if (eventId != null && eventId.HasValue && eventId.Value != 0)
                {
                    telemetryProps[LogConstants.EventIdKey] = eventId.Value.ToString();
                }
            }
            // we may track traces/dependencies after function scope ends - we don't want to update those
            else if (request != null)
            {
                UpdateRequestProperties(request);

                Activity currentActivity = Activity.Current;
                if (currentActivity != null)
                {
                    foreach (var tag in currentActivity.Tags)
                    {
                        // Apply well-known tags and custom properties,
                        // but ignore internal ai tags
                        if (!TryApplyProperty(request, tag) &&
                            !tag.Key.StartsWith("w3c_") &&
                            !tag.Key.StartsWith("ai_"))
                        {
                            request.Properties[tag.Key] = tag.Value;
                        }
                    }
                }
            }
        }
Exemple #15
0
 private DictionaryLoggerScope(IReadOnlyDictionary <string, object> state, DictionaryLoggerScope parent)
 {
     State  = state;
     Parent = parent;
 }