Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#nullable enable

namespace OpenTelemetry.Exporter;

[Flags]
internal enum OtlpExporterOptionsConfigurationType
{
#pragma warning disable SA1602 // Enumeration items should be documented
Default,
Logs,
Metrics,
Traces,
#pragma warning restore SA1602 // Enumeration items should be documented
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

namespace OpenTelemetry.Exporter;

/// <summary>
/// Contains spec environment variable key definitions for OpenTelemetry Protocol (OTLP) exporter.
/// </summary>
/// <remarks>
/// Specification: <see href="https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md"/>.
/// </remarks>
internal static class OtlpSpecConfigDefinitions
{
public const string DefaultEndpointEnvVarName = "OTEL_EXPORTER_OTLP_ENDPOINT";
public const string DefaultHeadersEnvVarName = "OTEL_EXPORTER_OTLP_HEADERS";
public const string DefaultTimeoutEnvVarName = "OTEL_EXPORTER_OTLP_TIMEOUT";
public const string DefaultProtocolEnvVarName = "OTEL_EXPORTER_OTLP_PROTOCOL";

public const string LogsEndpointEnvVarName = "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT";
public const string LogsHeadersEnvVarName = "OTEL_EXPORTER_OTLP_LOGS_HEADERS";
public const string LogsTimeoutEnvVarName = "OTEL_EXPORTER_OTLP_LOGS_TIMEOUT";
public const string LogsProtocolEnvVarName = "OTEL_EXPORTER_OTLP_LOGS_PROTOCOL";

public const string MetricsEndpointEnvVarName = "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT";
public const string MetricsHeadersEnvVarName = "OTEL_EXPORTER_OTLP_METRICS_HEADERS";
public const string MetricsTimeoutEnvVarName = "OTEL_EXPORTER_OTLP_METRICS_TIMEOUT";
public const string MetricsProtocolEnvVarName = "OTEL_EXPORTER_OTLP_METRICS_PROTOCOL";
public const string MetricsTemporalityPreferenceEnvVarName = "OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE";

public const string TracesEndpointEnvVarName = "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT";
public const string TracesHeadersEnvVarName = "OTEL_EXPORTER_OTLP_TRACES_HEADERS";
public const string TracesTimeoutEnvVarName = "OTEL_EXPORTER_OTLP_TRACES_TIMEOUT";
public const string TracesProtocolEnvVarName = "OTEL_EXPORTER_OTLP_TRACES_PROTOCOL";
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,25 @@ namespace OpenTelemetry.Exporter;

/// <summary>
/// OpenTelemetry Protocol (OTLP) exporter options.
/// OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS, OTEL_EXPORTER_OTLP_TIMEOUT, OTEL_EXPORTER_OTLP_PROTOCOL
/// environment variables are parsed during object construction.
/// </summary>
/// <remarks>
/// Note: OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS,
/// OTEL_EXPORTER_OTLP_TIMEOUT, and OTEL_EXPORTER_OTLP_PROTOCOL environment
/// variables are parsed during object construction.
/// </remarks>
public class OtlpExporterOptions
{
internal const string DefaultGrpcEndpoint = "http://localhost:4317";
internal const string DefaultHttpEndpoint = "http://localhost:4318";
internal const OtlpExportProtocol DefaultOtlpExportProtocol = OtlpExportProtocol.Grpc;

internal static readonly KeyValuePair<string, string>[] StandardHeaders = new KeyValuePair<string, string>[]
{
new KeyValuePair<string, string>("User-Agent", GetUserAgentString()),
};

internal readonly Func<HttpClient> DefaultHttpClientFactory;

private const string DefaultGrpcEndpoint = "http://localhost:4317";
private const string DefaultHttpEndpoint = "http://localhost:4318";
private const OtlpExportProtocol DefaultOtlpExportProtocol = OtlpExportProtocol.Grpc;
private const string UserAgentProduct = "OTel-OTLP-Exporter-Dotnet";

private Uri endpoint;
Expand All @@ -40,39 +44,27 @@ public class OtlpExporterOptions
/// Initializes a new instance of the <see cref="OtlpExporterOptions"/> class.
/// </summary>
public OtlpExporterOptions()
: this(new ConfigurationBuilder().AddEnvironmentVariables().Build(), new())
: this(OtlpExporterOptionsConfigurationType.Default)
{
}

internal OtlpExporterOptions(
OtlpExporterOptionsConfigurationType configurationType)
: this(
configuration: new ConfigurationBuilder().AddEnvironmentVariables().Build(),
configurationType,
defaultBatchOptions: new())
{
}

internal OtlpExporterOptions(
IConfiguration configuration,
OtlpExporterOptionsConfigurationType configurationType,
BatchExportActivityProcessorOptions defaultBatchOptions)
{
Debug.Assert(configuration != null, "configuration was null");
Debug.Assert(defaultBatchOptions != null, "defaultBatchOptions was null");

if (configuration.TryGetUriValue(OtlpExporterSpecEnvVarKeyDefinitions.DefaultEndpointEnvVarName, out var endpoint))
{
this.endpoint = endpoint;
}

if (configuration.TryGetStringValue(OtlpExporterSpecEnvVarKeyDefinitions.DefaultHeadersEnvVarName, out var headers))
{
this.Headers = headers;
}

if (configuration.TryGetIntValue(OtlpExporterSpecEnvVarKeyDefinitions.DefaultTimeoutEnvVarName, out var timeout))
{
this.TimeoutMilliseconds = timeout;
}

if (configuration.TryGetValue<OtlpExportProtocol>(
OtlpExporterSpecEnvVarKeyDefinitions.DefaultProtocolEnvVarName,
OtlpExportProtocolParser.TryParse,
out var protocol))
{
this.Protocol = protocol;
}
this.ApplyConfiguration(configuration, configurationType);

this.HttpClientFactory = this.DefaultHttpClientFactory = () =>
{
Expand All @@ -98,7 +90,7 @@ public Uri Endpoint
{
if (this.endpoint == null)
{
this.endpoint = this.Protocol == OtlpExportProtocol.Grpc
return this.Protocol == OtlpExportProtocol.Grpc
? new Uri(DefaultGrpcEndpoint)
: new Uri(DefaultHttpEndpoint);
}
Expand Down Expand Up @@ -195,8 +187,42 @@ internal static OtlpExporterOptions CreateOtlpExporterOptions(
string name)
=> new(
configuration,
OtlpExporterOptionsConfigurationType.Default,
serviceProvider.GetRequiredService<IOptionsMonitor<BatchExportActivityProcessorOptions>>().Get(name));

internal void ApplyConfigurationUsingSpecificationEnvVars(
IConfiguration configuration,
string endpointEnvVarKey,
bool appendSignalPathToEndpoint,
string protocolEnvVarKey,
string headersEnvVarKey,
string timeoutEnvVarKey)
{
if (configuration.TryGetUriValue(endpointEnvVarKey, out var endpoint))
{
this.endpoint = endpoint;
this.AppendSignalPathToEndpoint = appendSignalPathToEndpoint;
}

if (configuration.TryGetValue<OtlpExportProtocol>(
protocolEnvVarKey,
OtlpExportProtocolParser.TryParse,
out var protocol))
{
this.Protocol = protocol;
}

if (configuration.TryGetStringValue(headersEnvVarKey, out var headers))
{
this.Headers = headers;
}

if (configuration.TryGetIntValue(timeoutEnvVarKey, out var timeout))
{
this.TimeoutMilliseconds = timeout;
}
}

private static string GetUserAgentString()
{
try
Expand All @@ -210,4 +236,60 @@ private static string GetUserAgentString()
return UserAgentProduct;
}
}

private void ApplyConfiguration(
IConfiguration configuration,
OtlpExporterOptionsConfigurationType configurationType)
{
Debug.Assert(configuration != null, "configuration was null");

// Note: When using the "AddOtlpExporter" extensions configurationType
// never has a value other than "Default" because OtlpExporterOptions is
// shared by all signals and there is no way to differentiate which
// signal is being constructed.
if (configurationType == OtlpExporterOptionsConfigurationType.Default)
{
this.ApplyConfigurationUsingSpecificationEnvVars(
Comment thread
vishweshbankwar marked this conversation as resolved.
configuration!,
OtlpSpecConfigDefinitions.DefaultEndpointEnvVarName,
appendSignalPathToEndpoint: true,
OtlpSpecConfigDefinitions.DefaultProtocolEnvVarName,
OtlpSpecConfigDefinitions.DefaultHeadersEnvVarName,
OtlpSpecConfigDefinitions.DefaultTimeoutEnvVarName);
}
else if (configurationType == OtlpExporterOptionsConfigurationType.Logs)
{
this.ApplyConfigurationUsingSpecificationEnvVars(
configuration!,
OtlpSpecConfigDefinitions.LogsEndpointEnvVarName,
appendSignalPathToEndpoint: false,
OtlpSpecConfigDefinitions.LogsProtocolEnvVarName,
OtlpSpecConfigDefinitions.LogsHeadersEnvVarName,
OtlpSpecConfigDefinitions.LogsTimeoutEnvVarName);
}
else if (configurationType == OtlpExporterOptionsConfigurationType.Metrics)
{
this.ApplyConfigurationUsingSpecificationEnvVars(
configuration!,
OtlpSpecConfigDefinitions.MetricsEndpointEnvVarName,
appendSignalPathToEndpoint: false,
OtlpSpecConfigDefinitions.MetricsProtocolEnvVarName,
OtlpSpecConfigDefinitions.MetricsHeadersEnvVarName,
OtlpSpecConfigDefinitions.MetricsTimeoutEnvVarName);
}
else if (configurationType == OtlpExporterOptionsConfigurationType.Traces)
{
this.ApplyConfigurationUsingSpecificationEnvVars(
configuration!,
OtlpSpecConfigDefinitions.TracesEndpointEnvVarName,
appendSignalPathToEndpoint: false,
OtlpSpecConfigDefinitions.TracesProtocolEnvVarName,
OtlpSpecConfigDefinitions.TracesHeadersEnvVarName,
OtlpSpecConfigDefinitions.TracesTimeoutEnvVarName);
}
else
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this code if we don't expect it to called?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a defensive thing. This code is here to alert a future dev who might add a new definition to OtlpExporterOptionsConfigurationType that they need to update this code in order for things to work.

{
throw new NotSupportedException($"OtlpExporterOptionsConfigurationType '{configurationType}' is not supported.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public static MeterProviderBuilder AddOtlpExporter(
services.AddOptions<MetricReaderOptions>(finalOptionsName).Configure<IConfiguration>(
(readerOptions, config) =>
{
var otlpTemporalityPreference = config[OtlpExporterSpecEnvVarKeyDefinitions.MetricsTemporalityPreferenceEnvVarName];
var otlpTemporalityPreference = config[OtlpSpecConfigDefinitions.MetricsTemporalityPreferenceEnvVarName];
if (!string.IsNullOrWhiteSpace(otlpTemporalityPreference)
&& Enum.TryParse<MetricReaderTemporalityPreference>(otlpTemporalityPreference, ignoreCase: true, out var enumValue))
{
Expand Down Expand Up @@ -140,7 +140,7 @@ public static MeterProviderBuilder AddOtlpExporter(
services.AddOptions<MetricReaderOptions>(finalOptionsName).Configure<IConfiguration>(
(readerOptions, config) =>
{
var otlpTemporalityPreference = config[OtlpExporterSpecEnvVarKeyDefinitions.MetricsTemporalityPreferenceEnvVarName];
var otlpTemporalityPreference = config[OtlpSpecConfigDefinitions.MetricsTemporalityPreferenceEnvVarName];
if (!string.IsNullOrWhiteSpace(otlpTemporalityPreference)
&& Enum.TryParse<MetricReaderTemporalityPreference>(otlpTemporalityPreference, ignoreCase: true, out var enumValue))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public void ValidateOtlpHttpExportClientEndpoint(string optionEndpoint, string e
{
try
{
Environment.SetEnvironmentVariable(OtlpExporterSpecEnvVarKeyDefinitions.DefaultEndpointEnvVarName, endpointEnvVar);
Environment.SetEnvironmentVariable(OtlpSpecConfigDefinitions.DefaultEndpointEnvVarName, endpointEnvVar);

OtlpExporterOptions options = new() { Protocol = OtlpExportProtocol.HttpProtobuf };

Expand All @@ -35,7 +35,7 @@ public void ValidateOtlpHttpExportClientEndpoint(string optionEndpoint, string e
}
finally
{
Environment.SetEnvironmentVariable(OtlpExporterSpecEnvVarKeyDefinitions.DefaultEndpointEnvVarName, null);
Environment.SetEnvironmentVariable(OtlpSpecConfigDefinitions.DefaultEndpointEnvVarName, null);
}
}

Expand Down
Loading