Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/OpenTelemetry/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ Notes](../../RELEASENOTES.md).
file is truncated or the log volume runs out of space.
([#7956](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7956))

* **Experimental (pre-release builds only):** Fixed `Logger.EmitLog` ignoring
instrumentation suppression, which could cause recursive exports or deadlocks.
([#7961](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7961))

## 1.20.0

Released 2026-Oct-15
Expand Down
5 changes: 5 additions & 0 deletions src/OpenTelemetry/Logs/LoggerSdk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ public LoggerSdk(
/// <inheritdoc />
public override void EmitLog(in LogRecordData data, in LogRecordAttributeList attributes)
{
if (Sdk.SuppressInstrumentation)
{
return;
}

var provider = this.loggerProvider;
var processor = provider.Processor;
if (processor != null)
Expand Down
69 changes: 69 additions & 0 deletions test/OpenTelemetry.Tests/Logs/LoggerProviderSdkTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry.Exporter;
using OpenTelemetry.Tests;

namespace OpenTelemetry.Logs.Tests;

Expand Down Expand Up @@ -51,6 +52,74 @@ public void ForceFlushTest()
Assert.Single(exportedItems);
}

[Theory]
[InlineData(false)]
[InlineData(true)]
public void EmitLogRespectsSuppressInstrumentationTest(bool includeAttributes)
{
List<LogRecord> exportedItems = [];

using var provider = Sdk.CreateLoggerProviderBuilder()
.AddInMemoryExporter(exportedItems)
.Build();

var logger = provider.GetLogger("TestLogger");

using (SuppressInstrumentationScope.Begin())
{
if (includeAttributes)
{
logger.EmitLog(new() { Body = "Suppressed" }, new() { { "key", "value" } });
}
else
{
logger.EmitLog(new() { Body = "Suppressed" });
}
}

Assert.Empty(exportedItems);

logger.EmitLog(new() { Body = "Hello world" });

var logRecord = Assert.Single(exportedItems);
Assert.Equal("Hello world", logRecord.Body);
}

[Theory]
[InlineData(ExportResult.Success)]
[InlineData(ExportResult.Failure)]
public void EmitLogDuringExportIsNotFedBackIntoPipelineTest(ExportResult exportResult)
{
Logger? logger = null;
var exportCount = 0;

using var provider = Sdk.CreateLoggerProviderBuilder()
#pragma warning disable CA2000 // Dispose objects before losing scope
.AddProcessor(new SimpleLogRecordExportProcessor(new DelegatingExporter<LogRecord>
{
OnExportFunc = batch =>
{
using var scope = SuppressInstrumentationScope.Begin();

// Bound recursion so the regression cannot overflow the test host's stack.
if (++exportCount < 3)
{
logger!.EmitLog(new() { Body = "Emitted during export" });
}

return exportResult;
},
}))
#pragma warning restore CA2000 // Dispose objects before losing scope
.Build();

logger = provider.GetLogger("TestLogger");

logger.EmitLog(new() { Body = "Hello world" });

Assert.Equal(1, exportCount);
}

[Fact]
public void ThreadStaticPoolUsedByProviderTests()
{
Expand Down
Loading