From a46a2a9fd1b52829e9906909f7913935d5002637 Mon Sep 17 00:00:00 2001 From: Rasmus Kuusmann Date: Thu, 13 Nov 2025 14:24:00 +0000 Subject: [PATCH 1/5] Fix otlp priority env settings --- .../Configurations/Otlp/OtlpSettings.cs | 40 ++++++++++++++- .../Configurations/SettingsTests.cs | 49 +++++++++++++++++++ 2 files changed, 87 insertions(+), 2 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/Otlp/OtlpSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/Otlp/OtlpSettings.cs index 9d5be2854a..58da8f2f9e 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/Otlp/OtlpSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/Otlp/OtlpSettings.cs @@ -158,8 +158,44 @@ private static Uri GetOtlpHttpEndpoint(string? endpoint, OtlpSignalType signalTy { // the default in SDK is grpc. http/protobuf should be default for our purposes var priorityVar = OtlpSpecConfigDefinitions.GetProtocolEnvVar(signalType); - var exporterOtlpProtocol = configuration.GetString(priorityVar) ?? - configuration.GetString(OtlpSpecConfigDefinitions.DefaultProtocolEnvVarName); + var exporterOtlpProtocol = configuration.GetString(priorityVar); + + // SDK handles only general environment variables. + // In case priority env is set, the value must be maually passed. + if (!string.IsNullOrEmpty(exporterOtlpProtocol)) + { + switch (exporterOtlpProtocol) + { + case "grpc": +#if NETFRAMEWORK + if (configuration.FailFast) + { + throw new ArgumentException( + $"OTLP protocol 'grpc' is not supported on .NET Framework in environment variable '{priorityVar}'. Use 'http/protobuf' instead."); + } + else + { + // null value here means that it will be handled by OTEL .NET SDK + return null; + } +#else + return OtlpExportProtocol.Grpc; +#endif + case "http/protobuf": + return OtlpExportProtocol.HttpProtobuf; + default: + if (configuration.FailFast) + { + throw new ArgumentException( + $"Invalid OTLP protocol value '{exporterOtlpProtocol}' in environment variable '{priorityVar}'. Supported values are 'grpc' and 'http/protobuf'."); + } + + // null value here means that it will be handled by OTEL .NET SDK + return null; + } + } + + exporterOtlpProtocol = configuration.GetString(OtlpSpecConfigDefinitions.DefaultProtocolEnvVarName); if (string.IsNullOrEmpty(exporterOtlpProtocol)) { diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs index e9f2e2f330..563bbc77b0 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 using OpenTelemetry.AutoInstrumentation.Configurations; +using OpenTelemetry.AutoInstrumentation.Configurations.Otlp; using OpenTelemetry.Exporter; using Xunit; @@ -393,6 +394,45 @@ internal void OtlpExportProtocol_DependsOnCorrespondingEnvVariable(string? otlpP Assert.Equal(expectedOtlpExportProtocol, settings.OtlpSettings.Protocol); } + [Fact] + internal void OtlpExportProtocol_CheckPriorityEnvIsSet_Traces() + { + Environment.SetEnvironmentVariable(AutoOtlpDefinitions.TracesEndpointEnvVarName, "http://example.org/traces/v1"); + Environment.SetEnvironmentVariable(AutoOtlpDefinitions.TracesProtocolEnvVarName, "http/protobuf"); + Environment.SetEnvironmentVariable(AutoOtlpDefinitions.TracesTimeoutEnvVarName, "1"); + Environment.SetEnvironmentVariable(AutoOtlpDefinitions.TracesHeadersEnvVarName, "key1=value1,key2=value2"); + + var settings = Settings.FromDefaultSources(false).OtlpSettings; + + VerifyOtlpPrioritySettings(settings); + } + + [Fact] + internal void OtlpExportProtocol_CheckPriorityEnvIsSet_Metrics() + { + Environment.SetEnvironmentVariable(AutoOtlpDefinitions.MetricsEndpointEnvVarName, "http://example.org/traces/v1"); + Environment.SetEnvironmentVariable(AutoOtlpDefinitions.MetricsProtocolEnvVarName, "http/protobuf"); + Environment.SetEnvironmentVariable(AutoOtlpDefinitions.MetricsTimeoutEnvVarName, "1"); + Environment.SetEnvironmentVariable(AutoOtlpDefinitions.MetricsHeadersEnvVarName, "key1=value1,key2=value2"); + + var settings = Settings.FromDefaultSources(false).OtlpSettings; + + VerifyOtlpPrioritySettings(settings); + } + + [Fact] + internal void OtlpExportProtocol_CheckPriorityEnvIsSet_Logs() + { + Environment.SetEnvironmentVariable(AutoOtlpDefinitions.LogsEndpointEnvVarName, "http://example.org/traces/v1"); + Environment.SetEnvironmentVariable(AutoOtlpDefinitions.LogsProtocolEnvVarName, "http/protobuf"); + Environment.SetEnvironmentVariable(AutoOtlpDefinitions.LogsTimeoutEnvVarName, "1"); + Environment.SetEnvironmentVariable(AutoOtlpDefinitions.LogsHeadersEnvVarName, "key1=value1,key2=value2"); + + var settings = Settings.FromDefaultSources(false).OtlpSettings; + + VerifyOtlpPrioritySettings(settings); + } + [Theory] [InlineData("true", true)] [InlineData("false", false)] @@ -478,4 +518,13 @@ private static void ClearEnvVars() Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.InstrumentationOptions.HttpInstrumentationCaptureResponseHeaders, null); Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.InstrumentationOptions.OracleMdaSetDbStatementForText, null); } + + private void VerifyOtlpPrioritySettings(OtlpSettings? settings) + { + Assert.NotNull(settings); + Assert.Equal(new Uri("http://example.org/traces/v1"), settings.Endpoint); + Assert.Equal(OtlpExportProtocol.HttpProtobuf, settings.Protocol); + Assert.Equal(1, settings.TimeoutMilliseconds); + Assert.Equal("key1=value1,key2=value2", settings.Headers); + } } From 9a27a5a061c858100821368921a064eab1982231 Mon Sep 17 00:00:00 2001 From: Rasmus Kuusmann Date: Thu, 13 Nov 2025 14:51:13 +0000 Subject: [PATCH 2/5] Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34d276e214..e6dd45cffa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,9 @@ This component adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.h ### Changed +- Fixed `OTEL_EXPORTER_OTLP_TRACES_PROTOCOL`, `OTEL_EXPORTER_OTLP_METRICS_PROTOCOL` + `OTEL_EXPORTER_OTLP_LOGS_PROTOCOL` handling. See [#4593](https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/issues/4593). + #### Dependency updates - Updated [Core components](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/VERSIONING.md#core-components): From eb2e7c0b09332a4645799ff28209e67ddc05e69b Mon Sep 17 00:00:00 2001 From: Rasmus Kuusmann Date: Thu, 13 Nov 2025 15:07:46 +0000 Subject: [PATCH 3/5] fix tests --- .../Configurations/SettingsTests.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs index 563bbc77b0..dcad7d728c 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs @@ -405,6 +405,7 @@ internal void OtlpExportProtocol_CheckPriorityEnvIsSet_Traces() var settings = Settings.FromDefaultSources(false).OtlpSettings; VerifyOtlpPrioritySettings(settings); + ClearEnvVars(); } [Fact] @@ -418,6 +419,7 @@ internal void OtlpExportProtocol_CheckPriorityEnvIsSet_Metrics() var settings = Settings.FromDefaultSources(false).OtlpSettings; VerifyOtlpPrioritySettings(settings); + ClearEnvVars(); } [Fact] @@ -431,6 +433,7 @@ internal void OtlpExportProtocol_CheckPriorityEnvIsSet_Logs() var settings = Settings.FromDefaultSources(false).OtlpSettings; VerifyOtlpPrioritySettings(settings); + ClearEnvVars(); } [Theory] From 1ef993fc25cbcdcc98ec00e958c8d5511690405f Mon Sep 17 00:00:00 2001 From: Rasmus Kuusmann Date: Thu, 13 Nov 2025 15:23:01 +0000 Subject: [PATCH 4/5] fix tests --- .../Configurations/SettingsTests.cs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs index dcad7d728c..4dbe98998b 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs @@ -1,6 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using System.Reflection; using OpenTelemetry.AutoInstrumentation.Configurations; using OpenTelemetry.AutoInstrumentation.Configurations.Otlp; using OpenTelemetry.Exporter; @@ -405,7 +406,6 @@ internal void OtlpExportProtocol_CheckPriorityEnvIsSet_Traces() var settings = Settings.FromDefaultSources(false).OtlpSettings; VerifyOtlpPrioritySettings(settings); - ClearEnvVars(); } [Fact] @@ -419,7 +419,6 @@ internal void OtlpExportProtocol_CheckPriorityEnvIsSet_Metrics() var settings = Settings.FromDefaultSources(false).OtlpSettings; VerifyOtlpPrioritySettings(settings); - ClearEnvVars(); } [Fact] @@ -433,7 +432,6 @@ internal void OtlpExportProtocol_CheckPriorityEnvIsSet_Logs() var settings = Settings.FromDefaultSources(false).OtlpSettings; VerifyOtlpPrioritySettings(settings); - ClearEnvVars(); } [Theory] @@ -520,6 +518,21 @@ private static void ClearEnvVars() Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.InstrumentationOptions.HttpInstrumentationCaptureRequestHeaders, null); Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.InstrumentationOptions.HttpInstrumentationCaptureResponseHeaders, null); Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.InstrumentationOptions.OracleMdaSetDbStatementForText, null); + + // Cleanup OTLP env vars + foreach (var envVar in GetAllOtlpEnvVarNames()) + { + Environment.SetEnvironmentVariable(envVar, null); + } + } + + private static IEnumerable GetAllOtlpEnvVarNames() + { + return typeof(AutoOtlpDefinitions) + .GetFields(BindingFlags.Public | BindingFlags.Static) + .Where(f => f.FieldType == typeof(string)) + .Select(f => (string)f.GetValue(null)!) + .ToList() ?? Enumerable.Empty(); } private void VerifyOtlpPrioritySettings(OtlpSettings? settings) From a60d87cb894e9c09ab003c88d1c8b82890c785c1 Mon Sep 17 00:00:00 2001 From: Rasmus Kuusmann Date: Thu, 13 Nov 2025 15:48:46 +0000 Subject: [PATCH 5/5] refactor tests --- .../Configurations/SettingsTests.cs | 65 +++++++++++-------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs index 4dbe98998b..02d39a206a 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs @@ -398,40 +398,43 @@ internal void OtlpExportProtocol_DependsOnCorrespondingEnvVariable(string? otlpP [Fact] internal void OtlpExportProtocol_CheckPriorityEnvIsSet_Traces() { - Environment.SetEnvironmentVariable(AutoOtlpDefinitions.TracesEndpointEnvVarName, "http://example.org/traces/v1"); - Environment.SetEnvironmentVariable(AutoOtlpDefinitions.TracesProtocolEnvVarName, "http/protobuf"); - Environment.SetEnvironmentVariable(AutoOtlpDefinitions.TracesTimeoutEnvVarName, "1"); - Environment.SetEnvironmentVariable(AutoOtlpDefinitions.TracesHeadersEnvVarName, "key1=value1,key2=value2"); - - var settings = Settings.FromDefaultSources(false).OtlpSettings; + VerifyOtlpPrioritySettings(((string Endpoint, string Protocol, string Timeout, string Headers) values) => + { + Environment.SetEnvironmentVariable(AutoOtlpDefinitions.TracesEndpointEnvVarName, values.Endpoint); + Environment.SetEnvironmentVariable(AutoOtlpDefinitions.TracesProtocolEnvVarName, values.Protocol); + Environment.SetEnvironmentVariable(AutoOtlpDefinitions.TracesTimeoutEnvVarName, values.Timeout); + Environment.SetEnvironmentVariable(AutoOtlpDefinitions.TracesHeadersEnvVarName, values.Headers); - VerifyOtlpPrioritySettings(settings); + return Settings.FromDefaultSources(false).OtlpSettings; + }); } [Fact] internal void OtlpExportProtocol_CheckPriorityEnvIsSet_Metrics() { - Environment.SetEnvironmentVariable(AutoOtlpDefinitions.MetricsEndpointEnvVarName, "http://example.org/traces/v1"); - Environment.SetEnvironmentVariable(AutoOtlpDefinitions.MetricsProtocolEnvVarName, "http/protobuf"); - Environment.SetEnvironmentVariable(AutoOtlpDefinitions.MetricsTimeoutEnvVarName, "1"); - Environment.SetEnvironmentVariable(AutoOtlpDefinitions.MetricsHeadersEnvVarName, "key1=value1,key2=value2"); - - var settings = Settings.FromDefaultSources(false).OtlpSettings; + VerifyOtlpPrioritySettings(((string Endpoint, string Protocol, string Timeout, string Headers) values) => + { + Environment.SetEnvironmentVariable(AutoOtlpDefinitions.MetricsEndpointEnvVarName, values.Endpoint); + Environment.SetEnvironmentVariable(AutoOtlpDefinitions.MetricsProtocolEnvVarName, values.Protocol); + Environment.SetEnvironmentVariable(AutoOtlpDefinitions.MetricsTimeoutEnvVarName, values.Timeout); + Environment.SetEnvironmentVariable(AutoOtlpDefinitions.MetricsHeadersEnvVarName, values.Headers); - VerifyOtlpPrioritySettings(settings); + return Settings.FromDefaultSources(false).OtlpSettings; + }); } [Fact] internal void OtlpExportProtocol_CheckPriorityEnvIsSet_Logs() { - Environment.SetEnvironmentVariable(AutoOtlpDefinitions.LogsEndpointEnvVarName, "http://example.org/traces/v1"); - Environment.SetEnvironmentVariable(AutoOtlpDefinitions.LogsProtocolEnvVarName, "http/protobuf"); - Environment.SetEnvironmentVariable(AutoOtlpDefinitions.LogsTimeoutEnvVarName, "1"); - Environment.SetEnvironmentVariable(AutoOtlpDefinitions.LogsHeadersEnvVarName, "key1=value1,key2=value2"); - - var settings = Settings.FromDefaultSources(false).OtlpSettings; + VerifyOtlpPrioritySettings(((string Endpoint, string Protocol, string Timeout, string Headers) values) => + { + Environment.SetEnvironmentVariable(AutoOtlpDefinitions.LogsEndpointEnvVarName, values.Endpoint); + Environment.SetEnvironmentVariable(AutoOtlpDefinitions.LogsProtocolEnvVarName, values.Protocol); + Environment.SetEnvironmentVariable(AutoOtlpDefinitions.LogsTimeoutEnvVarName, values.Timeout); + Environment.SetEnvironmentVariable(AutoOtlpDefinitions.LogsHeadersEnvVarName, values.Headers); - VerifyOtlpPrioritySettings(settings); + return Settings.FromDefaultSources(false).OtlpSettings; + }); } [Theory] @@ -535,12 +538,22 @@ private static IEnumerable GetAllOtlpEnvVarNames() .ToList() ?? Enumerable.Empty(); } - private void VerifyOtlpPrioritySettings(OtlpSettings? settings) + private static void VerifyOtlpPrioritySettings(Func<(string Endpoint, string Protocol, string Timeout, string Headers), OtlpSettings?> setup) { + var endpoint = "http://example.org/traces/v1"; + var endpointValue = new Uri(endpoint); + var protocol = "http/protobuf"; + var protocolValue = OtlpExportProtocol.HttpProtobuf; + var timeout = "1"; + var timeoutValue = 1; + var headers = "key1=value1,key2=value2"; + + var settings = setup((endpoint, protocol, timeout, headers)); + Assert.NotNull(settings); - Assert.Equal(new Uri("http://example.org/traces/v1"), settings.Endpoint); - Assert.Equal(OtlpExportProtocol.HttpProtobuf, settings.Protocol); - Assert.Equal(1, settings.TimeoutMilliseconds); - Assert.Equal("key1=value1,key2=value2", settings.Headers); + Assert.Equal(endpointValue, settings.Endpoint); + Assert.Equal(protocolValue, settings.Protocol); + Assert.Equal(timeoutValue, settings.TimeoutMilliseconds); + Assert.Equal(headers, settings.Headers); } }