diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/CHANGELOG.md b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/CHANGELOG.md index a265b8879d510..5b95067073513 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/CHANGELOG.md +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/CHANGELOG.md @@ -8,6 +8,15 @@ ### Bugs Fixed +* Fixed an issue where a `DuplicateKeyException` could be thrown if `EventId` + and `EventName` were present in both `LogRecord` (`LogRecord.EventId`, + `LogRecord.EventName`) and `LogRecord.Attributes`. The method now uses + `EventId` and `EventName` from `LogRecord.Attributes` when both are present. + If they are not in `LogRecord.Attributes`, it uses the values from + `LogRecord.EventId` or `LogRecord.EventName`, preventing the `LogRecord` from + being dropped. + ([#44748](https://github.com/Azure/azure-sdk-for-net/pull/44748)) + ### Other Changes * Enabled support for log collection from Azure SDKs via `Microsoft.Extensions.Logging`. diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogsHelper.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogsHelper.cs index 2892fbec5edfd..c4dce94f2f3de 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogsHelper.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogsHelper.cs @@ -124,12 +124,12 @@ internal static List OtelToAzureMonitorLogs(Batch batc logRecord.ForEachScope(s_processScope, properties); - if (logRecord.EventId.Id != 0) + if (!properties.ContainsKey("EventId") && logRecord.EventId.Id != 0) { properties.Add("EventId", logRecord.EventId.Id.ToString(CultureInfo.InvariantCulture)); } - if (!string.IsNullOrEmpty(logRecord.EventId.Name)) + if (!properties.ContainsKey("EventName") && !string.IsNullOrEmpty(logRecord.EventId.Name)) { properties.Add("EventName", logRecord.EventId.Name!.Truncate(SchemaConstants.KVP_MaxValueLength)); } 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..59bbd2b7e0f7d 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 @@ -183,6 +183,36 @@ public void PropertiesContainEventIdAndEventNameIfSetOnLog() Assert.Equal(2, properties.Count); } + [Fact] + public void LogRecordAndAttributesContainEventIdAndEventName() + { + var logRecords = new List(); + using var loggerFactory = LoggerFactory.Create(builder => + { + builder.AddOpenTelemetry(options => + { + options.AddInMemoryExporter(logRecords); + }); + builder.AddFilter(typeof(LogsHelperTests).FullName, LogLevel.Trace); + }); + + var logger = loggerFactory.CreateLogger(); + + EventId id = new EventId(1, "TestEvent"); + + string log = "Log Information {EventId} {EventName}."; + logger.LogInformation(id, log, 100, "TestAttributeEventName"); + + var properties = new ChangeTrackingDictionary(); + LogsHelper.GetMessageAndSetProperties(logRecords[0], properties); + + Assert.True(properties.TryGetValue("EventId", out string eventId)); + Assert.Equal("100", eventId); + Assert.True(properties.TryGetValue("EventName", out string eventName)); + Assert.Equal("TestAttributeEventName", eventName); + Assert.Equal(2, properties.Count); + } + [Fact] public void ValidateSeverityLevels() {