From 19152e472bf83db0b0abed1afd6156fcd37826cc Mon Sep 17 00:00:00 2001 From: Timothy Mothra Lee Date: Wed, 26 Jun 2024 17:52:39 -0700 Subject: [PATCH 01/11] add Log Scopes example to Readme --- .../README.md | 29 ++++++++++++++++ .../README.md | 34 +++++++++++++++++-- .../E2ETelemetryItemValidation/LogsTests.cs | 24 +++++++++---- 3 files changed, 78 insertions(+), 9 deletions(-) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md index fe89c699a182c..1af605918fadf 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md @@ -293,6 +293,35 @@ The Azure Monitor Distro is a distribution package that facilitates users in sen Refer to [`Program.cs`](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Demo/Program.cs) for a complete demo. +### Log Scopes + +Log scopes allow you to add additional properties to the logs generated by your application. +Although the Azure Monitor Exporter does support scopes, this feature is off by default in OpenTelemetry. +To leverage log scopes, you must explicitly enable them. + +To include the scope with your logs, set `OpenTelemetryLoggerOptions.IncludeScopes` to `true` in your application's configuration: +```csharp +builder.Services.Configure(options => +{ + options.IncludeScopes = true; +}); +``` + +Once enabled, you can define a scope using a dictionary or any enumerable of KeyValuePair. +All logs written within the context of the scope will include the specified information. +Azure Monitor will add these scope values to the Log's CustomProperties. +```csharp +List> scope = +[ + new("scopeKey", "scopeValue") +]; + +using (logger.BeginScope(scope)) +{ + logger.LogInformation("Example message."); +} +``` + ## Troubleshooting The Azure Monitor Distro uses EventSource for its own internal logging. The logs are available to any EventListener by opting into the source named "OpenTelemetry-AzureMonitor-Exporter". diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md index adf8f88d26355..fa92af4294670 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md @@ -1,7 +1,5 @@ # Azure Monitor Exporter client library for .NET - - The [OpenTelemetry .NET](https://github.com/open-telemetry/opentelemetry-dotnet) exporters which send [telemetry data](https://docs.microsoft.com/azure/azure-monitor/app/data-model) to [Azure Monitor](https://docs.microsoft.com/azure/azure-monitor/app/app-insights-overview) following the [OpenTelemetry Specification](https://github.com/open-telemetry/opentelemetry-specification). ## Getting started @@ -135,6 +133,38 @@ For more information on the OpenTelemetry project, please review the [OpenTeleme Refer to [`Program.cs`](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Demo/Program.cs) for a complete demo. +### Log Scopes + +Log scopes allow you to add additional properties to the logs generated by your application. +Although the Azure Monitor Exporter does support scopes, this feature is off by default in OpenTelemetry. +To leverage log scopes, you must explicitly enable them. + +To include the scope with your logs, set `OpenTelemetryLoggerOptions.IncludeScopes` to `true` in your application's configuration: +```csharp +var loggerFactory = LoggerFactory.Create(builder => +{ + builder.AddOpenTelemetry(options => + { + options.IncludeScopes = true; + }); +}); +``` + +Once enabled, you can define a scope using a dictionary or any enumerable of KeyValuePair. +All logs written within the context of the scope will include the specified information. +Azure Monitor will add these scope values to the Log's CustomProperties. +```csharp +List> scope = +[ + new("scopeKey", "scopeValue") +]; + +using (logger.BeginScope(scope)) +{ + logger.LogInformation("Example message."); +} +``` + ## Troubleshooting The Azure Monitor exporter uses EventSource for its own internal logging. The exporter logs are available to any EventListener by opting into the source named "OpenTelemetry-AzureMonitor-Exporter". diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/LogsTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/LogsTests.cs index cb95fd64e3388..1f877b4b9d416 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/LogsTests.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/LogsTests.cs @@ -57,6 +57,7 @@ public void VerifyLog(LogLevel logLevel, string expectedSeverityLevel) .AddFilter(logCategoryName, logLevel) .AddOpenTelemetry(options => { + options.IncludeScopes = true; options.SetResourceBuilder(ResourceBuilder.CreateDefault().AddAttributes(testResourceAttributes)); options.AddAzureMonitorLogExporterForTest(out telemetryItems); }); @@ -64,12 +65,21 @@ public void VerifyLog(LogLevel logLevel, string expectedSeverityLevel) // ACT var logger = loggerFactory.CreateLogger(logCategoryName); - logger.Log( - logLevel: logLevel, - eventId: 0, - exception: null, - message: "Hello {name}.", - args: new object[] { "World" }); + + List> scope = new() + { + new("scopeKey", "scopeValue") + }; + + using (logger.BeginScope(scope)) + { + logger.Log( + logLevel: logLevel, + eventId: 0, + exception: null, + message: "Hello {name}.", + args: new object[] { "World" }); + } // CLEANUP loggerFactory.Dispose(); @@ -83,7 +93,7 @@ public void VerifyLog(LogLevel logLevel, string expectedSeverityLevel) telemetryItem: telemetryItem!, expectedSeverityLevel: expectedSeverityLevel, expectedMessage: "Hello {name}.", - expectedMessageProperties: new Dictionary { { "name", "World" }}, + expectedMessageProperties: new Dictionary { { "name", "World" }, { "scopeKey", "scopeValue" } }, expectedSpanId: null, expectedTraceId: null); } From 134d8f4dc44914aa151a6dfd21cf15f302f25920 Mon Sep 17 00:00:00 2001 From: Timothy Mothra Lee Date: Thu, 27 Jun 2024 13:43:33 -0700 Subject: [PATCH 02/11] pr feedback --- .../README.md | 2 ++ .../README.md | 2 ++ .../E2ETelemetryItemValidation/LogsTests.cs | 15 +++++++++++---- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md index 1af605918fadf..cd71521da828a 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md @@ -322,6 +322,8 @@ using (logger.BeginScope(scope)) } ``` +Note that if you define nested scopes with the same key or multiple keyvaluepairs with the same key, only the first value will be set. + ## Troubleshooting The Azure Monitor Distro uses EventSource for its own internal logging. The logs are available to any EventListener by opting into the source named "OpenTelemetry-AzureMonitor-Exporter". diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md index fa92af4294670..31eb4b1ad68dc 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md @@ -165,6 +165,8 @@ using (logger.BeginScope(scope)) } ``` +Note that if you define nested scopes with the same key or multiple keyvaluepairs with the same key, only the first value will be set. + ## Troubleshooting The Azure Monitor exporter uses EventSource for its own internal logging. The exporter logs are available to any EventListener by opting into the source named "OpenTelemetry-AzureMonitor-Exporter". diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/LogsTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/LogsTests.cs index 1f877b4b9d416..5962057a94e7f 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/LogsTests.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/LogsTests.cs @@ -66,12 +66,19 @@ public void VerifyLog(LogLevel logLevel, string expectedSeverityLevel) // ACT var logger = loggerFactory.CreateLogger(logCategoryName); - List> scope = new() + List> scope1 = new() { - new("scopeKey", "scopeValue") + new("scopeKey1", "scopeValue1"), + new("scopeKey1", "scopeValue2") }; - using (logger.BeginScope(scope)) + List> scope2 = new() + { + new("scopeKey1", "scopeValue3") + }; + + using (logger.BeginScope(scope1)) + using (logger.BeginScope(scope2)) { logger.Log( logLevel: logLevel, @@ -93,7 +100,7 @@ public void VerifyLog(LogLevel logLevel, string expectedSeverityLevel) telemetryItem: telemetryItem!, expectedSeverityLevel: expectedSeverityLevel, expectedMessage: "Hello {name}.", - expectedMessageProperties: new Dictionary { { "name", "World" }, { "scopeKey", "scopeValue" } }, + expectedMessageProperties: new Dictionary { { "name", "World" }, { "scopeKey1", "scopeValue1" } }, expectedSpanId: null, expectedTraceId: null); } From 4d48f54c5d5244d9aac2008f4f4c1c6c6801b81d Mon Sep 17 00:00:00 2001 From: Timothy Mothra Lee Date: Fri, 28 Jun 2024 10:02:58 -0700 Subject: [PATCH 03/11] add AzureMonitor to example code --- sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md | 1 + sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md | 1 + 2 files changed, 2 insertions(+) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md index cd71521da828a..05687e084e618 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md @@ -301,6 +301,7 @@ To leverage log scopes, you must explicitly enable them. To include the scope with your logs, set `OpenTelemetryLoggerOptions.IncludeScopes` to `true` in your application's configuration: ```csharp +builder.Services.AddOpenTelemetry().UseAzureMonitor(); builder.Services.Configure(options => { options.IncludeScopes = true; diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md index 31eb4b1ad68dc..f1cbc4dcac19a 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md @@ -145,6 +145,7 @@ var loggerFactory = LoggerFactory.Create(builder => { builder.AddOpenTelemetry(options => { + options.AddAzureMonitorLogExporter(o => o.ConnectionString = "InstrumentationKey=00000000-0000-0000-0000-000000000000"); options.IncludeScopes = true; }); }); From 6a84e1e0e12c0b2b275a2ac07a1f4651d048275c Mon Sep 17 00:00:00 2001 From: Timothy Mothra Lee Date: Fri, 28 Jun 2024 10:29:40 -0700 Subject: [PATCH 04/11] pr feedback --- sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md | 3 ++- sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md index 05687e084e618..43fb36d33a9dd 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md @@ -323,7 +323,8 @@ using (logger.BeginScope(scope)) } ``` -Note that if you define nested scopes with the same key or multiple keyvaluepairs with the same key, only the first value will be set. +In scenarios involving multiple scopes or a single scope with multiple key-value pairs, if duplicate keys are present, only the first occurrence of the key-value pair from the outermost scope will be recorded. +However, when the same key is utilized both within a logging scope and directly in the log message template, the value specified in the log message template will take precedence. ## Troubleshooting diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md index f1cbc4dcac19a..713532881cc36 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md @@ -166,7 +166,8 @@ using (logger.BeginScope(scope)) } ``` -Note that if you define nested scopes with the same key or multiple keyvaluepairs with the same key, only the first value will be set. +In scenarios involving multiple scopes or a single scope with multiple key-value pairs, if duplicate keys are present, only the first occurrence of the key-value pair from the outermost scope will be recorded. +However, when the same key is utilized both within a logging scope and directly in the log message template, the value specified in the log message template will take precedence. ## Troubleshooting From 3f1749c5734a9ac0435790201aef312aea528f05 Mon Sep 17 00:00:00 2001 From: Timothy Mothra Date: Fri, 28 Jun 2024 10:47:55 -0700 Subject: [PATCH 05/11] Update sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md Co-authored-by: Cijo Thomas --- sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md index 713532881cc36..52ad3fbe0d5a4 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md @@ -167,7 +167,7 @@ using (logger.BeginScope(scope)) ``` In scenarios involving multiple scopes or a single scope with multiple key-value pairs, if duplicate keys are present, only the first occurrence of the key-value pair from the outermost scope will be recorded. -However, when the same key is utilized both within a logging scope and directly in the log message template, the value specified in the log message template will take precedence. +However, when the same key is utilized both within a logging scope and directly in the log statement, the value specified in the log message template will take precedence. ## Troubleshooting From 0b4b6fc2fdeb5de46ed76226c0e48496a9a3e90e Mon Sep 17 00:00:00 2001 From: Timothy Mothra Lee Date: Fri, 28 Jun 2024 11:13:34 -0700 Subject: [PATCH 06/11] add another test --- .../LogsHelperTests.cs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/LogsHelperTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/LogsHelperTests.cs index 3905ea097d64f..6d23863c74d4b 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/LogsHelperTests.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/LogsHelperTests.cs @@ -415,6 +415,47 @@ public void DuplicateKeysInLogRecordAttributesAndLogScope() Assert.Equal(expectedAttributeValue, actualAttributeValue); } + [Fact] + public void DuplicateKeysInLogRecordAttributesAndLogScope2() + { + // Arrange. + var logRecords = new List(1); + using var loggerFactory = LoggerFactory.Create(builder => + { + builder.AddOpenTelemetry(options => + { + options.IncludeScopes = true; + options.AddInMemoryExporter(logRecords); + }); + }); + + var logger = loggerFactory.CreateLogger("Some category"); + + const string expectedScopeKey = "Some scope key"; + const string expectedScopeValue = "Some scope value"; + const string duplicateScopeValue = "Some duplicate scope value"; + const string duplicateScopeValue2 = "Another duplicate scope value"; + + // Act. + using (logger.BeginScope(new List> + { + new KeyValuePair(expectedScopeKey, expectedScopeValue), + new KeyValuePair(expectedScopeKey, duplicateScopeValue), + })) + { + logger.LogInformation($"Some log information message. {{{expectedScopeKey}}}.", duplicateScopeValue2); + } + + // Assert. + var logRecord = logRecords.Single(); + var properties = new ChangeTrackingDictionary(); + LogsHelper.GetMessageAndSetProperties(logRecords[0], properties); + + Assert.Single(properties); + Assert.True(properties.TryGetValue(expectedScopeKey, out string actualScopeValue)); + Assert.Equal(duplicateScopeValue2, actualScopeValue); + } + private class CustomObject { public override string ToString() From 840b3dd8e3bb089e30018694e6855b05a87a8bb0 Mon Sep 17 00:00:00 2001 From: Timothy Mothra Lee Date: Fri, 28 Jun 2024 11:44:48 -0700 Subject: [PATCH 07/11] pr feedback --- sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md | 4 ++-- sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md index 43fb36d33a9dd..d9537b45bb193 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md @@ -308,7 +308,7 @@ builder.Services.Configure(options => }); ``` -Once enabled, you can define a scope using a dictionary or any enumerable of KeyValuePair. +Once enabled, you can define a scope using a dictionary or any enumerable of `KeyValuePair`. All logs written within the context of the scope will include the specified information. Azure Monitor will add these scope values to the Log's CustomProperties. ```csharp @@ -324,7 +324,7 @@ using (logger.BeginScope(scope)) ``` In scenarios involving multiple scopes or a single scope with multiple key-value pairs, if duplicate keys are present, only the first occurrence of the key-value pair from the outermost scope will be recorded. -However, when the same key is utilized both within a logging scope and directly in the log message template, the value specified in the log message template will take precedence. +However, when the same key is utilized both within a logging scope and directly in the log statement, the value specified in the log message template will take precedence. ## Troubleshooting diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md index 52ad3fbe0d5a4..a3c04587c4f8a 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md @@ -151,7 +151,7 @@ var loggerFactory = LoggerFactory.Create(builder => }); ``` -Once enabled, you can define a scope using a dictionary or any enumerable of KeyValuePair. +Once enabled, you can define a scope using a dictionary or any enumerable of `KeyValuePair`. All logs written within the context of the scope will include the specified information. Azure Monitor will add these scope values to the Log's CustomProperties. ```csharp From e78ab781ec385b6a197cbbf39b5105da688987b4 Mon Sep 17 00:00:00 2001 From: Timothy Mothra Lee Date: Wed, 3 Jul 2024 16:47:51 -0700 Subject: [PATCH 08/11] pr feedback --- .../README.md | 18 +++++++++++------- .../README.md | 9 +++++---- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md index d9537b45bb193..9432993f0cc96 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md @@ -295,24 +295,27 @@ Refer to [`Program.cs`](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk ### Log Scopes -Log scopes allow you to add additional properties to the logs generated by your application. +Log [scopes](https://learn.microsoft.com/dotnet/core/extensions/logging#log-scopes) allow you to add additional properties to the logs generated by your application. Although the Azure Monitor Exporter does support scopes, this feature is off by default in OpenTelemetry. To leverage log scopes, you must explicitly enable them. To include the scope with your logs, set `OpenTelemetryLoggerOptions.IncludeScopes` to `true` in your application's configuration: ```csharp -builder.Services.AddOpenTelemetry().UseAzureMonitor(); -builder.Services.Configure(options => +var loggerFactory = LoggerFactory.Create(builder => { - options.IncludeScopes = true; + builder.AddOpenTelemetry(options => + { + options.AddAzureMonitorLogExporter(o => o.ConnectionString = "InstrumentationKey=00000000-0000-0000-0000-000000000000"); + options.IncludeScopes = true; + }); }); ``` -Once enabled, you can define a scope using a dictionary or any enumerable of `KeyValuePair`. +When using `ILogger` scopes, use a `List>` or `IReadOnlyList>` as the state for best performance. All logs written within the context of the scope will include the specified information. Azure Monitor will add these scope values to the Log's CustomProperties. ```csharp -List> scope = +List> scope = [ new("scopeKey", "scopeValue") ]; @@ -323,7 +326,8 @@ using (logger.BeginScope(scope)) } ``` -In scenarios involving multiple scopes or a single scope with multiple key-value pairs, if duplicate keys are present, only the first occurrence of the key-value pair from the outermost scope will be recorded. +In scenarios involving multiple scopes or a single scope with multiple key-value pairs, if duplicate keys are present, +only the first occurrence of the key-value pair from the outermost scope will be recorded. However, when the same key is utilized both within a logging scope and directly in the log statement, the value specified in the log message template will take precedence. ## Troubleshooting diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md index a3c04587c4f8a..c3b4ac1523d5d 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md @@ -135,7 +135,7 @@ Refer to [`Program.cs`](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk ### Log Scopes -Log scopes allow you to add additional properties to the logs generated by your application. +Log [scopes](https://learn.microsoft.com/dotnet/core/extensions/logging#log-scopes) allow you to add additional properties to the logs generated by your application. Although the Azure Monitor Exporter does support scopes, this feature is off by default in OpenTelemetry. To leverage log scopes, you must explicitly enable them. @@ -151,11 +151,11 @@ var loggerFactory = LoggerFactory.Create(builder => }); ``` -Once enabled, you can define a scope using a dictionary or any enumerable of `KeyValuePair`. +When using `ILogger` scopes, use a `List>` or `IReadOnlyList>` as the state for best performance. All logs written within the context of the scope will include the specified information. Azure Monitor will add these scope values to the Log's CustomProperties. ```csharp -List> scope = +List> scope = [ new("scopeKey", "scopeValue") ]; @@ -166,7 +166,8 @@ using (logger.BeginScope(scope)) } ``` -In scenarios involving multiple scopes or a single scope with multiple key-value pairs, if duplicate keys are present, only the first occurrence of the key-value pair from the outermost scope will be recorded. +In scenarios involving multiple scopes or a single scope with multiple key-value pairs, if duplicate keys are present, +only the first occurrence of the key-value pair from the outermost scope will be recorded. However, when the same key is utilized both within a logging scope and directly in the log statement, the value specified in the log message template will take precedence. ## Troubleshooting From f31bb505b98b874d333885555717b235e4ef647e Mon Sep 17 00:00:00 2001 From: Timothy Mothra Date: Tue, 16 Jul 2024 09:51:25 -0700 Subject: [PATCH 09/11] Update sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md Co-authored-by: Rajkumar Rangaraj --- sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md index 9432993f0cc96..05a1e57cd1aad 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md @@ -296,7 +296,7 @@ Refer to [`Program.cs`](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk ### Log Scopes Log [scopes](https://learn.microsoft.com/dotnet/core/extensions/logging#log-scopes) allow you to add additional properties to the logs generated by your application. -Although the Azure Monitor Exporter does support scopes, this feature is off by default in OpenTelemetry. +Although the Azure Monitor Distro does support scopes, this feature is off by default in OpenTelemetry. To leverage log scopes, you must explicitly enable them. To include the scope with your logs, set `OpenTelemetryLoggerOptions.IncludeScopes` to `true` in your application's configuration: From b8ee2a3785ea64acc027636887aa3f71817d2c92 Mon Sep 17 00:00:00 2001 From: "Timothy Mothra Lee (from Dev Box)" Date: Wed, 17 Jul 2024 13:34:20 -0700 Subject: [PATCH 10/11] fix --- .../LogsHelperTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/LogsHelperTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/LogsHelperTests.cs index 1cf126be3a54e..87bbbc96535ef 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/LogsHelperTests.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/LogsHelperTests.cs @@ -539,7 +539,7 @@ public void DuplicateKeysInLogRecordAttributesAndLogScope2() var properties = new ChangeTrackingDictionary(); LogsHelper.GetMessageAndSetProperties(logRecords[0], properties); - Assert.Single(properties); + Assert.Equal(2, properties.Count); Assert.True(properties.TryGetValue(expectedScopeKey, out string actualScopeValue)); Assert.Equal(duplicateScopeValue2, actualScopeValue); } From e2e22d20a0740b2f67053e3b29c829f6f168dfe9 Mon Sep 17 00:00:00 2001 From: "Timothy Mothra Lee (from Dev Box)" Date: Wed, 17 Jul 2024 14:04:55 -0700 Subject: [PATCH 11/11] pr feedback --- .../Azure.Monitor.OpenTelemetry.AspNetCore/README.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md index 4b43105b9846e..70c2b0c3fa57b 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md @@ -309,13 +309,9 @@ To leverage log scopes, you must explicitly enable them. To include the scope with your logs, set `OpenTelemetryLoggerOptions.IncludeScopes` to `true` in your application's configuration: ```csharp -var loggerFactory = LoggerFactory.Create(builder => +builder.Services.Configure((loggingOptions) => { - builder.AddOpenTelemetry(options => - { - options.AddAzureMonitorLogExporter(o => o.ConnectionString = "InstrumentationKey=00000000-0000-0000-0000-000000000000"); - options.IncludeScopes = true; - }); + loggingOptions.IncludeScopes = true; }); ```