diff --git a/CHANGELOG.md b/CHANGELOG.md index cd75134dde..bf13d60fde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## VNext - [ILogger LogError and LogWarning variants write exception `ExceptionStackTrace` when `TrackExceptionsAsExceptionTelemetry` flag is set to `false`](https://github.com/microsoft/ApplicationInsights-dotnet/pull/2065) - [The `{OriginalFormat}` field in ILogger will be emitted as `OriginalFormat` with the braces removed](https://github.com/microsoft/ApplicationInsights-dotnet/pull/2071) +- ApplicationInsightsLoggerProvider populates structured logging key/values irrespective of whether Scopes are enabled or not. ## Version 2.15.0 - EventCounterCollector module does not add AggregationInterval as a dimension to the metric. diff --git a/LOGGING/src/ILogger/ApplicationInsightsLogger.cs b/LOGGING/src/ILogger/ApplicationInsightsLogger.cs index 2767dc7b5c..dfbb0d44b5 100644 --- a/LOGGING/src/ILogger/ApplicationInsightsLogger.cs +++ b/LOGGING/src/ILogger/ApplicationInsightsLogger.cs @@ -1,6 +1,6 @@ // ----------------------------------------------------------------------- // -// Copyright (c) Microsoft Corporation. +// Copyright (c) Microsoft Corporation. // All rights reserved. 2013 // // ----------------------------------------------------------------------- @@ -168,23 +168,23 @@ private void PopulateTelemetry(ISupportProperties telemetryItem, TState dict["EventName"] = eventId.Name; } - if (this.applicationInsightsLoggerOptions.IncludeScopes) + if (state is IReadOnlyCollection> stateDictionary) { - if (state is IReadOnlyCollection> stateDictionary) + foreach (KeyValuePair item in stateDictionary) { - foreach (KeyValuePair item in stateDictionary) + if (item.Key == "{OriginalFormat}") { - if (item.Key == "{OriginalFormat}") - { - dict["OriginalFormat"] = Convert.ToString(item.Value, CultureInfo.InvariantCulture); - } - else - { - dict[item.Key] = Convert.ToString(item.Value, CultureInfo.InvariantCulture); - } + dict["OriginalFormat"] = Convert.ToString(item.Value, CultureInfo.InvariantCulture); + } + else + { + dict[item.Key] = Convert.ToString(item.Value, CultureInfo.InvariantCulture); } } + } + if (this.applicationInsightsLoggerOptions.IncludeScopes) + { if (this.ExternalScopeProvider != null) { StringBuilder stringBuilder = new StringBuilder(); diff --git a/LOGGING/test/ILogger.Tests/ILoggerIntegrationTests.cs b/LOGGING/test/ILogger.Tests/ILoggerIntegrationTests.cs index 1a5918964c..72e1168a4b 100644 --- a/LOGGING/test/ILogger.Tests/ILoggerIntegrationTests.cs +++ b/LOGGING/test/ILogger.Tests/ILoggerIntegrationTests.cs @@ -23,6 +23,54 @@ namespace Microsoft.ApplicationInsights [TestClass] public class ILoggerIntegrationTests { + /// + /// Ensures that populates params for structured logging into custom properties . + /// + [TestMethod] + [TestCategory("ILogger")] + public void ApplicationInsightsLoggerPopulateStructureLoggingParamsIntoCustomProperties() + { + List itemsReceived = new List(); + + // Scopes are enabled. + IServiceProvider serviceProvider = ILoggerIntegrationTests.SetupApplicationInsightsLoggerIntegration( + (telemetryItem, telemetryProcessor) => itemsReceived.Add(telemetryItem), + configureTelemetryConfiguration: null, + configureApplicationInsightsOptions: (appInsightsLoggerOptions) => appInsightsLoggerOptions.IncludeScopes = true); + + ILogger testLogger = serviceProvider.GetRequiredService>(); + testLogger.LogInformation("Testing structured with {CustomerName} {Age}", "TestCustomerName", 20); + + Assert.AreEqual("Testing structured with TestCustomerName 20", (itemsReceived[0] as TraceTelemetry).Message); + var customProperties = (itemsReceived[0] as TraceTelemetry).Properties; + Assert.IsTrue(customProperties["CustomerName"].Equals("TestCustomerName")); + Assert.IsTrue(customProperties["Age"].Equals("20")); + } + + /// + /// Ensures that populates params for structured logging into custom properties . + /// + [TestMethod] + [TestCategory("ILogger")] + public void ApplicationInsightsLoggerPopulateStructureLoggingParamsIntoCustomPropertiesWhenScopeDisabled() + { + List itemsReceived = new List(); + + // Disable scope + IServiceProvider serviceProvider = ILoggerIntegrationTests.SetupApplicationInsightsLoggerIntegration( + (telemetryItem, telemetryProcessor) => itemsReceived.Add(telemetryItem), + configureTelemetryConfiguration: null, + configureApplicationInsightsOptions: (appInsightsLoggerOptions) => appInsightsLoggerOptions.IncludeScopes = false); + + ILogger testLogger = serviceProvider.GetRequiredService>(); + testLogger.LogInformation("Testing structured with {CustomerName} {Age}", "TestCustomerName", 20); + + Assert.AreEqual("Testing structured with TestCustomerName 20", (itemsReceived[0] as TraceTelemetry).Message); + var customProperties = (itemsReceived[0] as TraceTelemetry).Properties; + Assert.IsTrue(customProperties["CustomerName"].Equals("TestCustomerName")); + Assert.IsTrue(customProperties["Age"].Equals("20")); + } + /// /// Ensures that is invoked when user logs using . /// @@ -142,7 +190,7 @@ public void ApplicationInsightsLoggerLogsExceptionAsTraceWhenSwitchIsFalse() Assert.AreEqual(SeverityLevel.Error, (itemsReceived[1] as TraceTelemetry).SeverityLevel); Assert.AreEqual("LoggerMessage", (itemsReceived[1] as TraceTelemetry).Message); - + Assert.IsTrue((itemsReceived[1] as TraceTelemetry).Properties["ExceptionMessage"].Contains("StackTraceEnabled")); Assert.IsTrue((itemsReceived[1] as TraceTelemetry).Properties.ContainsKey("ExceptionStackTrace")); @@ -263,7 +311,7 @@ public void DefaultLoggerOptionsAreCorrectlyRegistered() IServiceProvider serviceProvider = ILoggerIntegrationTests.SetupApplicationInsightsLoggerIntegration( (telemetryItem, telemetryProcessor) => { }); - IOptions registeredOptions = + IOptions registeredOptions = serviceProvider.GetRequiredService>(); Assert.IsTrue(registeredOptions.Value.TrackExceptionsAsExceptionTelemetry);