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); }
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)); }
public IDisposable BeginScope <TState>(TState state) { if (state == null) { throw new ArgumentNullException(nameof(state)); } StartTelemetryIfFunctionInvocation(state as IDictionary <string, object>); return(DictionaryLoggerScope.Push(state)); }
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; } } }
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(); } } }
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()); }
public static IDisposable Push(object state) { Current = new DictionaryLoggerScope(state, Current); return(new DisposableScope()); }
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; } } } } }
private DictionaryLoggerScope(IReadOnlyDictionary <string, object> state, DictionaryLoggerScope parent) { State = state; Parent = parent; }