Skip to content

Commit 890e3f7

Browse files
xiang17RassK
andauthored
Fix bug in OTEL_EXPORTER_OTLP_*_PROTOCOL handling for all signals (#4627)
Co-authored-by: Rasmus Kuusmann <[email protected]>
1 parent f55a74b commit 890e3f7

File tree

4 files changed

+131
-13
lines changed

4 files changed

+131
-13
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ This component adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.h
1313
- Support for [ASP.NET Core 10 metrics](https://learn.microsoft.com/en-us/aspnet/core/log-mon/metrics/built-in?view=aspnetcore-10.0).
1414
- Support for ASP.NET Core 10 Blazor traces from
1515
`Microsoft.AspNetCore.Components`
16-
and `"Microsoft.AspNetCore.Components.Server.Circuits`.
16+
and `Microsoft.AspNetCore.Components.Server.Circuits`.
1717
- Experimental support for file-based configuration.
1818
- Experimental support for configuration based instrumentation.
1919
- IL rewrite for SqlCommand on .NET Framework to ensure `CommandText` is
@@ -102,6 +102,10 @@ and runtime, then loads the correct version of dependency assemblies.
102102
See [#4269](https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/issues/4269)
103103
for details.
104104
- Fixed rule engine check for .NET 9 to reflect longer support for [STS channel](https://devblogs.microsoft.com/dotnet/dotnet-sts-releases-supported-for-24-months/).
105+
- Fix bug in signal specific OTLP exporter variables: `OTEL_EXPORTER_OTLP_TRACES_PROTOCOL`,
106+
`OTEL_EXPORTER_OTLP_METRICS_PROTOCOL` and `OTEL_EXPORTER_OTLP_LOGS_PROTOCOL`.
107+
See [#4593](https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/issues/4593)
108+
for details.
105109

106110
## [1.13.0-beta.1](https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/releases/tag/v1.13.0-beta.1)
107111

src/OpenTelemetry.AutoInstrumentation/AutoInstrumentationEventSource.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public void Information(string message)
4040
WriteEvent(4, message);
4141
}
4242

43-
/// <summary>Logs as Warning level message.</summary>
43+
/// <summary>Logs as Verbose level message.</summary>
4444
/// <param name="message">Message to log.</param>
4545
[Event(5, Message = "{0}", Level = EventLevel.Verbose)]
4646
public void Verbose(string message)

src/OpenTelemetry.AutoInstrumentation/Configurations/Otlp/OtlpSettings.cs

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration;
5+
using OpenTelemetry.AutoInstrumentation.Logging;
56
using OpenTelemetry.Exporter;
67

78
namespace OpenTelemetry.AutoInstrumentation.Configurations.Otlp;
@@ -12,6 +13,8 @@ namespace OpenTelemetry.AutoInstrumentation.Configurations.Otlp;
1213
/// </summary>
1314
internal class OtlpSettings
1415
{
16+
private static readonly IOtelLogger Logger = OtelLogging.GetLogger();
17+
1518
public OtlpSettings(OtlpSignalType signalType, Configuration configuration)
1619
{
1720
Protocol = GetExporterOtlpProtocol(signalType, configuration);
@@ -156,18 +159,37 @@ private static Uri GetOtlpHttpEndpoint(string? endpoint, OtlpSignalType signalTy
156159

157160
private static OtlpExportProtocol? GetExporterOtlpProtocol(OtlpSignalType signalType, Configuration configuration)
158161
{
159-
// the default in SDK is grpc. http/protobuf should be default for our purposes
162+
// http/protobuf should be default for our purposes. Always set a value to avoid relying on SDK, because the default in SDK is grpc.
160163
var priorityVar = OtlpSpecConfigDefinitions.GetProtocolEnvVar(signalType);
161-
var exporterOtlpProtocol = configuration.GetString(priorityVar) ??
162-
configuration.GetString(OtlpSpecConfigDefinitions.DefaultProtocolEnvVarName);
164+
var defaultVar = OtlpSpecConfigDefinitions.DefaultProtocolEnvVarName;
165+
string? usedEnvVarName = priorityVar;
166+
var exporterOtlpProtocol = configuration.GetString(priorityVar);
167+
if (exporterOtlpProtocol == null)
168+
{
169+
exporterOtlpProtocol = configuration.GetString(defaultVar);
170+
usedEnvVarName = defaultVar;
171+
}
163172

164-
if (string.IsNullOrEmpty(exporterOtlpProtocol))
173+
if (!string.IsNullOrEmpty(exporterOtlpProtocol))
165174
{
166-
// override settings only for http/protobuf
167-
return OtlpExportProtocol.HttpProtobuf;
175+
switch (exporterOtlpProtocol)
176+
{
177+
case "grpc":
178+
#if NETFRAMEWORK
179+
Logger.Warning($"OTLP protocol 'grpc' is not supported on .NET Framework in environment variable '{usedEnvVarName}'. Changing to 'http/protobuf' instead.");
180+
return OtlpExportProtocol.HttpProtobuf;
181+
#else
182+
return OtlpExportProtocol.Grpc;
183+
#endif
184+
case "http/protobuf":
185+
return OtlpExportProtocol.HttpProtobuf;
186+
default:
187+
Logger.Warning($"Invalid OTLP protocol value '{exporterOtlpProtocol}' in environment variable '{usedEnvVarName}'. Supported values are 'grpc' and 'http/protobuf'. Defaulting to 'http/protobuf'.");
188+
return OtlpExportProtocol.HttpProtobuf;
189+
}
168190
}
169191

170-
// null value here means that it will be handled by OTEL .NET SDK
171-
return null;
192+
// In case of absent value, it will fall back to default value
193+
return OtlpExportProtocol.HttpProtobuf;
172194
}
173195
}

test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs

Lines changed: 95 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright The OpenTelemetry Authors
22
// SPDX-License-Identifier: Apache-2.0
33

4+
using System.Reflection;
45
using OpenTelemetry.AutoInstrumentation.Configurations;
56
using OpenTelemetry.Exporter;
67
using Xunit;
@@ -379,9 +380,13 @@ internal void IncludeFormattedMessage_DependsOnCorrespondingEnvVariable(string i
379380
[Theory]
380381
[InlineData("", OtlpExportProtocol.HttpProtobuf)]
381382
[InlineData(null, OtlpExportProtocol.HttpProtobuf)]
382-
[InlineData("http/protobuf", null)]
383-
[InlineData("grpc", null)]
384-
[InlineData("nonExistingProtocol", null)]
383+
[InlineData("http/protobuf", OtlpExportProtocol.HttpProtobuf)]
384+
#if NETFRAMEWORK
385+
[InlineData("grpc", OtlpExportProtocol.HttpProtobuf)]
386+
#else
387+
[InlineData("grpc", OtlpExportProtocol.Grpc)]
388+
#endif
389+
[InlineData("nonExistingProtocol", OtlpExportProtocol.HttpProtobuf)]
385390
internal void OtlpExportProtocol_DependsOnCorrespondingEnvVariable(string? otlpProtocol, OtlpExportProtocol? expectedOtlpExportProtocol)
386391
{
387392
Environment.SetEnvironmentVariable(AutoOtlpDefinitions.DefaultProtocolEnvVarName, otlpProtocol);
@@ -393,6 +398,78 @@ internal void OtlpExportProtocol_DependsOnCorrespondingEnvVariable(string? otlpP
393398
Assert.Equal(expectedOtlpExportProtocol, settings.OtlpSettings.Protocol);
394399
}
395400

401+
[Theory]
402+
[InlineData("http/protobuf", "1", "key1=value1,key2=value2", OtlpExportProtocol.HttpProtobuf, 1)]
403+
#if NETFRAMEWORK
404+
[InlineData("grpc", "15000", "a=b,c=d", OtlpExportProtocol.HttpProtobuf, 15000)]
405+
#else
406+
[InlineData("grpc", "15000", "a=b,c=d", OtlpExportProtocol.Grpc, 15000)]
407+
#endif
408+
[InlineData("invalid", "42", "x=y", OtlpExportProtocol.HttpProtobuf, 42)]
409+
internal void OtlpExportProtocol_CheckPriorityEnvIsSet_Traces(string? protocol, string timeout, string headers, OtlpExportProtocol? expectedProtocol, int expectedTimeout)
410+
{
411+
var unexpectedProtocolForDistraction = expectedProtocol == OtlpExportProtocol.HttpProtobuf ? "grpc" : "http/protobuf";
412+
Environment.SetEnvironmentVariable(AutoOtlpDefinitions.DefaultProtocolEnvVarName, unexpectedProtocolForDistraction); // set a different default to verify priority
413+
Environment.SetEnvironmentVariable(AutoOtlpDefinitions.TracesProtocolEnvVarName, protocol);
414+
Environment.SetEnvironmentVariable(AutoOtlpDefinitions.TracesTimeoutEnvVarName, timeout);
415+
Environment.SetEnvironmentVariable(AutoOtlpDefinitions.TracesHeadersEnvVarName, headers);
416+
417+
var settings = Settings.FromDefaultSources<TracerSettings>(false).OtlpSettings;
418+
419+
Assert.NotNull(settings);
420+
Assert.Equal(expectedProtocol, settings.Protocol);
421+
Assert.Equal(expectedTimeout, settings.TimeoutMilliseconds);
422+
Assert.Equal(headers, settings.Headers);
423+
}
424+
425+
[Theory]
426+
[InlineData("http/protobuf", "1", "key1=value1,key2=value2", OtlpExportProtocol.HttpProtobuf, 1)]
427+
#if NETFRAMEWORK
428+
[InlineData("grpc", "25000", "m=n", OtlpExportProtocol.HttpProtobuf, 25000)]
429+
#else
430+
[InlineData("grpc", "25000", "m=n", OtlpExportProtocol.Grpc, 25000)]
431+
#endif
432+
[InlineData("invalid", "100", "a=b", OtlpExportProtocol.HttpProtobuf, 100)]
433+
internal void OtlpExportProtocol_CheckPriorityEnvIsSet_Metrics(string? protocol, string timeout, string headers, OtlpExportProtocol? expectedProtocol, int expectedTimeout)
434+
{
435+
var unexpectedProtocolForDistraction = expectedProtocol == OtlpExportProtocol.HttpProtobuf ? "grpc" : "http/protobuf";
436+
Environment.SetEnvironmentVariable(AutoOtlpDefinitions.DefaultProtocolEnvVarName, unexpectedProtocolForDistraction); // set a different default to verify priority
437+
Environment.SetEnvironmentVariable(AutoOtlpDefinitions.MetricsProtocolEnvVarName, protocol);
438+
Environment.SetEnvironmentVariable(AutoOtlpDefinitions.MetricsTimeoutEnvVarName, timeout);
439+
Environment.SetEnvironmentVariable(AutoOtlpDefinitions.MetricsHeadersEnvVarName, headers);
440+
441+
var settings = Settings.FromDefaultSources<MetricSettings>(false).OtlpSettings;
442+
443+
Assert.NotNull(settings);
444+
Assert.Equal(expectedProtocol, settings.Protocol);
445+
Assert.Equal(expectedTimeout, settings.TimeoutMilliseconds);
446+
Assert.Equal(headers, settings.Headers);
447+
}
448+
449+
[Theory]
450+
[InlineData("http/protobuf", "1", "key1=value1,key2=value2", OtlpExportProtocol.HttpProtobuf, 1)]
451+
#if NETFRAMEWORK
452+
[InlineData("grpc", "5000", "l=m", OtlpExportProtocol.HttpProtobuf, 5000)]
453+
#else
454+
[InlineData("grpc", "5000", "l=m", OtlpExportProtocol.Grpc, 5000)]
455+
#endif
456+
[InlineData("invalid", "77", "z=zz", OtlpExportProtocol.HttpProtobuf, 77)]
457+
internal void OtlpExportProtocol_CheckPriorityEnvIsSet_Logs(string? protocol, string timeout, string headers, OtlpExportProtocol? expectedProtocol, int expectedTimeout)
458+
{
459+
var unexpectedProtocolForDistraction = expectedProtocol == OtlpExportProtocol.HttpProtobuf ? "grpc" : "http/protobuf";
460+
Environment.SetEnvironmentVariable(AutoOtlpDefinitions.DefaultProtocolEnvVarName, unexpectedProtocolForDistraction); // set a different default to verify priority
461+
Environment.SetEnvironmentVariable(AutoOtlpDefinitions.LogsProtocolEnvVarName, protocol);
462+
Environment.SetEnvironmentVariable(AutoOtlpDefinitions.LogsTimeoutEnvVarName, timeout);
463+
Environment.SetEnvironmentVariable(AutoOtlpDefinitions.LogsHeadersEnvVarName, headers);
464+
465+
var settings = Settings.FromDefaultSources<LogSettings>(false).OtlpSettings;
466+
467+
Assert.NotNull(settings);
468+
Assert.Equal(expectedProtocol, settings.Protocol);
469+
Assert.Equal(expectedTimeout, settings.TimeoutMilliseconds);
470+
Assert.Equal(headers, settings.Headers);
471+
}
472+
396473
[Theory]
397474
[InlineData("true", true)]
398475
[InlineData("false", false)]
@@ -477,5 +554,20 @@ private static void ClearEnvVars()
477554
Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.InstrumentationOptions.HttpInstrumentationCaptureRequestHeaders, null);
478555
Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.InstrumentationOptions.HttpInstrumentationCaptureResponseHeaders, null);
479556
Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.InstrumentationOptions.OracleMdaSetDbStatementForText, null);
557+
558+
// Cleanup OTLP env vars
559+
foreach (var envVar in GetAllOtlpEnvVarNames())
560+
{
561+
Environment.SetEnvironmentVariable(envVar, null);
562+
}
563+
}
564+
565+
private static IEnumerable<string> GetAllOtlpEnvVarNames()
566+
{
567+
return typeof(AutoOtlpDefinitions)
568+
.GetFields(BindingFlags.Public | BindingFlags.Static)
569+
.Where(f => f.FieldType == typeof(string))
570+
.Select(f => (string)f.GetValue(null)!)
571+
.ToList() ?? Enumerable.Empty<string>();
480572
}
481573
}

0 commit comments

Comments
 (0)