From fdbd47587974df01758182a86b672bcd9a0b7e49 Mon Sep 17 00:00:00 2001 From: neistow Date: Tue, 19 Aug 2025 21:34:36 +0300 Subject: [PATCH] Refactor OpenTelemetryEnvironment to use respsect specific endpoint variables for logs and traces. --- .../Configuration/OpenTelemetryEnvironment.cs | 78 +++++++++++++------ .../OpenTelemetryEnvironmentVariables.cs | 15 ++++ .../OpenTelemetryEnvironmentTests.cs | 47 ++++++++--- 3 files changed, 106 insertions(+), 34 deletions(-) create mode 100644 src/Serilog.Sinks.OpenTelemetry/Sinks/OpenTelemetry/Configuration/OpenTelemetryEnvironmentVariables.cs diff --git a/src/Serilog.Sinks.OpenTelemetry/Sinks/OpenTelemetry/Configuration/OpenTelemetryEnvironment.cs b/src/Serilog.Sinks.OpenTelemetry/Sinks/OpenTelemetry/Configuration/OpenTelemetryEnvironment.cs index 7c9c5c4..2a5cb22 100644 --- a/src/Serilog.Sinks.OpenTelemetry/Sinks/OpenTelemetry/Configuration/OpenTelemetryEnvironment.cs +++ b/src/Serilog.Sinks.OpenTelemetry/Sinks/OpenTelemetry/Configuration/OpenTelemetryEnvironment.cs @@ -16,49 +16,81 @@ namespace Serilog.Sinks.OpenTelemetry.Configuration; static class OpenTelemetryEnvironment { - const string ProtocolVarName = "OTEL_EXPORTER_OTLP_PROTOCOL"; - const string EndpointVarName = "OTEL_EXPORTER_OTLP_ENDPOINT"; - const string HeaderVarName = "OTEL_EXPORTER_OTLP_HEADERS"; - const string ResourceAttributesVarName = "OTEL_RESOURCE_ATTRIBUTES"; - const string ServiceNameVarName = "OTEL_SERVICE_NAME"; - public static void Configure(BatchedOpenTelemetrySinkOptions options, Func getConfigurationVariable) { - options.Protocol = getConfigurationVariable(ProtocolVarName) switch - { - "http/protobuf" => OtlpProtocol.HttpProtobuf, - "grpc" => OtlpProtocol.Grpc, - _ => options.Protocol - }; + if (ParseProtocol(getConfigurationVariable(OpenTelemetryEnvironmentVariables.DefaultProtocol)) is { } protocol) + options.Protocol = protocol; - if (getConfigurationVariable(EndpointVarName) is { Length: > 1 } endpoint) + if (getConfigurationVariable(OpenTelemetryEnvironmentVariables.DefaultEndpoint) is { Length: > 1 } endpoint) options.Endpoint = endpoint; - FillHeadersIfPresent(getConfigurationVariable(HeaderVarName), options.Headers); + FillLogsConfigUsingSpecificationEnvVars(options, getConfigurationVariable); - FillHeadersResourceAttributesIfPresent(getConfigurationVariable(ResourceAttributesVarName), options.ResourceAttributes); + FillTracesConfigUsingSpecificationEnvVars(options, getConfigurationVariable); - if (getConfigurationVariable(ServiceNameVarName) is { Length: > 1 } serviceName) + FillDictionary( + options.Headers, + getConfigurationVariable, + OpenTelemetryEnvironmentVariables.DefaultHeaders); + + FillDictionary( + options.ResourceAttributes, + getConfigurationVariable, + OpenTelemetryEnvironmentVariables.ResourceAttributes); + + if (getConfigurationVariable(OpenTelemetryEnvironmentVariables.ServiceName) is { Length: > 1 } serviceName) { options.ResourceAttributes[SemanticConventions.AttributeServiceName] = serviceName; } } - static void FillHeadersIfPresent(string? config, IDictionary headers) + static OtlpProtocol? ParseProtocol(string? protocol) + { + return protocol switch + { + "http/protobuf" => OtlpProtocol.HttpProtobuf, + "grpc" => OtlpProtocol.Grpc, + _ => null + }; + } + + static void FillLogsConfigUsingSpecificationEnvVars( + BatchedOpenTelemetrySinkOptions options, + Func getConfigurationVariable) + { + options.LogsEndpoint = getConfigurationVariable(OpenTelemetryEnvironmentVariables.LogsEndpoint); + } + + static void FillTracesConfigUsingSpecificationEnvVars( + BatchedOpenTelemetrySinkOptions options, + Func getConfigurationVariable) + { + options.TracesEndpoint = getConfigurationVariable(OpenTelemetryEnvironmentVariables.TracesEndpoint); + } + + static void FillDictionary( + IDictionary dictionary, + Func getConfigurationVariable, + string environmentVariableName) { + var config = getConfigurationVariable(environmentVariableName); if (config == null) return; - foreach (var (key, value) in BaggageFormat.DecodeBaggageString(config, HeaderVarName)) + foreach (var (key, value) in BaggageFormat.DecodeBaggageString(config, environmentVariableName)) { - headers[key] = value; + dictionary[key] = value; } } - static void FillHeadersResourceAttributesIfPresent(string? config, IDictionary resourceAttributes) + static void FillDictionary( + IDictionary dictionary, + Func getConfigurationVariable, + string environmentVariableName) { + var config = getConfigurationVariable(environmentVariableName); if (config == null) return; - foreach (var (key, value) in BaggageFormat.DecodeBaggageString(config, ResourceAttributesVarName)) + foreach (var (key, value) in BaggageFormat.DecodeBaggageString(config, environmentVariableName)) { - resourceAttributes[key] = value; + dictionary[key] = value; } } -} +} \ No newline at end of file diff --git a/src/Serilog.Sinks.OpenTelemetry/Sinks/OpenTelemetry/Configuration/OpenTelemetryEnvironmentVariables.cs b/src/Serilog.Sinks.OpenTelemetry/Sinks/OpenTelemetry/Configuration/OpenTelemetryEnvironmentVariables.cs new file mode 100644 index 0000000..e9f6d8d --- /dev/null +++ b/src/Serilog.Sinks.OpenTelemetry/Sinks/OpenTelemetry/Configuration/OpenTelemetryEnvironmentVariables.cs @@ -0,0 +1,15 @@ +namespace Serilog.Sinks.OpenTelemetry.Configuration; + +static class OpenTelemetryEnvironmentVariables +{ + public const string DefaultEndpoint = "OTEL_EXPORTER_OTLP_ENDPOINT"; + public const string DefaultHeaders = "OTEL_EXPORTER_OTLP_HEADERS"; + public const string DefaultProtocol = "OTEL_EXPORTER_OTLP_PROTOCOL"; + + public const string LogsEndpoint = "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT"; + + public const string TracesEndpoint = "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"; + + public const string ServiceName = "OTEL_SERVICE_NAME"; + public const string ResourceAttributes = "OTEL_RESOURCE_ATTRIBUTES"; +} \ No newline at end of file diff --git a/test/Serilog.Sinks.OpenTelemetry.Tests/OpenTelemetryEnvironmentTests.cs b/test/Serilog.Sinks.OpenTelemetry.Tests/OpenTelemetryEnvironmentTests.cs index 98dc9d2..1ff51e2 100644 --- a/test/Serilog.Sinks.OpenTelemetry.Tests/OpenTelemetryEnvironmentTests.cs +++ b/test/Serilog.Sinks.OpenTelemetry.Tests/OpenTelemetryEnvironmentTests.cs @@ -5,6 +5,31 @@ namespace Serilog.Sinks.OpenTelemetry.Tests; public class OpenTelemetryEnvironmentTests { + [Fact] + public void ConfigureRespectsSpecificEndpointEnvironmentVariableValues() + { + BatchedOpenTelemetrySinkOptions options = new(); + + var generalEndpoint = "http://general"; + var logSpecificEndpoint = "http://log-specific"; + var tracesSpecificEndpoint = "http://traces-specific"; + + OpenTelemetryEnvironment.Configure(options, GetEnvVar); + + Assert.Equal(generalEndpoint, options.Endpoint); + Assert.Equal(logSpecificEndpoint, options.LogsEndpoint); + Assert.Equal(tracesSpecificEndpoint, options.TracesEndpoint); + return; + + string? GetEnvVar(string name) => name switch + { + OpenTelemetryEnvironmentVariables.DefaultEndpoint => generalEndpoint, + OpenTelemetryEnvironmentVariables.LogsEndpoint => logSpecificEndpoint, + OpenTelemetryEnvironmentVariables.TracesEndpoint => tracesSpecificEndpoint, + _ => null + }; + } + [Fact] public void ConfigureFillsOptionsWithEnvironmentVariableValues() { @@ -30,11 +55,11 @@ public void ConfigureFillsOptionsWithEnvironmentVariableValues() string? GetEnvVar(string name) => name switch { - "OTEL_EXPORTER_OTLP_ENDPOINT" => endpoint, - "OTEL_EXPORTER_OTLP_HEADERS" => headers, - "OTEL_RESOURCE_ATTRIBUTES" => resourceAttributes, - "OTEL_EXPORTER_OTLP_PROTOCOL" => "grpc", - "OTEL_SERVICE_NAME" => serviceName, + OpenTelemetryEnvironmentVariables.DefaultEndpoint => endpoint, + OpenTelemetryEnvironmentVariables.DefaultHeaders => headers, + OpenTelemetryEnvironmentVariables.ResourceAttributes => resourceAttributes, + OpenTelemetryEnvironmentVariables.DefaultProtocol => "grpc", + OpenTelemetryEnvironmentVariables.ServiceName => serviceName, _ => null }; } @@ -54,8 +79,8 @@ public void ExplicitServiceNameOverridesResourceAttribute() string? GetEnvVar(string name) => name switch { - "OTEL_RESOURCE_ATTRIBUTES" => resourceAttributes, - "OTEL_SERVICE_NAME" => serviceName, + OpenTelemetryEnvironmentVariables.ResourceAttributes => resourceAttributes, + OpenTelemetryEnvironmentVariables.ServiceName => serviceName, _ => null }; } @@ -76,8 +101,8 @@ public void ConfigureAppendPathToEndpointIfProtocolIsHttpProtobufAndEndpointDoes string? GetEnvVar(string name) => name switch { - "OTEL_EXPORTER_OTLP_ENDPOINT" => endpoint, - "OTEL_EXPORTER_OTLP_PROTOCOL" => "http/protobuf", + OpenTelemetryEnvironmentVariables.DefaultEndpoint => endpoint, + OpenTelemetryEnvironmentVariables.DefaultProtocol => "http/protobuf", _ => null }; } @@ -95,7 +120,7 @@ public void ConfigureThrowsIfHeaderEnvIsInvalidFormat() string? GetEnvVar(string name) => name switch { - "OTEL_EXPORTER_OTLP_HEADERS" => headers, + OpenTelemetryEnvironmentVariables.DefaultHeaders => headers, _ => null }; } @@ -113,7 +138,7 @@ public void ConfigureThrowsIfResourceAttributesEnvIsInvalidFormat() string? GetEnvVar(string name) => name switch { - "OTEL_RESOURCE_ATTRIBUTES" => resourceAttributes, + OpenTelemetryEnvironmentVariables.ResourceAttributes => resourceAttributes, _ => null }; }