diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index 8ac2f28309d..198df8c2c70 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -6,6 +6,10 @@ 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)) * Fixed an issue where the Base2 Exponential Bucket Histogram did not reset its scale to 20 after each collection cycle when using delta aggregation temporality. ([#6557](https://github.com/open-telemetry/opentelemetry-dotnet/pull/6557)) diff --git a/src/OpenTelemetry/Logs/Builder/LoggerProviderBuilderBase.cs b/src/OpenTelemetry/Logs/Builder/LoggerProviderBuilderBase.cs index d2a7149fe69..f2208cc9da3 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; @@ -39,7 +41,15 @@ internal LoggerProviderBuilderBase(IServiceCollection services) services .AddOpenTelemetryLoggerProviderBuilderServices() - .TryAddSingleton(sp => new LoggerProviderSdk(sp, ownsServiceProvider: false)); + .TryAddSingleton(sp => + { + if (IsOtelSdkDisabled(sp.GetRequiredService())) + { + return new NoopLoggerProvider(); + } + + return new LoggerProviderSdk(sp, ownsServiceProvider: false); + }); this.innerBuilder = new LoggerProviderServiceCollectionBuilder(services); @@ -91,7 +101,25 @@ internal LoggerProvider Build() bool validateScopes = false; #endif var serviceProvider = services.BuildServiceProvider(validateScopes); + var configuration = serviceProvider.GetRequiredService(); + + if (IsOtelSdkDisabled(configuration)) + { + serviceProvider.Dispose(); + return new NoopLoggerProvider(); + } return new LoggerProviderSdk(serviceProvider, ownsServiceProvider: true); } + + private static bool IsOtelSdkDisabled(IConfiguration configuration) + { + bool isDisabled = configuration.TryGetBoolValue(OpenTelemetrySdkEventSource.Log, SdkConfigDefinitions.SdkDisableEnvVarName, out bool result) && result; + if (isDisabled) + { + OpenTelemetrySdkEventSource.Log.LoggerProviderSdkEvent($"Disabled because {SdkConfigDefinitions.SdkDisableEnvVarName} is true."); + } + + return isDisabled; + } } diff --git a/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderBase.cs b/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderBase.cs index 097cbc372c2..c5f04b8fbd1 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; @@ -39,7 +41,15 @@ internal MeterProviderBuilderBase(IServiceCollection services) services .AddOpenTelemetryMeterProviderBuilderServices() - .TryAddSingleton(sp => new MeterProviderSdk(sp, ownsServiceProvider: false)); + .TryAddSingleton(sp => + { + if (IsOtelSdkDisabled(sp.GetRequiredService())) + { + return new NoopMeterProvider(); + } + + return new MeterProviderSdk(sp, ownsServiceProvider: false); + }); this.innerBuilder = new MeterProviderServiceCollectionBuilder(services); @@ -108,7 +118,25 @@ protected MeterProvider Build() bool validateScopes = false; #endif var serviceProvider = services.BuildServiceProvider(validateScopes); + var configuration = serviceProvider.GetRequiredService(); + + if (IsOtelSdkDisabled(configuration)) + { + serviceProvider.Dispose(); + return new NoopMeterProvider(); + } return new MeterProviderSdk(serviceProvider, ownsServiceProvider: true); } + + private static bool IsOtelSdkDisabled(IConfiguration configuration) + { + bool isDisabled = configuration.TryGetBoolValue(OpenTelemetrySdkEventSource.Log, SdkConfigDefinitions.SdkDisableEnvVarName, out bool result) && result; + if (isDisabled) + { + OpenTelemetrySdkEventSource.Log.MeterProviderSdkEvent($"Disabled because {SdkConfigDefinitions.SdkDisableEnvVarName} is true."); + } + + return isDisabled; + } } 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..d2a5230d3b5 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; @@ -39,7 +41,15 @@ internal TracerProviderBuilderBase(IServiceCollection services) services .AddOpenTelemetryTracerProviderBuilderServices() - .TryAddSingleton(sp => new TracerProviderSdk(sp, ownsServiceProvider: false)); + .TryAddSingleton(sp => + { + if (IsOtelSdkDisabled(sp.GetRequiredService())) + { + return new NoopTracerProvider(); + } + + return new TracerProviderSdk(sp, ownsServiceProvider: false); + }); this.innerBuilder = new TracerProviderServiceCollectionBuilder(services); @@ -146,7 +156,25 @@ protected TracerProvider Build() bool validateScopes = false; #endif var serviceProvider = services.BuildServiceProvider(validateScopes); + var configuration = serviceProvider.GetRequiredService(); + + if (IsOtelSdkDisabled(configuration)) + { + serviceProvider.Dispose(); + return new NoopTracerProvider(); + } return new TracerProviderSdk(serviceProvider, ownsServiceProvider: true); } + + private static bool IsOtelSdkDisabled(IConfiguration configuration) + { + bool isDisabled = configuration.TryGetBoolValue(OpenTelemetrySdkEventSource.Log, SdkConfigDefinitions.SdkDisableEnvVarName, out bool result) && result; + if (isDisabled) + { + OpenTelemetrySdkEventSource.Log.TracerProviderSdkEvent($"Disabled because {SdkConfigDefinitions.SdkDisableEnvVarName} is true."); + } + + return isDisabled; + } } 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() {