From 81b61556301ef28c870042ffcbf8b48c2bb2519f Mon Sep 17 00:00:00 2001 From: jo <95hyouka@gmail.com> Date: Fri, 3 Oct 2025 15:15:20 +0900 Subject: [PATCH 1/7] add failing test regarding https://github.com/open-telemetry/opentelemetry-dotnet/issues/6558 --- .../OtlpExporterOptionsTests.cs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExporterOptionsTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExporterOptionsTests.cs index 9536d283cf5..77b2d2f0020 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExporterOptionsTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExporterOptionsTests.cs @@ -2,6 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; +using OpenTelemetry.Trace; using Xunit; namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests; @@ -164,6 +168,44 @@ public void OtlpExporterOptions_SetterOverridesEnvironmentVariable() Assert.False(options.AppendSignalPathToEndpoint); } + // https://github.com/open-telemetry/opentelemetry-dotnet/issues/6558 + [Fact] + public void OtlpExporterOptions_EnvironmentVariableAppliedAfterIConfigurationBuilt() + { + var expectedEndpoint = "http://test:4317"; + var host = Host + .CreateDefaultBuilder() + .ConfigureServices((_, services) => + { + Environment.SetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT", expectedEndpoint); + services + .AddOpenTelemetry() + .WithTracing(builder => builder.AddOtlpExporter()); + }) + .Build(); + + var options = host.Services.GetRequiredService>().Value; + + Assert.Equal(new Uri(expectedEndpoint), options.Endpoint); + } + + // https://github.com/open-telemetry/opentelemetry-dotnet/issues/5586 + [Fact] + public void OtlpExporterOptions_EnvironmentVariableAppliedWhenEmptyApplication() + { + var expectedEndpoint = "http://test:4317"; + Environment.SetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT", expectedEndpoint); + var hostBuilder = Host.CreateEmptyApplicationBuilder(settings: null); + hostBuilder.Services + .AddOpenTelemetry() + .WithTracing(builder => builder.AddOtlpExporter()); + var host = hostBuilder.Build(); + + var options = host.Services.GetRequiredService>().Value; + + Assert.Equal(new Uri(expectedEndpoint), options.Endpoint); + } + [Fact] public void OtlpExporterOptions_EndpointGetterUsesProtocolWhenNull() { From c2e3e2df738aeb8e9b6afa5a0f4047e4b717a100 Mon Sep 17 00:00:00 2001 From: jo <95hyouka@gmail.com> Date: Thu, 2 Oct 2025 16:41:28 +0900 Subject: [PATCH 2/7] Fix: Make OtlpExporterOptions pick up env variables When environment variables are set after IConfiguration is built (during WebHost building), even though they are set before exporters are configured, OtlpExporterOptions does not pick them up. This patch fixes the issue. --- .../Implementation/OtlpSpecConfigDefinitions.cs | 2 ++ .../OtlpExporterOptions.cs | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpSpecConfigDefinitions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpSpecConfigDefinitions.cs index 3bc62218b3f..aa1c93c5390 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpSpecConfigDefinitions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpSpecConfigDefinitions.cs @@ -11,6 +11,8 @@ namespace OpenTelemetry.Exporter; /// internal static class OtlpSpecConfigDefinitions { + public const string EnvVarPrefix = "OTEL_"; + public const string DefaultEndpointEnvVarName = "OTEL_EXPORTER_OTLP_ENDPOINT"; public const string DefaultHeadersEnvVarName = "OTEL_EXPORTER_OTLP_HEADERS"; public const string DefaultTimeoutEnvVarName = "OTEL_EXPORTER_OTLP_TIMEOUT"; diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs index 91ebfdbd3e1..05b0288effa 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs @@ -67,8 +67,12 @@ internal OtlpExporterOptions( BatchExportActivityProcessorOptions defaultBatchOptions) { Debug.Assert(defaultBatchOptions != null, "defaultBatchOptions was null"); + var finalConfiguration = new ConfigurationBuilder() + .AddEnvironmentVariables(OtlpSpecConfigDefinitions.EnvVarPrefix) + .AddConfiguration(configuration) + .Build(); - this.ApplyConfiguration(configuration, configurationType); + this.ApplyConfiguration(finalConfiguration, configurationType); this.DefaultHttpClientFactory = () => { From 20d3c388ca5c7f794b66c2fa9aeb44257e16175b Mon Sep 17 00:00:00 2001 From: jo <95hyouka@gmail.com> Date: Thu, 2 Oct 2025 16:48:23 +0900 Subject: [PATCH 3/7] Refactor: Remove confusing unused internal constructor in OtlpExporterOptions The internal constructor was only ever called from the public constructor, and the public constructor itself is only used in tests. This made it easy to assume the internal constructor was part of normal runtime scenarios, which could cause confusion. (in normal runtime scenarios, only the factory method `OtlpExporterOptions.CreateOtlpExporterOptions` is used) Removing it simplifies the code and avoids misleading readers. --- .../OtlpExporterOptions.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs index 05b0288effa..b3192a598d6 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs @@ -48,16 +48,10 @@ public class OtlpExporterOptions : IOtlpExporterOptions /// Initializes a new instance of the class. /// public OtlpExporterOptions() - : this(OtlpExporterOptionsConfigurationType.Default) - { - } - - internal OtlpExporterOptions( - OtlpExporterOptionsConfigurationType configurationType) : this( - configuration: new ConfigurationBuilder().AddEnvironmentVariables().Build(), - configurationType, - defaultBatchOptions: new()) + configuration: new ConfigurationBuilder().Build(), + configurationType: OtlpExporterOptionsConfigurationType.Default, + defaultBatchOptions: new()) { } From 759073092ea81df3404369ae3cc6f15978b82fbc Mon Sep 17 00:00:00 2001 From: jo <95hyouka@gmail.com> Date: Thu, 2 Oct 2025 18:45:50 +0900 Subject: [PATCH 4/7] remove prefix --- .../Implementation/OtlpSpecConfigDefinitions.cs | 2 -- .../OtlpExporterOptions.cs | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpSpecConfigDefinitions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpSpecConfigDefinitions.cs index aa1c93c5390..3bc62218b3f 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpSpecConfigDefinitions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpSpecConfigDefinitions.cs @@ -11,8 +11,6 @@ namespace OpenTelemetry.Exporter; /// internal static class OtlpSpecConfigDefinitions { - public const string EnvVarPrefix = "OTEL_"; - public const string DefaultEndpointEnvVarName = "OTEL_EXPORTER_OTLP_ENDPOINT"; public const string DefaultHeadersEnvVarName = "OTEL_EXPORTER_OTLP_HEADERS"; public const string DefaultTimeoutEnvVarName = "OTEL_EXPORTER_OTLP_TIMEOUT"; diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs index b3192a598d6..069e640d4f7 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs @@ -62,7 +62,7 @@ internal OtlpExporterOptions( { Debug.Assert(defaultBatchOptions != null, "defaultBatchOptions was null"); var finalConfiguration = new ConfigurationBuilder() - .AddEnvironmentVariables(OtlpSpecConfigDefinitions.EnvVarPrefix) + .AddEnvironmentVariables() .AddConfiguration(configuration) .Build(); From ed479a367eefab78ae7187fbedb76f461b9cc2d6 Mon Sep 17 00:00:00 2001 From: jo <95hyouka@gmail.com> Date: Thu, 2 Oct 2025 18:49:24 +0900 Subject: [PATCH 5/7] remove redundant empty configuration creation --- .../OtlpExporterOptions.cs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs index 069e640d4f7..f6893de1d56 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs @@ -49,24 +49,27 @@ public class OtlpExporterOptions : IOtlpExporterOptions /// public OtlpExporterOptions() : this( - configuration: new ConfigurationBuilder().Build(), + configuration: null, configurationType: OtlpExporterOptionsConfigurationType.Default, defaultBatchOptions: new()) { } internal OtlpExporterOptions( - IConfiguration configuration, + IConfiguration? configuration, OtlpExporterOptionsConfigurationType configurationType, BatchExportActivityProcessorOptions defaultBatchOptions) { Debug.Assert(defaultBatchOptions != null, "defaultBatchOptions was null"); - var finalConfiguration = new ConfigurationBuilder() - .AddEnvironmentVariables() - .AddConfiguration(configuration) - .Build(); + var finalConfigurationBuilder = new ConfigurationBuilder() + .AddEnvironmentVariables(); + + if (configuration != null) + { + finalConfigurationBuilder = finalConfigurationBuilder.AddConfiguration(configuration); + } - this.ApplyConfiguration(finalConfiguration, configurationType); + this.ApplyConfiguration(finalConfigurationBuilder.Build(), configurationType); this.DefaultHttpClientFactory = () => { From 28998156b2a586248a537cf32108c13b2dc623d3 Mon Sep 17 00:00:00 2001 From: jo <95hyouka@gmail.com> Date: Thu, 2 Oct 2025 19:04:22 +0900 Subject: [PATCH 6/7] resurrect the internal constructor removed in bdc556e it was used in tests --- .../OtlpExporterOptions.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs index f6893de1d56..4ffaca35b69 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs @@ -48,9 +48,14 @@ public class OtlpExporterOptions : IOtlpExporterOptions /// Initializes a new instance of the class. /// public OtlpExporterOptions() + : this(configurationType: OtlpExporterOptionsConfigurationType.Default) + { + } + + internal OtlpExporterOptions(OtlpExporterOptionsConfigurationType configurationType) : this( configuration: null, - configurationType: OtlpExporterOptionsConfigurationType.Default, + configurationType: configurationType, defaultBatchOptions: new()) { } From b5f8bceaf45b1440ad68d4c807b69c72efda4d8f Mon Sep 17 00:00:00 2001 From: jo <95hyouka@gmail.com> Date: Fri, 3 Oct 2025 15:51:27 +0900 Subject: [PATCH 7/7] update CHANGELOG --- .../CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md index 79d6d1f3b10..2a9fdf13c4e 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md @@ -7,6 +7,12 @@ Notes](../../RELEASENOTES.md). ## Unreleased +* Fixed an issue where `OtlpExporterOptions` did not read environment variables (e.g. `OTEL_EXPORTER_OTLP_ENDPOINT`) + if the environment variables were set after `IConfiguration` was built. + ([#6558](https://github.com/open-telemetry/opentelemetry-dotnet/issues/6558)) + This change also addresses similar issues when .Net `Host` does not load environment variables into `IConfiguration` (e.g. `Host.CreateEmptyApplicationBuilder`). + ([#5586](https://github.com/open-telemetry/opentelemetry-dotnet/issues/5586)) + ## 1.13.0 Released 2025-Oct-01