From ae0384060f39ef58126c7f97ec89855d355c119b Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Mon, 26 Jun 2023 10:19:50 -0700 Subject: [PATCH 1/5] [sdk-1.5.0-hotfix] Fix LogRecord.State being null when TState matches known interfaces (#4609) --- src/OpenTelemetry/CHANGELOG.md | 6 +++ .../Logs/ILogger/OpenTelemetryLogger.cs | 31 ++++++++++++--- .../OtlpLogExporterTests.cs | 2 +- .../OpenTelemetry.Tests/Logs/LogRecordTest.cs | 39 ++++++++++++++----- 4 files changed, 62 insertions(+), 16 deletions(-) diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index 12adabd6966..5eee0c5b453 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -2,6 +2,12 @@ ## Unreleased +* Fixed a breaking change causing `LogRecord.State` to be `null` where it was + previously set to a valid value when + `OpenTelemetryLoggerOptions.ParseStateValues` is `false` and states implement + `IReadOnlyList` or `IEnumerable` of `KeyValuePair`s. + ([#4609](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4609)) + ## 1.5.0 Released 2023-Jun-05 diff --git a/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLogger.cs b/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLogger.cs index 1ca14d3e0bd..e66c548d2bc 100644 --- a/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLogger.cs +++ b/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLogger.cs @@ -95,9 +95,8 @@ public void Log(LogLevel logLevel, EventId eventId, TState state, Except LogRecordData.SetActivityContext(ref data, activity); - var attributes = record.Attributes = this.options.IncludeAttributes - ? ProcessState(record, ref iloggerData, in state, this.options.ParseStateValues) - : null; + var attributes = record.Attributes = + ProcessState(record, ref iloggerData, in state, this.options.IncludeAttributes, this.options.ParseStateValues); if (!TryGetOriginalFormatFromAttributes(attributes, out var originalFormat)) { @@ -153,9 +152,15 @@ internal static void SetLogRecordSeverityFields(ref LogRecordData logRecordData, LogRecord logRecord, ref LogRecord.LogRecordILoggerData iLoggerData, in TState state, + bool includeAttributes, bool parseStateValues) { - iLoggerData.State = null; + if (!includeAttributes + || (!typeof(TState).IsValueType && state is null)) + { + iLoggerData.State = null; + return null; + } /* TODO: Enable this if/when LogRecordAttributeList becomes public. if (typeof(TState) == typeof(LogRecordAttributeList)) @@ -172,10 +177,20 @@ internal static void SetLogRecordSeverityFields(ref LogRecordData logRecordData, else */ if (state is IReadOnlyList> stateList) { + // Note: This is to preserve legacy behavior where State is exposed + // if we didn't parse state. We use stateList here to prevent a + // second boxing of struct TStates. + iLoggerData.State = !parseStateValues ? stateList : null; + return stateList; } else if (state is IEnumerable> stateValues) { + // Note: This is to preserve legacy behavior where State is exposed + // if we didn't parse state. We use stateValues here to prevent a + // second boxing of struct TStates. + iLoggerData.State = !parseStateValues ? stateValues : null; + var attributeStorage = logRecord.AttributeStorage; if (attributeStorage == null) { @@ -187,7 +202,7 @@ internal static void SetLogRecordSeverityFields(ref LogRecordData logRecordData, return attributeStorage; } } - else if (!parseStateValues || state is null) + else if (!parseStateValues) { // Note: This is to preserve legacy behavior where State is // exposed if we didn't parse state. @@ -196,9 +211,13 @@ internal static void SetLogRecordSeverityFields(ref LogRecordData logRecordData, } else { + // Note: We clear State because the LogRecord we are processing may + // have come from the pool and may have State from a prior log. + iLoggerData.State = null; + try { - PropertyDescriptorCollection itemProperties = TypeDescriptor.GetProperties(state); + PropertyDescriptorCollection itemProperties = TypeDescriptor.GetProperties(state!); var attributeStorage = logRecord.AttributeStorage ??= new List>(itemProperties.Count); diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpLogExporterTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpLogExporterTests.cs index 404b41e3533..d9e79fee60d 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpLogExporterTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpLogExporterTests.cs @@ -65,7 +65,7 @@ public void AddOtlpLogExporterReceivesAttributesWithParseStateValueSetToFalse() Assert.Single(logRecords); var logRecord = logRecords[0]; #pragma warning disable CS0618 // Type or member is obsolete - Assert.Null(logRecord.State); + Assert.NotNull(logRecord.State); #pragma warning restore CS0618 // Type or member is obsolete Assert.NotNull(logRecord.Attributes); } diff --git a/test/OpenTelemetry.Tests/Logs/LogRecordTest.cs b/test/OpenTelemetry.Tests/Logs/LogRecordTest.cs index f9f6e6cb038..a9861d03aca 100644 --- a/test/OpenTelemetry.Tests/Logs/LogRecordTest.cs +++ b/test/OpenTelemetry.Tests/Logs/LogRecordTest.cs @@ -82,7 +82,7 @@ public void CheckStateForUnstructuredLog(bool includeFormattedMessage) const string message = "Hello, World!"; logger.LogInformation(message); - Assert.Null(exportedItems[0].State); + Assert.NotNull(exportedItems[0].State); var attributes = exportedItems[0].Attributes; Assert.NotNull(attributes); @@ -113,7 +113,7 @@ public void CheckStateForUnstructuredLogWithStringInterpolation(bool includeForm var message = $"Hello from potato {0.99}."; logger.LogInformation(message); - Assert.Null(exportedItems[0].State); + Assert.NotNull(exportedItems[0].State); var attributes = exportedItems[0].Attributes; Assert.NotNull(attributes); @@ -143,7 +143,7 @@ public void CheckStateForStructuredLogWithTemplate(bool includeFormattedMessage) const string message = "Hello from {name} {price}."; logger.LogInformation(message, "tomato", 2.99); - Assert.Null(exportedItems[0].State); + Assert.NotNull(exportedItems[0].State); var attributes = exportedItems[0].Attributes; Assert.NotNull(attributes); @@ -185,7 +185,7 @@ public void CheckStateForStructuredLogWithStrongType(bool includeFormattedMessag var food = new Food { Name = "artichoke", Price = 3.99 }; logger.LogInformation("{food}", food); - Assert.Null(exportedItems[0].State); + Assert.NotNull(exportedItems[0].State); var attributes = exportedItems[0].Attributes; Assert.NotNull(attributes); @@ -226,7 +226,7 @@ public void CheckStateForStructuredLogWithAnonymousType(bool includeFormattedMes var anonymousType = new { Name = "pumpkin", Price = 5.99 }; logger.LogInformation("{food}", anonymousType); - Assert.Null(exportedItems[0].State); + Assert.NotNull(exportedItems[0].State); var attributes = exportedItems[0].Attributes; Assert.NotNull(attributes); @@ -271,7 +271,7 @@ public void CheckStateForStructuredLogWithGeneralType(bool includeFormattedMessa }; logger.LogInformation("{food}", food); - Assert.Null(exportedItems[0].State); + Assert.NotNull(exportedItems[0].State); var attributes = exportedItems[0].Attributes; Assert.NotNull(attributes); @@ -321,7 +321,13 @@ public void CheckStateForExceptionLogged() const string message = "Exception Occurred"; logger.LogInformation(exception, message); - Assert.Null(exportedItems[0].State); + Assert.NotNull(exportedItems[0].State); + + var state = exportedItems[0].State; + var itemCount = state.GetType().GetProperty("Count").GetValue(state); + + // state only has {OriginalFormat} + Assert.Equal(1, itemCount); var attributes = exportedItems[0].Attributes; Assert.NotNull(attributes); @@ -334,6 +340,7 @@ public void CheckStateForExceptionLogged() Assert.Equal(exceptionMessage, loggedException.Message); Assert.Equal(message, exportedItems[0].Body); + Assert.Equal(message, state.ToString()); Assert.Null(exportedItems[0].FormattedMessage); } @@ -711,7 +718,14 @@ public void VerifyParseStateValues_UsingStandardExtensions(bool parseStateValues var logRecord = exportedItems[0]; Assert.NotNull(logRecord.StateValues); - Assert.Null(logRecord.State); + if (parseStateValues) + { + Assert.Null(logRecord.State); + } + else + { + Assert.NotNull(logRecord.State); + } Assert.NotNull(logRecord.StateValues); Assert.Equal(3, logRecord.StateValues.Count); @@ -725,7 +739,14 @@ public void VerifyParseStateValues_UsingStandardExtensions(bool parseStateValues logRecord = exportedItems[1]; Assert.NotNull(logRecord.StateValues); - Assert.Null(logRecord.State); + if (parseStateValues) + { + Assert.Null(logRecord.State); + } + else + { + Assert.NotNull(logRecord.State); + } Assert.NotNull(logRecord.StateValues); Assert.Equal(4, logRecord.StateValues.Count); From b03e031fbcc58d9feda4eeda8605a43a1df406b0 Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Mon, 26 Jun 2023 13:00:42 -0700 Subject: [PATCH 2/5] [sdk-1.5.0-hotfix] Removed support for parsing custom log states using reflection (#4614) --- src/OpenTelemetry/CHANGELOG.md | 10 ++++++ .../Internal/OpenTelemetrySdkEventSource.cs | 17 ++++++++++ .../Logs/ILogger/OpenTelemetryLogger.cs | 33 ++----------------- .../ILogger/OpenTelemetryLoggerOptions.cs | 16 ++++++--- .../AotCompatibilityTests.cs | 2 +- .../OtlpLogExporterTests.cs | 12 +++++-- .../OpenTelemetry.Tests/Logs/LogRecordTest.cs | 11 +++---- 7 files changed, 58 insertions(+), 43 deletions(-) diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index 5eee0c5b453..b2aa7b15ea9 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -8,6 +8,16 @@ `IReadOnlyList` or `IEnumerable` of `KeyValuePair`s. ([#4609](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4609)) +* **Breaking Change** Removed the support for parsing `TState` types passed to + the `ILogger.Log` API when `ParseStateValues` is true and `TState` + does not implement either `IReadOnlyList>` or + `IEnumerable>`. This feature was first introduced + in the `1.5.0` stable release with + [#4334](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4334) and + has been removed because it makes the OpenTelemetry .NET SDK incompatible with + native AOT. + ([#4614](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4614)) + ## 1.5.0 Released 2023-Jun-05 diff --git a/src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs b/src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs index a13bc1adba0..db4aff9ce65 100644 --- a/src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs +++ b/src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs @@ -158,6 +158,17 @@ public void LoggerProviderException(string methodName, Exception ex) } } + [NonEvent] + public void LoggerProcessStateSkipped() + { + if (this.IsEnabled(EventLevel.Warning, EventKeywords.All)) + { + this.LoggerProcessStateSkipped( + typeof(TState).FullName!, + "because it does not implement a supported interface (either IReadOnlyList> or IEnumerable>)"); + } + } + [Event(4, Message = "Unknown error in SpanProcessor event '{0}': '{1}'.", Level = EventLevel.Error)] public void SpanProcessorException(string evnt, string ex) { @@ -325,6 +336,12 @@ public void LoggerProviderException(string methodName, string ex) this.WriteEvent(50, methodName, ex); } + [Event(51, Message = "Skipped processing log state of type '{0}' {1}.", Level = EventLevel.Warning)] + public void LoggerProcessStateSkipped(string type, string reason) + { + this.WriteEvent(51, type, reason); + } + #if DEBUG public class OpenTelemetryEventListener : EventListener { diff --git a/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLogger.cs b/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLogger.cs index e66c548d2bc..9d15e3f1355 100644 --- a/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLogger.cs +++ b/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLogger.cs @@ -16,7 +16,6 @@ #nullable enable -using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; @@ -207,6 +206,7 @@ internal static void SetLogRecordSeverityFields(ref LogRecordData logRecordData, // Note: This is to preserve legacy behavior where State is // exposed if we didn't parse state. iLoggerData.State = state; + return null; } else @@ -215,36 +215,9 @@ internal static void SetLogRecordSeverityFields(ref LogRecordData logRecordData, // have come from the pool and may have State from a prior log. iLoggerData.State = null; - try - { - PropertyDescriptorCollection itemProperties = TypeDescriptor.GetProperties(state!); - - var attributeStorage = logRecord.AttributeStorage ??= new List>(itemProperties.Count); - - foreach (PropertyDescriptor? itemProperty in itemProperties) - { - if (itemProperty == null) - { - continue; - } - - object? value = itemProperty.GetValue(state); - if (value == null) - { - continue; - } - - attributeStorage.Add(new KeyValuePair(itemProperty.Name, value)); - } + OpenTelemetrySdkEventSource.Log.LoggerProcessStateSkipped(); - return attributeStorage; - } - catch (Exception parseException) - { - OpenTelemetrySdkEventSource.Log.LoggerParseStateException(parseException); - - return Array.Empty>(); - } + return Array.Empty>(); } } diff --git a/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLoggerOptions.cs b/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLoggerOptions.cs index f2a392e52e7..d3ff3681f2a 100644 --- a/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLoggerOptions.cs +++ b/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLoggerOptions.cs @@ -58,13 +58,21 @@ public class OpenTelemetryLoggerOptions /// /// Notes: /// - /// Parsing is only executed when the state logged does NOT - /// implement or As of OpenTelemetry v1.5 state parsing is handled automatically if + /// the state logged implements or where T is KeyValuePair<string, - /// object>. + /// object> than will be set + /// regardless of the value of . /// When is set to will always be . + /// langword="null"/>. When is set to will always be set to + /// the logged state to support legacy exporters which access directly. Exporters should NOT access directly because is NOT safe and may lead to + /// exceptions or incorrect data especially when using batching. Exporters + /// should use to safely access any data + /// attached to log messages. /// /// public bool ParseStateValues { get; set; } diff --git a/test/OpenTelemetry.AotCompatibility.Tests/AotCompatibilityTests.cs b/test/OpenTelemetry.AotCompatibility.Tests/AotCompatibilityTests.cs index 2b9cf77d9c3..0e54f129a10 100644 --- a/test/OpenTelemetry.AotCompatibility.Tests/AotCompatibilityTests.cs +++ b/test/OpenTelemetry.AotCompatibility.Tests/AotCompatibilityTests.cs @@ -85,7 +85,7 @@ public void EnsureAotCompatibility() Assert.True(process.ExitCode == 0, "Publishing the AotCompatibility app failed. See test output for more details."); var warnings = expectedOutput.ToString().Split('\n', '\r').Where(line => line.Contains("warning IL")); - Assert.Equal(43, warnings.Count()); + Assert.Equal(42, warnings.Count()); } } } diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpLogExporterTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpLogExporterTests.cs index d9e79fee60d..b5dd80f329d 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpLogExporterTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpLogExporterTests.cs @@ -100,7 +100,11 @@ public void AddOtlpLogExporterParseStateValueCanBeTurnedOff(bool parseState) { Assert.Null(logRecord.State); Assert.NotNull(logRecord.Attributes); - Assert.Contains(logRecord.Attributes, kvp => kvp.Key == "propertyA" && (string)kvp.Value == "valueA"); + + // Note: We currently do not support parsing custom states which do + // not implement the standard interfaces. We return empty attributes + // for these. + Assert.Empty(logRecord.Attributes); } else { @@ -140,7 +144,11 @@ public void AddOtlpLogExporterParseStateValueCanBeTurnedOffHosting(bool parseSta { Assert.Null(logRecord.State); Assert.NotNull(logRecord.Attributes); - Assert.Contains(logRecord.Attributes, kvp => kvp.Key == "propertyA" && (string)kvp.Value == "valueA"); + + // Note: We currently do not support parsing custom states which do + // not implement the standard interfaces. We return empty attributes + // for these. + Assert.Empty(logRecord.Attributes); } else { diff --git a/test/OpenTelemetry.Tests/Logs/LogRecordTest.cs b/test/OpenTelemetry.Tests/Logs/LogRecordTest.cs index a9861d03aca..a828e7af63e 100644 --- a/test/OpenTelemetry.Tests/Logs/LogRecordTest.cs +++ b/test/OpenTelemetry.Tests/Logs/LogRecordTest.cs @@ -826,7 +826,7 @@ public void ParseStateValuesUsingIEnumerableTest() } [Fact] - public void ParseStateValuesUsingCustomTest() + public void ParseStateValuesUsingNonconformingCustomTypeTest() { using var loggerFactory = InitializeLoggerFactory(out List exportedItems, configure: options => options.ParseStateValues = true); var logger = loggerFactory.CreateLogger(); @@ -848,12 +848,11 @@ public void ParseStateValuesUsingCustomTest() Assert.Null(logRecord.State); Assert.NotNull(logRecord.StateValues); - Assert.Equal(1, logRecord.StateValues.Count); - - KeyValuePair actualState = logRecord.StateValues[0]; - Assert.Equal("Property", actualState.Key); - Assert.Equal("Value", actualState.Value); + // Note: We currently do not support parsing custom states which do + // not implement the standard interfaces. We return empty attributes + // for these. + Assert.Empty(logRecord.StateValues); } [Fact] From 8d6169144707c589cd5e7e862c1c8dac9042e9fb Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Mon, 26 Jun 2023 15:48:42 -0700 Subject: [PATCH 3/5] [sdk-1.5.0-hotfix] Update CHANGELOG for release (#4615) --- src/OpenTelemetry.Api.ProviderBuilderExtensions/CHANGELOG.md | 4 ++++ src/OpenTelemetry.Api/CHANGELOG.md | 4 ++++ src/OpenTelemetry.Exporter.Console/CHANGELOG.md | 4 ++++ src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md | 4 ++++ src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md | 4 ++++ src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md | 4 ++++ src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md | 4 ++++ src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md | 4 ++++ src/OpenTelemetry.Extensions.Propagators/CHANGELOG.md | 4 ++++ src/OpenTelemetry/CHANGELOG.md | 4 ++++ 10 files changed, 40 insertions(+) diff --git a/src/OpenTelemetry.Api.ProviderBuilderExtensions/CHANGELOG.md b/src/OpenTelemetry.Api.ProviderBuilderExtensions/CHANGELOG.md index 2652e2e628e..274b80550b0 100644 --- a/src/OpenTelemetry.Api.ProviderBuilderExtensions/CHANGELOG.md +++ b/src/OpenTelemetry.Api.ProviderBuilderExtensions/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.5.1 + +Released 2023-Jun-26 + ## 1.5.0 Released 2023-Jun-05 diff --git a/src/OpenTelemetry.Api/CHANGELOG.md b/src/OpenTelemetry.Api/CHANGELOG.md index c87f1b4b31f..06fdc116a6b 100644 --- a/src/OpenTelemetry.Api/CHANGELOG.md +++ b/src/OpenTelemetry.Api/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.5.1 + +Released 2023-Jun-26 + ## 1.5.0 Released 2023-Jun-05 diff --git a/src/OpenTelemetry.Exporter.Console/CHANGELOG.md b/src/OpenTelemetry.Exporter.Console/CHANGELOG.md index 9092da706a2..e7f12746374 100644 --- a/src/OpenTelemetry.Exporter.Console/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Console/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.5.1 + +Released 2023-Jun-26 + ## 1.5.0 Released 2023-Jun-05 diff --git a/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md b/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md index 11b5782ef82..71a62851dab 100644 --- a/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.5.1 + +Released 2023-Jun-26 + ## 1.5.0 Released 2023-Jun-05 diff --git a/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md b/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md index 7da333f1efc..bdd4d000b78 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.5.1 + +Released 2023-Jun-26 + ## 1.5.0 Released 2023-Jun-05 diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md index 5104c3aa90f..f54749716c4 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.5.1 + +Released 2023-Jun-26 + ## 1.5.0 Released 2023-Jun-05 diff --git a/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md b/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md index f4a087974ec..f2e21b66c06 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.5.1 + +Released 2023-Jun-26 + ## 1.5.0 Released 2023-Jun-05 diff --git a/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md b/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md index df4fdb71df5..73c09094a4f 100644 --- a/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md +++ b/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.5.1 + +Released 2023-Jun-26 + ## 1.5.0 Released 2023-Jun-05 diff --git a/src/OpenTelemetry.Extensions.Propagators/CHANGELOG.md b/src/OpenTelemetry.Extensions.Propagators/CHANGELOG.md index 96c5e0f1ebb..ae47a662498 100644 --- a/src/OpenTelemetry.Extensions.Propagators/CHANGELOG.md +++ b/src/OpenTelemetry.Extensions.Propagators/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.5.1 + +Released 2023-Jun-26 + ## 1.5.0 Released 2023-Jun-05 diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index b2aa7b15ea9..6de920c992a 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.5.1 + +Released 2023-Jun-26 + * Fixed a breaking change causing `LogRecord.State` to be `null` where it was previously set to a valid value when `OpenTelemetryLoggerOptions.ParseStateValues` is `false` and states implement From 1cf54f19f93c36c45e7397b89f964b2ed0f42f27 Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Mon, 26 Jun 2023 16:29:01 -0700 Subject: [PATCH 4/5] Updates for 1.6 logging changes. --- src/OpenTelemetry.Api/Logs/LogRecordAttributeList.cs | 5 +++-- src/OpenTelemetry/Logs/ILogger/OpenTelemetryLogger.cs | 9 ++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/OpenTelemetry.Api/Logs/LogRecordAttributeList.cs b/src/OpenTelemetry.Api/Logs/LogRecordAttributeList.cs index 8498b1417f7..170b7949837 100644 --- a/src/OpenTelemetry.Api/Logs/LogRecordAttributeList.cs +++ b/src/OpenTelemetry.Api/Logs/LogRecordAttributeList.cs @@ -32,6 +32,7 @@ public struct LogRecordAttributeList : IReadOnlyList>? OverflowAttributes; + private static readonly IReadOnlyList> Empty = Array.Empty>(); private KeyValuePair attribute1; private KeyValuePair attribute2; private KeyValuePair attribute3; @@ -207,12 +208,12 @@ public readonly Enumerator GetEnumerator() /// readonly IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); - internal readonly List>? Export(ref List>? attributeStorage) + internal readonly IReadOnlyList> Export(ref List>? attributeStorage) { int count = this.count; if (count <= 0) { - return null; + return Empty; } var overflowAttributes = this.OverflowAttributes; diff --git a/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLogger.cs b/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLogger.cs index 768756836f0..8fb5af320f4 100644 --- a/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLogger.cs +++ b/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLogger.cs @@ -170,7 +170,14 @@ internal static void SetLogRecordSeverityFields(ref LogRecordData logRecordData, var logRecordAttributes = (LogRecordAttributeList)(object)state!; - return logRecordAttributes.Export(ref logRecord.AttributeStorage); + var exportedAttributes = logRecordAttributes.Export(ref logRecord.AttributeStorage); + + // Note: This is to preserve legacy behavior where State is exposed + // if we didn't parse state. We use exportedAttributes here to prevent a + // boxing of struct LogRecordAttributeList. + iLoggerData.State = !parseStateValues ? exportedAttributes : null; + + return exportedAttributes; } else if (state is IReadOnlyList> stateList) { From 7af15f6898ee2f08518b8eabb3990644f41dda8a Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Mon, 26 Jun 2023 16:46:29 -0700 Subject: [PATCH 5/5] Test updates. --- .../OpenTelemetry.Api.Tests/Logs/LogRecordAttributeListTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/OpenTelemetry.Api.Tests/Logs/LogRecordAttributeListTests.cs b/test/OpenTelemetry.Api.Tests/Logs/LogRecordAttributeListTests.cs index 21d856c9799..21a583810df 100644 --- a/test/OpenTelemetry.Api.Tests/Logs/LogRecordAttributeListTests.cs +++ b/test/OpenTelemetry.Api.Tests/Logs/LogRecordAttributeListTests.cs @@ -117,7 +117,7 @@ public void ExportTest(int numberOfItems) if (numberOfItems == 0) { - Assert.Null(exportedAttributes); + Assert.Empty(exportedAttributes); Assert.Null(storage); return; }