From ef977c107a3862c2e6fd24a6677c52bc2d44d625 Mon Sep 17 00:00:00 2001 From: Julius Koval <124600946+AB027PS@users.noreply.github.com> Date: Mon, 5 Feb 2024 19:19:19 +0100 Subject: [PATCH] [otlp] Use LogRecord.Logger.Name for instrumentation scope if LogRecord.CategoryName is null (#5300) Co-authored-by: Mikel Blanchard --- .../CHANGELOG.md | 5 +++ .../OtlpLogRecordTransformer.cs | 9 +++-- .../OtlpLogExporterTests.cs | 38 +++++++++++++++++++ 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md index dcd24114fd1..6978f0c8a38 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md @@ -21,6 +21,11 @@ experimental Logs Bridge API. ([#5268](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5268)) +* Updated `OtlpLogExporter` to set instrumentation scope name on the data model + from `LogRecord.Logger.Name` if `LogRecord.CategoryName` is `null`. This is + typically the case when using the experimental Logs Bridge API. + ([#5300](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5300)) + ## 1.7.0 Released 2023-Dec-08 diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpLogRecordTransformer.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpLogRecordTransformer.cs index 607f8fa5584..4851816017c 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpLogRecordTransformer.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpLogRecordTransformer.cs @@ -18,6 +18,8 @@ internal sealed class OtlpLogRecordTransformer { internal static readonly ConcurrentBag LogListPool = new(); + private const string DefaultScopeName = ""; + private readonly SdkLimitOptions sdkLimitOptions; private readonly ExperimentalOptions experimentalOptions; @@ -47,10 +49,11 @@ internal OtlpCollector.ExportLogsServiceRequest BuildExportRequest( var otlpLogRecord = this.ToOtlpLog(logRecord); if (otlpLogRecord != null) { - if (!logsByCategory.TryGetValue(logRecord.CategoryName, out var scopeLogs)) + var scopeName = logRecord.CategoryName ?? logRecord.Logger?.Name ?? DefaultScopeName; + if (!logsByCategory.TryGetValue(scopeName, out var scopeLogs)) { - scopeLogs = this.GetLogListFromPool(logRecord.CategoryName); - logsByCategory.Add(logRecord.CategoryName, scopeLogs); + scopeLogs = this.GetLogListFromPool(scopeName); + logsByCategory.Add(scopeName, scopeLogs); resourceLogs.ScopeLogs.Add(scopeLogs); } diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpLogExporterTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpLogExporterTests.cs index 3656dda54aa..7181557ae5a 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpLogExporterTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpLogExporterTests.cs @@ -1469,6 +1469,44 @@ public void VerifyEnvironmentVariablesTakenFromIConfigurationWhenUsingLoggingBui }); } + [Theory] + [InlineData("my_instrumentation_scope_name", "my_instrumentation_scope_name")] + [InlineData(null, "")] + public void LogRecordLoggerNameIsExportedWhenUsingBridgeApi(string loggerName, string expectedScopeName) + { + LogRecordAttributeList attributes = default; + attributes.Add("name", "tomato"); + attributes.Add("price", 2.99); + attributes.Add("{OriginalFormat}", "Hello from {name} {price}."); + + var logRecords = new List(); + + using (var loggerProvider = Sdk.CreateLoggerProviderBuilder() + .AddInMemoryExporter(logRecords) + .Build()) + { + var logger = loggerProvider.GetLogger(loggerName); + + logger.EmitLog(new LogRecordData()); + } + + Assert.Single(logRecords); + + var otlpLogRecordTransformer = new OtlpLogRecordTransformer(DefaultSdkLimitOptions, new()); + + var batch = new Batch(new[] { logRecords[0] }, 1); + + var request = otlpLogRecordTransformer.BuildExportRequest( + new Proto.Resource.V1.Resource(), + batch); + + Assert.NotNull(request); + Assert.Single(request.ResourceLogs); + Assert.Single(request.ResourceLogs[0].ScopeLogs); + + Assert.Equal(expectedScopeName, request.ResourceLogs[0].ScopeLogs[0].Scope?.Name); + } + private static void RunVerifyEnvironmentVariablesTakenFromIConfigurationTest( string optionsName, Func, (IDisposable Container, ILoggerFactory LoggerFactory)> createLoggerFactoryFunc)