diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index a11f9108e92..063db0361b4 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -6,6 +6,11 @@ Notes](../../RELEASENOTES.md). ## Unreleased +* Added support for the `OTEL_SDK_DISABLED` environment variable in TracerProvider, + MeterProvider, and LoggerProvider. When `OTEL_SDK_DISABLED=true`, + the SDK returns no-op implementations for all telemetry signals. + ([#6568](https://github.com/open-telemetry/opentelemetry-dotnet/pull/6568)) + ## 1.13.0 Released 2025-Oct-01 diff --git a/src/OpenTelemetry/Logs/Builder/LoggerProviderBuilderBase.cs b/src/OpenTelemetry/Logs/Builder/LoggerProviderBuilderBase.cs index d2a7149fe69..9a0cf3db9ad 100644 --- a/src/OpenTelemetry/Logs/Builder/LoggerProviderBuilderBase.cs +++ b/src/OpenTelemetry/Logs/Builder/LoggerProviderBuilderBase.cs @@ -1,9 +1,11 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using OpenTelemetry.Internal; +using static OpenTelemetry.OpenTelemetrySdk; namespace OpenTelemetry.Logs; @@ -91,6 +93,14 @@ internal LoggerProvider Build() bool validateScopes = false; #endif var serviceProvider = services.BuildServiceProvider(validateScopes); + var configuration = serviceProvider.GetRequiredService(); + configuration.TryGetStringValue(SdkConfigDefinitions.SdkDisableEnvVarName, out var envVarValue); + + if (bool.TryParse(envVarValue, out bool result) && result) + { + serviceProvider.Dispose(); + return new NoopLoggerProvider(); + } return new LoggerProviderSdk(serviceProvider, ownsServiceProvider: true); } diff --git a/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderBase.cs b/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderBase.cs index 097cbc372c2..de8297b6cd5 100644 --- a/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderBase.cs +++ b/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderBase.cs @@ -1,9 +1,11 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using OpenTelemetry.Internal; +using static OpenTelemetry.OpenTelemetrySdk; namespace OpenTelemetry.Metrics; @@ -108,6 +110,14 @@ protected MeterProvider Build() bool validateScopes = false; #endif var serviceProvider = services.BuildServiceProvider(validateScopes); + var configuration = serviceProvider.GetRequiredService(); + configuration.TryGetStringValue(SdkConfigDefinitions.SdkDisableEnvVarName, out var envVarValue); + + if (bool.TryParse(envVarValue, out bool result) && result) + { + serviceProvider.Dispose(); + return new NoopMeterProvider(); + } return new MeterProviderSdk(serviceProvider, ownsServiceProvider: true); } diff --git a/src/OpenTelemetry/SdkConfigDefinitions.cs b/src/OpenTelemetry/SdkConfigDefinitions.cs new file mode 100644 index 00000000000..5ae0402e634 --- /dev/null +++ b/src/OpenTelemetry/SdkConfigDefinitions.cs @@ -0,0 +1,9 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +namespace OpenTelemetry; + +internal static class SdkConfigDefinitions +{ + public const string SdkDisableEnvVarName = "OTEL_SDK_DISABLED"; +} diff --git a/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderBase.cs b/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderBase.cs index 894ebe7b265..e1e19c14064 100644 --- a/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderBase.cs +++ b/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderBase.cs @@ -1,9 +1,11 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using OpenTelemetry.Internal; +using static OpenTelemetry.OpenTelemetrySdk; namespace OpenTelemetry.Trace; @@ -146,6 +148,14 @@ protected TracerProvider Build() bool validateScopes = false; #endif var serviceProvider = services.BuildServiceProvider(validateScopes); + var configuration = serviceProvider.GetRequiredService(); + configuration.TryGetStringValue(SdkConfigDefinitions.SdkDisableEnvVarName, out var envVarValue); + + if (bool.TryParse(envVarValue, out bool result) && result) + { + serviceProvider.Dispose(); + return new NoopTracerProvider(); + } return new TracerProviderSdk(serviceProvider, ownsServiceProvider: true); } diff --git a/test/OpenTelemetry.Tests/EnvironmentVariableScope.cs b/test/OpenTelemetry.Tests/EnvironmentVariableScope.cs new file mode 100644 index 00000000000..fb9f9a8c2cb --- /dev/null +++ b/test/OpenTelemetry.Tests/EnvironmentVariableScope.cs @@ -0,0 +1,17 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +internal sealed class EnvironmentVariableScope : IDisposable +{ + private readonly string name; + private readonly string? previous; + + public EnvironmentVariableScope(string name, string? value) + { + this.name = name; + this.previous = Environment.GetEnvironmentVariable(name); + Environment.SetEnvironmentVariable(name, value); + } + + public void Dispose() => Environment.SetEnvironmentVariable(this.name, this.previous); +} diff --git a/test/OpenTelemetry.Tests/Logs/LoggerProviderBuilderBaseTests.cs b/test/OpenTelemetry.Tests/Logs/LoggerProviderBuilderBaseTests.cs new file mode 100644 index 00000000000..8a5fd806bba --- /dev/null +++ b/test/OpenTelemetry.Tests/Logs/LoggerProviderBuilderBaseTests.cs @@ -0,0 +1,26 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using Xunit; +using static OpenTelemetry.OpenTelemetrySdk; + +namespace OpenTelemetry.Logs.Tests; + +public sealed class LoggerProviderBuilderBaseTests +{ + [Theory] + [InlineData("true", typeof(NoopLoggerProvider))] + [InlineData("false", typeof(LoggerProviderSdk))] + [InlineData(null, typeof(LoggerProviderSdk))] + public void LoggerProviderIsExpectedType(string? value, Type expected) + { + using (new EnvironmentVariableScope("OTEL_SDK_DISABLED", value)) + { + var builder = new LoggerProviderBuilderBase(); + + using var provider = builder.Build(); + + Assert.IsType(expected, provider); + } + } +} diff --git a/test/OpenTelemetry.Tests/Metrics/MeterProviderBuilderBaseTests.cs b/test/OpenTelemetry.Tests/Metrics/MeterProviderBuilderBaseTests.cs new file mode 100644 index 00000000000..617bd4a0efc --- /dev/null +++ b/test/OpenTelemetry.Tests/Metrics/MeterProviderBuilderBaseTests.cs @@ -0,0 +1,26 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using Xunit; +using static OpenTelemetry.OpenTelemetrySdk; + +namespace OpenTelemetry.Metrics.Tests; + +public sealed class MeterProviderBuilderBaseTests +{ + [Theory] + [InlineData("true", typeof(NoopMeterProvider))] + [InlineData("false", typeof(MeterProviderSdk))] + [InlineData(null, typeof(MeterProviderSdk))] + public void LoggerProviderIsExpectedType(string? value, Type expected) + { + using (new EnvironmentVariableScope("OTEL_SDK_DISABLED", value)) + { + var builder = new MeterProviderBuilderBase(); + + using var provider = builder.Build(); + + Assert.IsType(expected, provider); + } + } +} diff --git a/test/OpenTelemetry.Tests/Trace/TracerProviderBuilderBaseTests.cs b/test/OpenTelemetry.Tests/Trace/TracerProviderBuilderBaseTests.cs index ed9a337c6b3..9b6d5e7c2ac 100644 --- a/test/OpenTelemetry.Tests/Trace/TracerProviderBuilderBaseTests.cs +++ b/test/OpenTelemetry.Tests/Trace/TracerProviderBuilderBaseTests.cs @@ -2,11 +2,28 @@ // SPDX-License-Identifier: Apache-2.0 using Xunit; +using static OpenTelemetry.OpenTelemetrySdk; namespace OpenTelemetry.Trace.Tests; -public class TracerProviderBuilderBaseTests +public sealed class TracerProviderBuilderBaseTests { + [Theory] + [InlineData("true", typeof(NoopTracerProvider))] + [InlineData("false", typeof(TracerProviderSdk))] + [InlineData(null, typeof(TracerProviderSdk))] + public void TracerProviderIsExpectedType(string? value, Type expected) + { + using (new EnvironmentVariableScope("OTEL_SDK_DISABLED", value)) + { + var builder = new TestTracerProviderBuilder(); + + using var provider = builder.Build(); + + Assert.IsType(expected, provider); + } + } + [Fact] public void AddInstrumentationInvokesFactoryTest() {