diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md index 25703ccc4c3..878fadd3638 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md @@ -16,6 +16,10 @@ Released 2022-Oct-17 are configured via the environment variables defined in the specification. ([#3684](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3684)) +* Added support for loading environment variables from `IConfiguration` when + using the `AddOtlpExporter` extensions + ([#3760](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3760)) + ## 1.4.0-beta.1 Released 2022-Sep-29 diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Configuration/EnvironmentVariableConfiguration.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Configuration/EnvironmentVariableConfiguration.cs deleted file mode 100644 index dd6cbc7ee9e..00000000000 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Configuration/EnvironmentVariableConfiguration.cs +++ /dev/null @@ -1,46 +0,0 @@ -// -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -using System; -using OpenTelemetry.Internal; - -namespace OpenTelemetry.Configuration; - -internal class EnvironmentVariableConfiguration -{ - public static void InitializeDefaultConfigurationFromEnvironment(SdkConfiguration sdkConfiguration) - { - // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#attribute-limits - SetIntConfigValue("OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT", value => sdkConfiguration.AttributeValueLengthLimit = value); - SetIntConfigValue("OTEL_ATTRIBUTE_COUNT_LIMIT", value => sdkConfiguration.AttributeCountLimit = value); - - // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#span-limits - SetIntConfigValue("OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT", value => sdkConfiguration.SpanAttributeValueLengthLimit = value); - SetIntConfigValue("OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT", value => sdkConfiguration.SpanAttributeCountLimit = value); - SetIntConfigValue("OTEL_SPAN_EVENT_COUNT_LIMIT", value => sdkConfiguration.SpanEventCountLimit = value); - SetIntConfigValue("OTEL_SPAN_LINK_COUNT_LIMIT", value => sdkConfiguration.SpanLinkCountLimit = value); - SetIntConfigValue("OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT", value => sdkConfiguration.EventAttributeCountLimit = value); - SetIntConfigValue("OTEL_LINK_ATTRIBUTE_COUNT_LIMIT", value => sdkConfiguration.LinkAttributeCountLimit = value); - } - - private static void SetIntConfigValue(string key, Action setter) - { - if (EnvironmentVariableHelper.LoadNumeric(key, out var result)) - { - setter(result); - } - } -} diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Configuration/SdkConfiguration.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Configuration/SdkConfiguration.cs deleted file mode 100644 index a7772bcd532..00000000000 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Configuration/SdkConfiguration.cs +++ /dev/null @@ -1,69 +0,0 @@ -// -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -namespace OpenTelemetry.Configuration; - -internal class SdkConfiguration -{ - private int? spanAttributeValueLengthLimit; - private int? spanAttributeCountLimit; - private int? eventAttributeCountLimit; - private int? linkAttributeCountLimit; - - private SdkConfiguration() - { - EnvironmentVariableConfiguration.InitializeDefaultConfigurationFromEnvironment(this); - } - - public static SdkConfiguration Instance { get; private set; } = new SdkConfiguration(); - - public int? AttributeValueLengthLimit { get; set; } - - public int? AttributeCountLimit { get; set; } - - public int? SpanAttributeValueLengthLimit - { - get => this.spanAttributeValueLengthLimit ?? this.AttributeValueLengthLimit; - set => this.spanAttributeValueLengthLimit = value; - } - - public int? SpanAttributeCountLimit - { - get => this.spanAttributeCountLimit ?? this.AttributeCountLimit; - set => this.spanAttributeCountLimit = value; - } - - public int? SpanEventCountLimit { get; set; } - - public int? SpanLinkCountLimit { get; set; } - - public int? EventAttributeCountLimit - { - get => this.eventAttributeCountLimit ?? this.SpanAttributeCountLimit; - set => this.eventAttributeCountLimit = value; - } - - public int? LinkAttributeCountLimit - { - get => this.linkAttributeCountLimit ?? this.SpanAttributeCountLimit; - set => this.linkAttributeCountLimit = value; - } - - internal static void Reset() - { - Instance = new SdkConfiguration(); - } -} diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs index c5a24dfa2a4..a1ad5e64e30 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs @@ -24,7 +24,6 @@ using System.Runtime.CompilerServices; using Google.Protobuf; using Google.Protobuf.Collections; -using OpenTelemetry.Configuration; using OpenTelemetry.Internal; using OpenTelemetry.Proto.Collector.Trace.V1; using OpenTelemetry.Proto.Common.V1; @@ -42,6 +41,7 @@ internal static class ActivityExtensions internal static void AddBatch( this ExportTraceServiceRequest request, + SdkLimitOptions sdkLimitOptions, Resource processResource, in Batch activityBatch) { @@ -54,7 +54,7 @@ internal static void AddBatch( foreach (var activity in activityBatch) { - Span span = activity.ToOtlpSpan(); + Span span = activity.ToOtlpSpan(sdkLimitOptions); if (span == null) { OpenTelemetryProtocolExporterEventSource.Log.CouldNotTranslateActivity( @@ -116,7 +116,7 @@ internal static ScopeSpans GetSpanListFromPool(string name, string version) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Span ToOtlpSpan(this Activity activity) + internal static Span ToOtlpSpan(this Activity activity, SdkLimitOptions sdkLimitOptions) { if (activity.IdFormat != ActivityIdFormat.W3C) { @@ -157,9 +157,10 @@ internal static Span ToOtlpSpan(this Activity activity) TagEnumerationState otlpTags = new() { + SdkLimitOptions = sdkLimitOptions, Span = otlpSpan, }; - otlpTags.EnumerateTags(activity, SdkConfiguration.Instance.SpanAttributeCountLimit ?? int.MaxValue); + otlpTags.EnumerateTags(activity, sdkLimitOptions.SpanAttributeCountLimit ?? int.MaxValue); if (activity.Kind == ActivityKind.Client || activity.Kind == ActivityKind.Producer) { @@ -180,15 +181,17 @@ internal static Span ToOtlpSpan(this Activity activity) EventEnumerationState otlpEvents = new() { + SdkLimitOptions = sdkLimitOptions, Span = otlpSpan, }; - otlpEvents.EnumerateEvents(activity, SdkConfiguration.Instance.SpanEventCountLimit ?? int.MaxValue); + otlpEvents.EnumerateEvents(activity, sdkLimitOptions.SpanEventCountLimit ?? int.MaxValue); LinkEnumerationState otlpLinks = new() { + SdkLimitOptions = sdkLimitOptions, Span = otlpSpan, }; - otlpLinks.EnumerateLinks(activity, SdkConfiguration.Instance.SpanLinkCountLimit ?? int.MaxValue); + otlpLinks.EnumerateLinks(activity, sdkLimitOptions.SpanLinkCountLimit ?? int.MaxValue); return otlpSpan; } @@ -236,7 +239,7 @@ private static OtlpTrace.Status ToOtlpStatus(this Activity activity, ref TagEnum } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Span.Types.Link ToOtlpLink(in ActivityLink activityLink) + private static Span.Types.Link ToOtlpLink(in ActivityLink activityLink, SdkLimitOptions sdkLimitOptions) { byte[] traceIdBytes = new byte[16]; byte[] spanIdBytes = new byte[8]; @@ -250,10 +253,10 @@ private static Span.Types.Link ToOtlpLink(in ActivityLink activityLink) SpanId = UnsafeByteOperations.UnsafeWrap(spanIdBytes), }; - int maxTags = SdkConfiguration.Instance.LinkAttributeCountLimit ?? int.MaxValue; + int maxTags = sdkLimitOptions.SpanLinkAttributeCountLimit ?? int.MaxValue; foreach (ref readonly var tag in activityLink.EnumerateTagObjects()) { - if (OtlpKeyValueTransformer.Instance.TryTransformTag(tag, out var attribute, SdkConfiguration.Instance.AttributeValueLengthLimit)) + if (OtlpKeyValueTransformer.Instance.TryTransformTag(tag, out var attribute, sdkLimitOptions.AttributeValueLengthLimit)) { if (otlpLink.Attributes.Count < maxTags) { @@ -270,7 +273,7 @@ private static Span.Types.Link ToOtlpLink(in ActivityLink activityLink) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Span.Types.Event ToOtlpEvent(in ActivityEvent activityEvent) + private static Span.Types.Event ToOtlpEvent(in ActivityEvent activityEvent, SdkLimitOptions sdkLimitOptions) { var otlpEvent = new Span.Types.Event { @@ -278,10 +281,10 @@ private static Span.Types.Event ToOtlpEvent(in ActivityEvent activityEvent) TimeUnixNano = (ulong)activityEvent.Timestamp.ToUnixTimeNanoseconds(), }; - int maxTags = SdkConfiguration.Instance.EventAttributeCountLimit ?? int.MaxValue; + int maxTags = sdkLimitOptions.SpanEventAttributeCountLimit ?? int.MaxValue; foreach (ref readonly var tag in activityEvent.EnumerateTagObjects()) { - if (OtlpKeyValueTransformer.Instance.TryTransformTag(tag, out var attribute, SdkConfiguration.Instance.AttributeValueLengthLimit)) + if (OtlpKeyValueTransformer.Instance.TryTransformTag(tag, out var attribute, sdkLimitOptions.AttributeValueLengthLimit)) { if (otlpEvent.Attributes.Count < maxTags) { @@ -320,6 +323,8 @@ private static Action, int> CreateRepeatedFieldOfSpanSetCoun private struct TagEnumerationState : PeerServiceResolver.IPeerServiceState { + public SdkLimitOptions SdkLimitOptions; + public Span Span; public string StatusCode; @@ -357,7 +362,7 @@ public void EnumerateTags(Activity activity, int maxTags) continue; } - if (OtlpKeyValueTransformer.Instance.TryTransformTag(tag, out var attribute, SdkConfiguration.Instance.AttributeValueLengthLimit)) + if (OtlpKeyValueTransformer.Instance.TryTransformTag(tag, out var attribute, this.SdkLimitOptions.AttributeValueLengthLimit)) { if (this.Span.Attributes.Count < maxTags) { @@ -384,6 +389,8 @@ public void EnumerateTags(Activity activity, int maxTags) private struct EventEnumerationState { + public SdkLimitOptions SdkLimitOptions; + public Span Span; public void EnumerateEvents(Activity activity, int maxEvents) @@ -392,7 +399,7 @@ public void EnumerateEvents(Activity activity, int maxEvents) { if (this.Span.Events.Count < maxEvents) { - this.Span.Events.Add(ToOtlpEvent(in @event)); + this.Span.Events.Add(ToOtlpEvent(in @event, this.SdkLimitOptions)); } else { @@ -404,6 +411,8 @@ public void EnumerateEvents(Activity activity, int maxEvents) private struct LinkEnumerationState { + public SdkLimitOptions SdkLimitOptions; + public Span Span; public void EnumerateLinks(Activity activity, int maxLinks) @@ -412,7 +421,7 @@ public void EnumerateLinks(Activity activity, int maxLinks) { if (this.Span.Links.Count < maxLinks) { - this.Span.Links.Add(ToOtlpLink(in link)); + this.Span.Links.Add(ToOtlpLink(in link, this.SdkLimitOptions)); } else { diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/LogRecordExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/LogRecordExtensions.cs index e674b30f7ad..b7d289f8f28 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/LogRecordExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/LogRecordExtensions.cs @@ -19,7 +19,6 @@ using System.Runtime.CompilerServices; using Google.Protobuf; using Microsoft.Extensions.Logging; -using OpenTelemetry.Configuration; using OpenTelemetry.Internal; using OpenTelemetry.Logs; using OpenTelemetry.Trace; @@ -39,6 +38,7 @@ internal static class LogRecordExtensions internal static void AddBatch( this OtlpCollector.ExportLogsServiceRequest request, + SdkLimitOptions sdkLimitOptions, OtlpResource.Resource processResource, in Batch logRecordBatch) { @@ -53,7 +53,7 @@ internal static void AddBatch( foreach (var logRecord in logRecordBatch) { - var otlpLogRecord = logRecord.ToOtlpLog(); + var otlpLogRecord = logRecord.ToOtlpLog(sdkLimitOptions); if (otlpLogRecord != null) { scopeLogs.LogRecords.Add(otlpLogRecord); @@ -62,7 +62,7 @@ internal static void AddBatch( } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static OtlpLogs.LogRecord ToOtlpLog(this LogRecord logRecord) + internal static OtlpLogs.LogRecord ToOtlpLog(this LogRecord logRecord, SdkLimitOptions sdkLimitOptions) { OtlpLogs.LogRecord otlpLogRecord = null; @@ -75,8 +75,8 @@ internal static OtlpLogs.LogRecord ToOtlpLog(this LogRecord logRecord) SeverityText = LogLevels[(int)logRecord.LogLevel], }; - var attributeValueLengthLimit = SdkConfiguration.Instance.AttributeValueLengthLimit; - var attributeCountLimit = SdkConfiguration.Instance.AttributeCountLimit ?? int.MaxValue; + var attributeValueLengthLimit = sdkLimitOptions.AttributeValueLengthLimit; + var attributeCountLimit = sdkLimitOptions.AttributeCountLimit ?? int.MaxValue; // First add the generic attributes like category, eventid and exception, so they are less likely being dropped because of AttributeCountLimit diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/SdkLimitOptions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/SdkLimitOptions.cs new file mode 100644 index 00000000000..305af1780d5 --- /dev/null +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/SdkLimitOptions.cs @@ -0,0 +1,125 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using Microsoft.Extensions.Configuration; +using OpenTelemetry.Internal; + +namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation; + +internal sealed class SdkLimitOptions +{ + private int? spanAttributeValueLengthLimit; + private int? spanAttributeCountLimit; + private int? spanEventAttributeCountLimit; + private int? spanLinkAttributeCountLimit; + + internal SdkLimitOptions() + : this(new ConfigurationBuilder().AddEnvironmentVariables().Build()) + { + } + + internal SdkLimitOptions(IConfiguration configuration) + { + // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#attribute-limits + SetIntConfigValue(configuration, "OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT", value => this.AttributeValueLengthLimit = value); + SetIntConfigValue(configuration, "OTEL_ATTRIBUTE_COUNT_LIMIT", value => this.AttributeCountLimit = value); + + // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#span-limits + SetIntConfigValue(configuration, "OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT", value => this.SpanAttributeValueLengthLimit = value); + SetIntConfigValue(configuration, "OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT", value => this.SpanAttributeCountLimit = value); + SetIntConfigValue(configuration, "OTEL_SPAN_EVENT_COUNT_LIMIT", value => this.SpanEventCountLimit = value); + SetIntConfigValue(configuration, "OTEL_SPAN_LINK_COUNT_LIMIT", value => this.SpanLinkCountLimit = value); + SetIntConfigValue(configuration, "OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT", value => this.SpanEventAttributeCountLimit = value); + SetIntConfigValue(configuration, "OTEL_LINK_ATTRIBUTE_COUNT_LIMIT", value => this.SpanLinkAttributeCountLimit = value); + } + + /// + /// Gets or sets the maximum allowed attribute value size. + /// + public int? AttributeValueLengthLimit { get; set; } + + /// + /// Gets or sets the maximum allowed attribute count. + /// + public int? AttributeCountLimit { get; set; } + + /// + /// Gets or sets the maximum allowed span attribute value size. + /// + /// + /// Note: Overrides the setting for spans if specified. + /// + public int? SpanAttributeValueLengthLimit + { + get => this.spanAttributeValueLengthLimit ?? this.AttributeValueLengthLimit; + set => this.spanAttributeValueLengthLimit = value; + } + + /// + /// Gets or sets the maximum allowed span attribute count. + /// + /// + /// Note: Overrides the setting for spans if specified. + /// + public int? SpanAttributeCountLimit + { + get => this.spanAttributeCountLimit ?? this.AttributeCountLimit; + set => this.spanAttributeCountLimit = value; + } + + /// + /// Gets or sets the maximum allowed span event count. + /// + public int? SpanEventCountLimit { get; set; } + + /// + /// Gets or sets the maximum allowed span link count. + /// + public int? SpanLinkCountLimit { get; set; } + + /// + /// Gets or sets the maximum allowed span event attribute count. + /// + /// + /// Note: Overrides the setting for span events if specified. + /// + public int? SpanEventAttributeCountLimit + { + get => this.spanEventAttributeCountLimit ?? this.SpanAttributeCountLimit; + set => this.spanEventAttributeCountLimit = value; + } + + /// + /// Gets or sets the maximum allowed span link attribute count. + /// + /// + /// Note: Overrides the setting for span links if specified. + /// + public int? SpanLinkAttributeCountLimit + { + get => this.spanLinkAttributeCountLimit ?? this.SpanAttributeCountLimit; + set => this.spanLinkAttributeCountLimit = value; + } + + private static void SetIntConfigValue(IConfiguration configuration, string key, Action setter) + { + if (configuration.TryGetIntValue(key, out var result)) + { + setter(result); + } + } +} diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj index 529e72b586f..995d2b02298 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj @@ -34,7 +34,7 @@ - + diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs index 936da811fa4..67871fbf492 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs @@ -17,6 +17,7 @@ using System; using System.Diagnostics; using System.Net.Http; +using Microsoft.Extensions.Configuration; using OpenTelemetry.Internal; using OpenTelemetry.Metrics; using OpenTelemetry.Trace; @@ -51,32 +52,33 @@ public class OtlpExporterOptions /// Initializes a new instance of the class. /// public OtlpExporterOptions() + : this(new ConfigurationBuilder().AddEnvironmentVariables().Build()) { - if (EnvironmentVariableHelper.LoadUri(EndpointEnvVarName, out Uri parsedEndpoint)) + } + + internal OtlpExporterOptions(IConfiguration configuration) + { + if (configuration.TryGetUriValue(EndpointEnvVarName, out var endpoint)) { - this.endpoint = parsedEndpoint; + this.endpoint = endpoint; } - if (EnvironmentVariableHelper.LoadString(HeadersEnvVarName, out string headersEnvVar)) + if (configuration.TryGetStringValue(HeadersEnvVarName, out var headers)) { - this.Headers = headersEnvVar; + this.Headers = headers; } - if (EnvironmentVariableHelper.LoadNumeric(TimeoutEnvVarName, out int timeout)) + if (configuration.TryGetIntValue(TimeoutEnvVarName, out var timeout)) { this.TimeoutMilliseconds = timeout; } - if (EnvironmentVariableHelper.LoadString(ProtocolEnvVarName, out string protocolEnvVar)) + if (configuration.TryGetValue( + ProtocolEnvVarName, + OtlpExportProtocolParser.TryParse, + out var protocol)) { - if (OtlpExportProtocolParser.TryParse(protocolEnvVar, out var protocol)) - { - this.Protocol = protocol; - } - else - { - throw new FormatException($"{ProtocolEnvVarName} environment variable has an invalid value: '{protocolEnvVar}'"); - } + this.Protocol = protocol; } this.HttpClientFactory = this.DefaultHttpClientFactory = () => diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporter.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporter.cs index 0e146110414..8bcde202e7f 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporter.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporter.cs @@ -15,6 +15,7 @@ // using System; +using System.Diagnostics; using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation; using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient; using OpenTelemetry.Logs; @@ -29,6 +30,7 @@ namespace OpenTelemetry.Exporter /// internal class OtlpLogExporter : BaseExporter { + private readonly SdkLimitOptions sdkLimitOptions; private readonly IExportClient exportClient; private OtlpResource.Resource processResource; @@ -38,24 +40,33 @@ internal class OtlpLogExporter : BaseExporter /// /// Configuration options for the exporter. public OtlpLogExporter(OtlpExporterOptions options) - : this(options, null) + : this(options, new(), null) { } /// /// Initializes a new instance of the class. /// - /// Configuration options for the exporter. + /// Configuration options for the exporter. + /// . /// Client used for sending export request. - internal OtlpLogExporter(OtlpExporterOptions options, IExportClient exportClient = null) + internal OtlpLogExporter( + OtlpExporterOptions exporterOptions, + SdkLimitOptions sdkLimitOptions, + IExportClient exportClient = null) { + Debug.Assert(exporterOptions != null, "exporterOptions was null"); + Debug.Assert(sdkLimitOptions != null, "sdkLimitOptions was null"); + + this.sdkLimitOptions = sdkLimitOptions; + if (exportClient != null) { this.exportClient = exportClient; } else { - this.exportClient = options.GetLogExportClient(); + this.exportClient = exporterOptions.GetLogExportClient(); } } @@ -71,7 +82,7 @@ public override ExportResult Export(in Batch logRecordBatch) try { - request.AddBatch(this.ProcessResource, logRecordBatch); + request.AddBatch(this.sdkLimitOptions, this.ProcessResource, logRecordBatch); if (!this.exportClient.SendExportRequest(request)) { diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporterExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporterExtensions.cs index d3d45402c19..741314ab8b4 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporterExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporterExtensions.cs @@ -60,10 +60,15 @@ public static MeterProviderBuilder AddOtlpExporter( name ??= Options.DefaultName; - if (configureExporter != null) + builder.ConfigureServices(services => { - builder.ConfigureServices(services => services.Configure(name, configureExporter)); - } + if (configureExporter != null) + { + services.Configure(name, configureExporter); + } + + services.RegisterOptionsFactory(configuration => new OtlpExporterOptions(configuration)); + }); return builder.ConfigureBuilder((sp, builder) => { @@ -106,6 +111,11 @@ public static MeterProviderBuilder AddOtlpExporter( name ??= Options.DefaultName; + builder.ConfigureServices(services => + { + services.RegisterOptionsFactory(configuration => new OtlpExporterOptions(configuration)); + }); + return builder.ConfigureBuilder((sp, builder) => { var exporterOptions = sp.GetRequiredService>().Get(name); diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporter.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporter.cs index 01cb49bd4f8..156c366e6c9 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporter.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporter.cs @@ -29,6 +29,7 @@ namespace OpenTelemetry.Exporter /// public class OtlpTraceExporter : BaseExporter { + private readonly SdkLimitOptions sdkLimitOptions; private readonly IExportClient exportClient; private OtlpResource.Resource processResource; @@ -38,24 +39,33 @@ public class OtlpTraceExporter : BaseExporter /// /// Configuration options for the export. public OtlpTraceExporter(OtlpExporterOptions options) - : this(options, null) + : this(options, new(), null) { } /// /// Initializes a new instance of the class. /// - /// Configuration options for the export. + /// . + /// . /// Client used for sending export request. - internal OtlpTraceExporter(OtlpExporterOptions options, IExportClient exportClient = null) + internal OtlpTraceExporter( + OtlpExporterOptions exporterOptions, + SdkLimitOptions sdkLimitOptions, + IExportClient exportClient = null) { + Debug.Assert(exporterOptions != null, "exporterOptions was null"); + Debug.Assert(sdkLimitOptions != null, "sdkLimitOptions was null"); + + this.sdkLimitOptions = sdkLimitOptions; + if (exportClient != null) { this.exportClient = exportClient; } else { - this.exportClient = options.GetTraceExportClient(); + this.exportClient = exporterOptions.GetTraceExportClient(); } } @@ -71,7 +81,7 @@ public override ExportResult Export(in Batch activityBatch) try { - request.AddBatch(this.ProcessResource, activityBatch); + request.AddBatch(this.sdkLimitOptions, this.ProcessResource, activityBatch); if (!this.exportClient.SendExportRequest(request)) { diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporterHelperExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporterHelperExtensions.cs index 807b7633f2a..889fe7fca5d 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporterHelperExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporterHelperExtensions.cs @@ -19,6 +19,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using OpenTelemetry.Exporter; +using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation; using OpenTelemetry.Internal; namespace OpenTelemetry.Trace @@ -61,28 +62,40 @@ public static TracerProviderBuilder AddOtlpExporter( name ??= Options.DefaultName; - if (configure != null) + builder.ConfigureServices(services => { - builder.ConfigureServices(services => services.Configure(name, configure)); - } + if (configure != null) + { + services.Configure(name, configure); + } + + services.RegisterOptionsFactory(configuration => new SdkLimitOptions(configuration)); + services.RegisterOptionsFactory(configuration => new OtlpExporterOptions(configuration)); + }); return builder.ConfigureBuilder((sp, builder) => { - var options = sp.GetRequiredService>().Get(name); + var exporterOptions = sp.GetRequiredService>().Get(name); + + // Note: Not using name here for SdkLimitOptions. There should + // only be one provider for a given service collection so + // SdkLimitOptions is treated as a single default instance. + var sdkOptionsManager = sp.GetRequiredService>().CurrentValue; - AddOtlpExporter(builder, options, sp); + AddOtlpExporter(builder, exporterOptions, sdkOptionsManager, sp); }); } internal static TracerProviderBuilder AddOtlpExporter( TracerProviderBuilder builder, OtlpExporterOptions exporterOptions, + SdkLimitOptions sdkLimitOptions, IServiceProvider serviceProvider, Func, BaseExporter> configureExporterInstance = null) { exporterOptions.TryEnableIHttpClientFactoryIntegration(serviceProvider, "OtlpTraceExporter"); - BaseExporter otlpExporter = new OtlpTraceExporter(exporterOptions); + BaseExporter otlpExporter = new OtlpTraceExporter(exporterOptions, sdkLimitOptions); if (configureExporterInstance != null) { diff --git a/src/OpenTelemetry/Internal/Builder/ProviderBuilderServiceCollectionExtensions.cs b/src/OpenTelemetry/Internal/Builder/ProviderBuilderServiceCollectionExtensions.cs index ab136d3a4f0..f08c48c9395 100644 --- a/src/OpenTelemetry/Internal/Builder/ProviderBuilderServiceCollectionExtensions.cs +++ b/src/OpenTelemetry/Internal/Builder/ProviderBuilderServiceCollectionExtensions.cs @@ -19,6 +19,8 @@ using System.Diagnostics; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection.Extensions; +using OpenTelemetry.Internal; +using OpenTelemetry.Metrics; namespace Microsoft.Extensions.DependencyInjection; @@ -39,4 +41,13 @@ public static IServiceCollection AddOpenTelemetryProviderBuilderServices(this IS return services!; } + + public static IServiceCollection AddOpenTelemetryMeterProviderBuilderServices(this IServiceCollection services) + { + services.AddOpenTelemetryProviderBuilderServices(); + + services.RegisterOptionsFactory(configuration => new MetricReaderOptions(configuration)); + + return services; + } } diff --git a/src/OpenTelemetry/Internal/PeriodicExportingMetricReaderHelper.cs b/src/OpenTelemetry/Internal/PeriodicExportingMetricReaderHelper.cs index 0fa1fc9058b..5514871993c 100644 --- a/src/OpenTelemetry/Internal/PeriodicExportingMetricReaderHelper.cs +++ b/src/OpenTelemetry/Internal/PeriodicExportingMetricReaderHelper.cs @@ -14,15 +14,11 @@ // limitations under the License. // -using OpenTelemetry.Internal; - namespace OpenTelemetry.Metrics; internal static class PeriodicExportingMetricReaderHelper { - internal const string OTelMetricExportIntervalEnvVarKey = "OTEL_METRIC_EXPORT_INTERVAL"; internal const int DefaultExportIntervalMilliseconds = 60000; - internal const string OTelMetricExportTimeoutEnvVarKey = "OTEL_METRIC_EXPORT_TIMEOUT"; internal const int DefaultExportTimeoutMilliseconds = 30000; internal static PeriodicExportingMetricReader CreatePeriodicExportingMetricReader( @@ -31,15 +27,11 @@ internal static PeriodicExportingMetricReader CreatePeriodicExportingMetricReade int defaultExportIntervalMilliseconds = DefaultExportIntervalMilliseconds, int defaultExportTimeoutMilliseconds = DefaultExportTimeoutMilliseconds) { - var exportInterval = GetValue( - options.PeriodicExportingMetricReaderOptions?.ExportIntervalMilliseconds, - OTelMetricExportIntervalEnvVarKey, - defaultExportIntervalMilliseconds); + var exportInterval = + options.PeriodicExportingMetricReaderOptions?.ExportIntervalMilliseconds ?? defaultExportIntervalMilliseconds; - var exportTimeout = GetValue( - options.PeriodicExportingMetricReaderOptions?.ExportTimeoutMilliseconds, - OTelMetricExportTimeoutEnvVarKey, - defaultExportTimeoutMilliseconds); + var exportTimeout = + options.PeriodicExportingMetricReaderOptions?.ExportTimeoutMilliseconds ?? defaultExportTimeoutMilliseconds; var metricReader = new PeriodicExportingMetricReader(exporter, exportInterval, exportTimeout) { @@ -48,19 +40,4 @@ internal static PeriodicExportingMetricReader CreatePeriodicExportingMetricReade return metricReader; } - - private static int GetValue(int? optionsValue, string envVarKey, int defaultValue) - { - if (optionsValue.HasValue) - { - return optionsValue.Value; - } - - if (EnvironmentVariableHelper.LoadNumeric(envVarKey, out var envVarValue)) - { - return envVarValue; - } - - return defaultValue; - } } diff --git a/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderBase.cs b/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderBase.cs index 80482d7b5cd..9d98c308566 100644 --- a/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderBase.cs +++ b/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderBase.cs @@ -52,7 +52,8 @@ internal MeterProviderBuilderBase(IServiceCollection services) { Guard.ThrowIfNull(services); - services.AddOpenTelemetryProviderBuilderServices(); + services.AddOpenTelemetryMeterProviderBuilderServices(); + services.TryAddSingleton(sp => new MeterProviderSdk(sp, ownsServiceProvider: false)); this.services = services; @@ -65,7 +66,7 @@ protected MeterProviderBuilderBase() { var services = new ServiceCollection(); - services.AddOpenTelemetryProviderBuilderServices(); + services.AddOpenTelemetryMeterProviderBuilderServices(); this.services = services; this.ownsServices = true; diff --git a/src/OpenTelemetry/Metrics/MetricReaderOptions.cs b/src/OpenTelemetry/Metrics/MetricReaderOptions.cs index 69f9e12dc9b..13de4f98b0a 100644 --- a/src/OpenTelemetry/Metrics/MetricReaderOptions.cs +++ b/src/OpenTelemetry/Metrics/MetricReaderOptions.cs @@ -16,6 +16,7 @@ #nullable enable +using Microsoft.Extensions.Configuration; using OpenTelemetry.Internal; namespace OpenTelemetry.Metrics; @@ -25,7 +26,20 @@ namespace OpenTelemetry.Metrics; /// public class MetricReaderOptions { - private PeriodicExportingMetricReaderOptions? periodicExportingMetricReaderOptions; + private PeriodicExportingMetricReaderOptions periodicExportingMetricReaderOptions; + + /// + /// Initializes a new instance of the class. + /// + public MetricReaderOptions() + : this(new ConfigurationBuilder().AddEnvironmentVariables().Build()) + { + } + + internal MetricReaderOptions(IConfiguration configuration) + { + this.periodicExportingMetricReaderOptions = new PeriodicExportingMetricReaderOptions(configuration); + } /// /// Gets or sets the . @@ -33,11 +47,11 @@ public class MetricReaderOptions public MetricReaderTemporalityPreference TemporalityPreference { get; set; } = MetricReaderTemporalityPreference.Cumulative; /// - /// Gets or sets the . + /// Gets or sets the . /// public PeriodicExportingMetricReaderOptions PeriodicExportingMetricReaderOptions { - get => this.periodicExportingMetricReaderOptions ??= new(); + get => this.periodicExportingMetricReaderOptions; set { Guard.ThrowIfNull(value); diff --git a/src/OpenTelemetry/Metrics/PeriodicExportingMetricReaderOptions.cs b/src/OpenTelemetry/Metrics/PeriodicExportingMetricReaderOptions.cs index a8072a0e400..b3d62913220 100644 --- a/src/OpenTelemetry/Metrics/PeriodicExportingMetricReaderOptions.cs +++ b/src/OpenTelemetry/Metrics/PeriodicExportingMetricReaderOptions.cs @@ -14,10 +14,37 @@ // limitations under the License. // +using Microsoft.Extensions.Configuration; +using OpenTelemetry.Internal; + namespace OpenTelemetry.Metrics { public class PeriodicExportingMetricReaderOptions { + internal const string OTelMetricExportIntervalEnvVarKey = "OTEL_METRIC_EXPORT_INTERVAL"; + internal const string OTelMetricExportTimeoutEnvVarKey = "OTEL_METRIC_EXPORT_TIMEOUT"; + + /// + /// Initializes a new instance of the class. + /// + public PeriodicExportingMetricReaderOptions() + : this(new ConfigurationBuilder().AddEnvironmentVariables().Build()) + { + } + + internal PeriodicExportingMetricReaderOptions(IConfiguration configuration) + { + if (configuration.TryGetIntValue(OTelMetricExportIntervalEnvVarKey, out var interval)) + { + this.ExportIntervalMilliseconds = interval; + } + + if (configuration.TryGetIntValue(OTelMetricExportTimeoutEnvVarKey, out var timeout)) + { + this.ExportTimeoutMilliseconds = timeout; + } + } + /// /// Gets or sets the metric export interval in milliseconds. /// If not set, the default value depends on the type of metric exporter diff --git a/test/Benchmarks/Exporter/OtlpGrpcExporterBenchmarks.cs b/test/Benchmarks/Exporter/OtlpGrpcExporterBenchmarks.cs index 3f348a29f04..fc445fc041f 100644 --- a/test/Benchmarks/Exporter/OtlpGrpcExporterBenchmarks.cs +++ b/test/Benchmarks/Exporter/OtlpGrpcExporterBenchmarks.cs @@ -26,6 +26,7 @@ using OpenTelemetry; using OpenTelemetry.Internal; using OpenTelemetryProtocol::OpenTelemetry.Exporter; +using OpenTelemetryProtocol::OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation; using OpenTelemetryProtocol::OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient; using OtlpCollector = OpenTelemetryProtocol::OpenTelemetry.Proto.Collector.Trace.V1; @@ -58,6 +59,7 @@ public void GlobalSetup() var options = new OtlpExporterOptions(); this.exporter = new OtlpTraceExporter( options, + new SdkLimitOptions(), new OtlpGrpcTraceExportClient(options, mockClient.Object)); this.activity = ActivityHelper.CreateTestActivity(); diff --git a/test/Benchmarks/Exporter/OtlpHttpExporterBenchmarks.cs b/test/Benchmarks/Exporter/OtlpHttpExporterBenchmarks.cs index d10fe92064d..8f5004a3b9b 100644 --- a/test/Benchmarks/Exporter/OtlpHttpExporterBenchmarks.cs +++ b/test/Benchmarks/Exporter/OtlpHttpExporterBenchmarks.cs @@ -25,6 +25,7 @@ using OpenTelemetry.Internal; using OpenTelemetry.Tests; using OpenTelemetryProtocol::OpenTelemetry.Exporter; +using OpenTelemetryProtocol::OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation; using OpenTelemetryProtocol::OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient; namespace Benchmarks.Exporter @@ -74,6 +75,7 @@ public void GlobalSetup() }; this.exporter = new OtlpTraceExporter( options, + new SdkLimitOptions(), new OtlpHttpTraceExportClient(options, options.HttpClientFactory())); this.activity = ActivityHelper.CreateTestActivity(); diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/Implementation/ExportClient/OtlpHttpTraceExportClientTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/Implementation/ExportClient/OtlpHttpTraceExportClientTests.cs index a6dc816fd85..14acf30dc68 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/Implementation/ExportClient/OtlpHttpTraceExportClientTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/Implementation/ExportClient/OtlpHttpTraceExportClientTests.cs @@ -36,6 +36,8 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests { public class OtlpHttpTraceExportClientTests { + private static readonly SdkLimitOptions DefaultSdkLimitOptions = new(); + static OtlpHttpTraceExportClientTests() { Activity.DefaultIdFormat = ActivityIdFormat.W3C; @@ -171,7 +173,7 @@ void RunTest(Batch batch) { var request = new OtlpCollector.ExportTraceServiceRequest(); - request.AddBatch(resourceBuilder.Build().ToOtlpResource(), batch); + request.AddBatch(DefaultSdkLimitOptions, resourceBuilder.Build().ToOtlpResource(), batch); // Act var result = exportClient.SendExportRequest(request); diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/IntegrationTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/IntegrationTests.cs index 85bae563da6..48ed182f561 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/IntegrationTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/IntegrationTests.cs @@ -21,6 +21,7 @@ using System.Diagnostics.Tracing; using System.Linq; using System.Threading; +using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation; using OpenTelemetry.Metrics; using OpenTelemetry.Tests; using OpenTelemetry.Trace; @@ -33,6 +34,7 @@ public sealed class IntegrationTests : IDisposable { private const string CollectorHostnameEnvVarName = "OTEL_COLLECTOR_HOSTNAME"; private const int ExportIntervalMilliseconds = 10000; + private static readonly SdkLimitOptions DefaultSdkLimitOptions = new(); private static readonly string CollectorHostname = SkipUnlessEnvVarFoundTheoryAttribute.GetEnvironmentVariable(CollectorHostnameEnvVarName); private readonly OpenTelemetryEventListener openTelemetryEventListener; @@ -82,6 +84,7 @@ public void TraceExportResultIsSuccess(OtlpExportProtocol protocol, string endpo OtlpTraceExporterHelperExtensions.AddOtlpExporter( builder, exporterOptions, + DefaultSdkLimitOptions, serviceProvider: null, configureExporterInstance: otlpExporter => { diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExporterOptionsTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExporterOptionsTests.cs index d3e39fb3ec9..f1b03638283 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExporterOptionsTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExporterOptionsTests.cs @@ -15,6 +15,8 @@ // using System; +using System.Collections.Generic; +using Microsoft.Extensions.Configuration; using Xunit; namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests @@ -72,6 +74,29 @@ public void OtlpExporterOptions_EnvironmentVariableOverride() Assert.Equal(OtlpExportProtocol.HttpProtobuf, options.Protocol); } + [Fact] + public void OtlpExporterOptions_UsingIConfiguration() + { + var values = new Dictionary() + { + [OtlpExporterOptions.EndpointEnvVarName] = "http://test:8888", + [OtlpExporterOptions.HeadersEnvVarName] = "A=2,B=3", + [OtlpExporterOptions.TimeoutEnvVarName] = "2000", + [OtlpExporterOptions.ProtocolEnvVarName] = "http/protobuf", + }; + + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(values) + .Build(); + + var options = new OtlpExporterOptions(configuration); + + Assert.Equal(new Uri("http://test:8888"), options.Endpoint); + Assert.Equal("A=2,B=3", options.Headers); + Assert.Equal(2000, options.TimeoutMilliseconds); + Assert.Equal(OtlpExportProtocol.HttpProtobuf, options.Protocol); + } + [Fact] public void OtlpExporterOptions_InvalidEndpointVariableOverride() { diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpLogExporterTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpLogExporterTests.cs index 8feab03e185..3ac1e8e7199 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpLogExporterTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpLogExporterTests.cs @@ -32,6 +32,8 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests { public class OtlpLogExporterTests : Http2UnencryptedSupportTests { + private static readonly SdkLimitOptions DefaultSdkLimitOptions = new(); + [Fact] public void AddOtlpLogExporterOptionsTest() { @@ -133,7 +135,7 @@ public void OtlpLogRecordTestWhenStateValuesArePopulated() Assert.Single(logRecords); var logRecord = logRecords[0]; - var otlpLogRecord = logRecord.ToOtlpLog(); + var otlpLogRecord = logRecord.ToOtlpLog(DefaultSdkLimitOptions); Assert.NotNull(otlpLogRecord); Assert.Equal("Hello from tomato 2.99.", otlpLogRecord.Body.StringValue); @@ -173,7 +175,7 @@ public void CheckToOtlpLogRecordLoggerCategory() Assert.Single(logRecords); var logRecord = logRecords[0]; - var otlpLogRecord = logRecord.ToOtlpLog(); + var otlpLogRecord = logRecord.ToOtlpLog(DefaultSdkLimitOptions); Assert.NotNull(otlpLogRecord); Assert.Single(otlpLogRecord.Attributes); @@ -187,7 +189,7 @@ public void CheckToOtlpLogRecordLoggerCategory() Assert.Single(logRecords); logRecord = logRecords[0]; - otlpLogRecord = logRecord.ToOtlpLog(); + otlpLogRecord = logRecord.ToOtlpLog(DefaultSdkLimitOptions); Assert.NotNull(otlpLogRecord); Assert.Empty(otlpLogRecord.Attributes); } @@ -211,7 +213,7 @@ public void CheckToOtlpLogRecordEventId() Assert.Single(logRecords); var logRecord = logRecords[0]; - var otlpLogRecord = logRecord.ToOtlpLog(); + var otlpLogRecord = logRecord.ToOtlpLog(DefaultSdkLimitOptions); Assert.NotNull(otlpLogRecord); Assert.Equal("Hello from tomato 2.99.", otlpLogRecord.Body.StringValue); @@ -228,7 +230,7 @@ public void CheckToOtlpLogRecordEventId() Assert.Single(logRecords); logRecord = logRecords[0]; - otlpLogRecord = logRecord.ToOtlpLog(); + otlpLogRecord = logRecord.ToOtlpLog(DefaultSdkLimitOptions); Assert.NotNull(otlpLogRecord); Assert.Equal("Hello from tomato 2.99.", otlpLogRecord.Body.StringValue); @@ -256,7 +258,7 @@ public void CheckToOtlpLogRecordTraceIdSpanIdFlagWithNoActivity() var logger = loggerFactory.CreateLogger("OtlpLogExporterTests"); logger.LogInformation("Log when there is no activity."); var logRecord = logRecords[0]; - var otlpLogRecord = logRecord.ToOtlpLog(); + var otlpLogRecord = logRecord.ToOtlpLog(DefaultSdkLimitOptions); Assert.Null(Activity.Current); Assert.True(otlpLogRecord.TraceId.IsEmpty); @@ -289,7 +291,7 @@ public void CheckToOtlpLogRecordSpanIdTraceIdAndFlag() } var logRecord = logRecords[0]; - var otlpLogRecord = logRecord.ToOtlpLog(); + var otlpLogRecord = logRecord.ToOtlpLog(DefaultSdkLimitOptions); Assert.Equal(expectedTraceId.ToString(), ActivityTraceId.CreateFromBytes(otlpLogRecord.TraceId.ToByteArray()).ToString()); Assert.Equal(expectedSpanId.ToString(), ActivitySpanId.CreateFromBytes(otlpLogRecord.SpanId.ToByteArray()).ToString()); @@ -321,7 +323,7 @@ public void CheckToOtlpLogRecordSeverityLevelAndText(LogLevel logLevel) Assert.Single(logRecords); var logRecord = logRecords[0]; - var otlpLogRecord = logRecord.ToOtlpLog(); + var otlpLogRecord = logRecord.ToOtlpLog(DefaultSdkLimitOptions); Assert.NotNull(otlpLogRecord); Assert.Equal(logRecord.LogLevel.ToString(), otlpLogRecord.SeverityText); @@ -371,7 +373,7 @@ public void CheckToOtlpLogRecordBodyIsPopulated(bool includeFormattedMessage) Assert.Single(logRecords); var logRecord = logRecords[0]; - var otlpLogRecord = logRecord.ToOtlpLog(); + var otlpLogRecord = logRecord.ToOtlpLog(DefaultSdkLimitOptions); Assert.NotNull(otlpLogRecord); if (includeFormattedMessage) @@ -390,7 +392,7 @@ public void CheckToOtlpLogRecordBodyIsPopulated(bool includeFormattedMessage) Assert.Single(logRecords); logRecord = logRecords[0]; - otlpLogRecord = logRecord.ToOtlpLog(); + otlpLogRecord = logRecord.ToOtlpLog(DefaultSdkLimitOptions); Assert.NotNull(otlpLogRecord); if (includeFormattedMessage) @@ -410,7 +412,7 @@ public void CheckToOtlpLogRecordBodyIsPopulated(bool includeFormattedMessage) Assert.Single(logRecords); logRecord = logRecords[0]; - otlpLogRecord = logRecord.ToOtlpLog(); + otlpLogRecord = logRecord.ToOtlpLog(DefaultSdkLimitOptions); Assert.NotNull(otlpLogRecord); @@ -443,7 +445,7 @@ public void CheckToOtlpLogRecordExceptionAttributes() var logRecord = logRecords[0]; var loggedException = logRecord.Exception; - var otlpLogRecord = logRecord.ToOtlpLog(); + var otlpLogRecord = logRecord.ToOtlpLog(DefaultSdkLimitOptions); Assert.NotNull(otlpLogRecord); var otlpLogRecordAttributes = otlpLogRecord.Attributes.ToString(); diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs index 835d464dc44..e302f5654f0 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs @@ -21,7 +21,6 @@ using Google.Protobuf.Collections; using Microsoft.Extensions.DependencyInjection; using Moq; -using OpenTelemetry.Configuration; using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation; using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient; using OpenTelemetry.Resources; @@ -38,6 +37,8 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests [Collection("xUnitCollectionPreventingTestsThatDependOnSdkConfigurationFromRunningInParallel")] public class OtlpTraceExporterTests : Http2UnencryptedSupportTests { + private static readonly SdkLimitOptions DefaultSdkLimitOptions = new(); + static OtlpTraceExporterTests() { Activity.DefaultIdFormat = ActivityIdFormat.W3C; @@ -187,13 +188,13 @@ public void ToOtlpResourceSpansTest(bool includeServiceNameInResource) Assert.Equal(10, exportedItems.Count); var batch = new Batch(exportedItems.ToArray(), exportedItems.Count); - RunTest(batch); + RunTest(DefaultSdkLimitOptions, batch); - void RunTest(Batch batch) + void RunTest(SdkLimitOptions sdkOptions, Batch batch) { var request = new OtlpCollector.ExportTraceServiceRequest(); - request.AddBatch(resourceBuilder.Build().ToOtlpResource(), batch); + request.AddBatch(sdkOptions, resourceBuilder.Build().ToOtlpResource(), batch); Assert.Single(request.ResourceSpans); var otlpResource = request.ResourceSpans.First().Resource; @@ -243,10 +244,13 @@ void RunTest(Batch batch) [Fact] public void SpanLimitsTest() { - SdkConfiguration.Instance.AttributeValueLengthLimit = 4; - SdkConfiguration.Instance.AttributeCountLimit = 3; - SdkConfiguration.Instance.SpanEventCountLimit = 1; - SdkConfiguration.Instance.SpanLinkCountLimit = 1; + var sdkOptions = new SdkLimitOptions() + { + AttributeValueLengthLimit = 4, + AttributeCountLimit = 3, + SpanEventCountLimit = 1, + SpanLinkCountLimit = 1, + }; var tags = new ActivityTagsCollection() { @@ -271,7 +275,7 @@ public void SpanLimitsTest() activity.AddEvent(event1); activity.AddEvent(event2); - var otlpSpan = activity.ToOtlpSpan(); + var otlpSpan = activity.ToOtlpSpan(sdkOptions); Assert.NotNull(otlpSpan); Assert.Equal(3, otlpSpan.Attributes.Count); @@ -314,8 +318,6 @@ void ArrayValueAsserts(RepeatedField values) } } } - - SdkConfiguration.Reset(); } [Fact] @@ -359,7 +361,7 @@ public void ToOtlpSpanTest() rootActivity.TraceId.CopyTo(traceIdSpan); var traceId = traceIdSpan.ToArray(); - var otlpSpan = rootActivity.ToOtlpSpan(); + var otlpSpan = rootActivity.ToOtlpSpan(DefaultSdkLimitOptions); Assert.NotNull(otlpSpan); Assert.Equal("root", otlpSpan.Name); @@ -393,7 +395,7 @@ public void ToOtlpSpanTest() rootActivity.Context.SpanId.CopyTo(parentIdSpan); var parentId = parentIdSpan.ToArray(); - otlpSpan = childActivity.ToOtlpSpan(); + otlpSpan = childActivity.ToOtlpSpan(DefaultSdkLimitOptions); Assert.NotNull(otlpSpan); Assert.Equal("child", otlpSpan.Name); @@ -432,7 +434,7 @@ public void ToOtlpSpanActivitiesWithNullArrayTest() var stringArr = new string[] { "test", string.Empty, null }; rootActivity.SetTag("stringArray", stringArr); - var otlpSpan = rootActivity.ToOtlpSpan(); + var otlpSpan = rootActivity.ToOtlpSpan(DefaultSdkLimitOptions); Assert.NotNull(otlpSpan); @@ -454,7 +456,7 @@ public void ToOtlpSpanNativeActivityStatusTest(ActivityStatusCode expectedStatus using var activity = activitySource.StartActivity("Name"); activity.SetStatus(expectedStatusCode, statusDescription); - var otlpSpan = activity.ToOtlpSpan(); + var otlpSpan = activity.ToOtlpSpan(DefaultSdkLimitOptions); if (expectedStatusCode == ActivityStatusCode.Unset) { @@ -487,7 +489,7 @@ public void ToOtlpSpanStatusTagTest(StatusCode expectedStatusCode, string status activity.SetTag(SpanAttributeConstants.StatusCodeKey, statusCodeTagValue); activity.SetTag(SpanAttributeConstants.StatusDescriptionKey, statusDescription); - var otlpSpan = activity.ToOtlpSpan(); + var otlpSpan = activity.ToOtlpSpan(DefaultSdkLimitOptions); Assert.NotNull(otlpSpan.Status); Assert.Equal((int)expectedStatusCode, (int)otlpSpan.Status.Code); @@ -512,7 +514,7 @@ public void ToOtlpSpanStatusTagIsCaseInsensitiveTest(StatusCode expectedStatusCo using var activity = activitySource.StartActivity("Name"); activity.SetTag(SpanAttributeConstants.StatusCodeKey, statusCodeTagValue); - var otlpSpan = activity.ToOtlpSpan(); + var otlpSpan = activity.ToOtlpSpan(DefaultSdkLimitOptions); Assert.NotNull(otlpSpan.Status); Assert.Equal((int)expectedStatusCode, (int)otlpSpan.Status.Code); @@ -528,7 +530,7 @@ public void ToOtlpSpanActivityStatusTakesPrecedenceOverStatusTagsWhenActivitySta activity.SetTag(SpanAttributeConstants.StatusCodeKey, "ERROR"); activity.SetTag(SpanAttributeConstants.StatusDescriptionKey, TagDescriptionOnError); - var otlpSpan = activity.ToOtlpSpan(); + var otlpSpan = activity.ToOtlpSpan(DefaultSdkLimitOptions); Assert.NotNull(otlpSpan.Status); Assert.Equal((int)ActivityStatusCode.Ok, (int)otlpSpan.Status.Code); @@ -544,7 +546,7 @@ public void ToOtlpSpanActivityStatusTakesPrecedenceOverStatusTagsWhenActivitySta activity.SetStatus(ActivityStatusCode.Error, StatusDescriptionOnError); activity.SetTag(SpanAttributeConstants.StatusCodeKey, "OK"); - var otlpSpan = activity.ToOtlpSpan(); + var otlpSpan = activity.ToOtlpSpan(DefaultSdkLimitOptions); Assert.NotNull(otlpSpan.Status); Assert.Equal((int)ActivityStatusCode.Error, (int)otlpSpan.Status.Code); @@ -560,7 +562,7 @@ public void ToOtlpSpanPeerServiceTest() rootActivity.SetTag(SemanticConventions.AttributeHttpHost, "opentelemetry.io"); - var otlpSpan = rootActivity.ToOtlpSpan(); + var otlpSpan = rootActivity.ToOtlpSpan(DefaultSdkLimitOptions); Assert.NotNull(otlpSpan); @@ -618,7 +620,7 @@ public void Shutdown_ClientShutdownIsCalled() { var exportClientMock = new Mock>(); - var exporter = new OtlpTraceExporter(new OtlpExporterOptions(), exportClientMock.Object); + var exporter = new OtlpTraceExporter(new OtlpExporterOptions(), DefaultSdkLimitOptions, exportClientMock.Object); var result = exporter.Shutdown(); diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/Configuration/SdkConfigurationTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/SdkLimitOptionsTests.cs similarity index 58% rename from test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/Configuration/SdkConfigurationTests.cs rename to test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/SdkLimitOptionsTests.cs index dbbc9e43688..0e1fcfb0e2b 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/Configuration/SdkConfigurationTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/SdkLimitOptionsTests.cs @@ -1,4 +1,4 @@ -// +// // Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,29 +15,29 @@ // using System; +using System.Collections.Generic; +using Microsoft.Extensions.Configuration; +using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation; using Xunit; -namespace OpenTelemetry.Configuration.Tests +namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests { - [Collection("xUnitCollectionPreventingTestsThatDependOnSdkConfigurationFromRunningInParallel")] - public class SdkConfigurationTests : IDisposable + public sealed class SdkLimitOptionsTests : IDisposable { - public SdkConfigurationTests() + public SdkLimitOptionsTests() { ClearEnvVars(); - SdkConfiguration.Reset(); } public void Dispose() { ClearEnvVars(); - SdkConfiguration.Reset(); } [Fact] - public void SdkConfigurationDefaults() + public void SdkLimitOptionsDefaults() { - var config = SdkConfiguration.Instance; + var config = new SdkLimitOptions(); Assert.Null(config.AttributeValueLengthLimit); Assert.Null(config.AttributeCountLimit); @@ -45,12 +45,12 @@ public void SdkConfigurationDefaults() Assert.Null(config.SpanAttributeCountLimit); Assert.Null(config.SpanEventCountLimit); Assert.Null(config.SpanLinkCountLimit); - Assert.Null(config.EventAttributeCountLimit); - Assert.Null(config.LinkAttributeCountLimit); + Assert.Null(config.SpanEventAttributeCountLimit); + Assert.Null(config.SpanLinkAttributeCountLimit); } [Fact] - public void SdkConfigurationIsInitializedFromEnvironment() + public void SdkLimitOptionsIsInitializedFromEnvironment() { Environment.SetEnvironmentVariable("OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT", "10"); Environment.SetEnvironmentVariable("OTEL_ATTRIBUTE_COUNT_LIMIT", "10"); @@ -61,8 +61,7 @@ public void SdkConfigurationIsInitializedFromEnvironment() Environment.SetEnvironmentVariable("OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT", "30"); Environment.SetEnvironmentVariable("OTEL_LINK_ATTRIBUTE_COUNT_LIMIT", "30"); - SdkConfiguration.Reset(); - var config = SdkConfiguration.Instance; + var config = new SdkLimitOptions(); Assert.Equal(10, config.AttributeValueLengthLimit); Assert.Equal(10, config.AttributeCountLimit); @@ -70,14 +69,14 @@ public void SdkConfigurationIsInitializedFromEnvironment() Assert.Equal(20, config.SpanAttributeCountLimit); Assert.Equal(10, config.SpanEventCountLimit); Assert.Equal(10, config.SpanLinkCountLimit); - Assert.Equal(30, config.EventAttributeCountLimit); - Assert.Equal(30, config.LinkAttributeCountLimit); + Assert.Equal(30, config.SpanEventAttributeCountLimit); + Assert.Equal(30, config.SpanLinkAttributeCountLimit); } [Fact] public void SpanAttributeValueLengthLimitFallback() { - var config = SdkConfiguration.Instance; + var config = new SdkLimitOptions(); config.AttributeValueLengthLimit = 10; Assert.Equal(10, config.AttributeValueLengthLimit); @@ -91,31 +90,62 @@ public void SpanAttributeValueLengthLimitFallback() [Fact] public void SpanAttributeCountLimitFallback() { - var config = SdkConfiguration.Instance; + var config = new SdkLimitOptions(); config.AttributeCountLimit = 10; Assert.Equal(10, config.AttributeCountLimit); Assert.Equal(10, config.SpanAttributeCountLimit); - Assert.Equal(10, config.EventAttributeCountLimit); - Assert.Equal(10, config.LinkAttributeCountLimit); + Assert.Equal(10, config.SpanEventAttributeCountLimit); + Assert.Equal(10, config.SpanLinkAttributeCountLimit); config.SpanAttributeCountLimit = 20; Assert.Equal(10, config.AttributeCountLimit); Assert.Equal(20, config.SpanAttributeCountLimit); - Assert.Equal(20, config.EventAttributeCountLimit); - Assert.Equal(20, config.LinkAttributeCountLimit); + Assert.Equal(20, config.SpanEventAttributeCountLimit); + Assert.Equal(20, config.SpanLinkAttributeCountLimit); - config.EventAttributeCountLimit = 30; + config.SpanEventAttributeCountLimit = 30; Assert.Equal(10, config.AttributeCountLimit); Assert.Equal(20, config.SpanAttributeCountLimit); - Assert.Equal(30, config.EventAttributeCountLimit); - Assert.Equal(20, config.LinkAttributeCountLimit); + Assert.Equal(30, config.SpanEventAttributeCountLimit); + Assert.Equal(20, config.SpanLinkAttributeCountLimit); - config.LinkAttributeCountLimit = 40; + config.SpanLinkAttributeCountLimit = 40; Assert.Equal(10, config.AttributeCountLimit); Assert.Equal(20, config.SpanAttributeCountLimit); - Assert.Equal(30, config.EventAttributeCountLimit); - Assert.Equal(40, config.LinkAttributeCountLimit); + Assert.Equal(30, config.SpanEventAttributeCountLimit); + Assert.Equal(40, config.SpanLinkAttributeCountLimit); + } + + [Fact] + public void SdkLimitOptionsUsingIConfiguration() + { + var values = new Dictionary() + { + ["OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT"] = "23", + ["OTEL_ATTRIBUTE_COUNT_LIMIT"] = "24", + ["OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT"] = "25", + ["OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT"] = "26", + ["OTEL_SPAN_EVENT_COUNT_LIMIT"] = "27", + ["OTEL_SPAN_LINK_COUNT_LIMIT"] = "28", + ["OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT"] = "29", + ["OTEL_LINK_ATTRIBUTE_COUNT_LIMIT"] = "30", + }; + + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(values) + .Build(); + + var options = new SdkLimitOptions(configuration); + + Assert.Equal(23, options.AttributeValueLengthLimit); + Assert.Equal(24, options.AttributeCountLimit); + Assert.Equal(25, options.SpanAttributeValueLengthLimit); + Assert.Equal(26, options.SpanAttributeCountLimit); + Assert.Equal(27, options.SpanEventCountLimit); + Assert.Equal(28, options.SpanLinkCountLimit); + Assert.Equal(29, options.SpanEventAttributeCountLimit); + Assert.Equal(30, options.SpanLinkAttributeCountLimit); } private static void ClearEnvVars() diff --git a/test/OpenTelemetry.Tests/Internal/PeriodicExportingMetricReaderHelperTests.cs b/test/OpenTelemetry.Tests/Internal/PeriodicExportingMetricReaderHelperTests.cs index 78fe549436a..a5d1c4fd3cf 100644 --- a/test/OpenTelemetry.Tests/Internal/PeriodicExportingMetricReaderHelperTests.cs +++ b/test/OpenTelemetry.Tests/Internal/PeriodicExportingMetricReaderHelperTests.cs @@ -15,6 +15,8 @@ // using System; +using System.Collections.Generic; +using Microsoft.Extensions.Configuration; using OpenTelemetry.Exporter; using OpenTelemetry.Metrics; using Xunit; @@ -58,7 +60,7 @@ public void CreatePeriodicExportingMetricReader_TemporalityPreference_FromOption [Fact] public void CreatePeriodicExportingMetricReader_ExportIntervalMilliseconds_FromOptions() { - Environment.SetEnvironmentVariable(PeriodicExportingMetricReaderHelper.OTelMetricExportIntervalEnvVarKey, "88888"); // should be ignored, as value set via options has higher priority + Environment.SetEnvironmentVariable(PeriodicExportingMetricReaderOptions.OTelMetricExportIntervalEnvVarKey, "88888"); // should be ignored, as value set via options has higher priority var value = 123; var reader = CreatePeriodicExportingMetricReader(new() { @@ -74,7 +76,7 @@ public void CreatePeriodicExportingMetricReader_ExportIntervalMilliseconds_FromO [Fact] public void CreatePeriodicExportingMetricReader_ExportTimeoutMilliseconds_FromOptions() { - Environment.SetEnvironmentVariable(PeriodicExportingMetricReaderHelper.OTelMetricExportTimeoutEnvVarKey, "99999"); // should be ignored, as value set via options has higher priority + Environment.SetEnvironmentVariable(PeriodicExportingMetricReaderOptions.OTelMetricExportTimeoutEnvVarKey, "99999"); // should be ignored, as value set via options has higher priority var value = 456; var reader = CreatePeriodicExportingMetricReader(new() { @@ -91,7 +93,7 @@ public void CreatePeriodicExportingMetricReader_ExportTimeoutMilliseconds_FromOp public void CreatePeriodicExportingMetricReader_ExportIntervalMilliseconds_FromEnvVar() { var value = 789; - Environment.SetEnvironmentVariable(PeriodicExportingMetricReaderHelper.OTelMetricExportIntervalEnvVarKey, value.ToString()); + Environment.SetEnvironmentVariable(PeriodicExportingMetricReaderOptions.OTelMetricExportIntervalEnvVarKey, value.ToString()); var reader = CreatePeriodicExportingMetricReader(); Assert.Equal(value, reader.ExportIntervalMilliseconds); @@ -101,23 +103,42 @@ public void CreatePeriodicExportingMetricReader_ExportIntervalMilliseconds_FromE public void CreatePeriodicExportingMetricReader_ExportTimeoutMilliseconds_FromEnvVar() { var value = 246; - Environment.SetEnvironmentVariable(PeriodicExportingMetricReaderHelper.OTelMetricExportTimeoutEnvVarKey, value.ToString()); + Environment.SetEnvironmentVariable(PeriodicExportingMetricReaderOptions.OTelMetricExportTimeoutEnvVarKey, value.ToString()); var reader = CreatePeriodicExportingMetricReader(); Assert.Equal(value, reader.ExportTimeoutMilliseconds); } + [Fact] + public void CreatePeriodicExportingMetricReader_FromIConfiguration() + { + var values = new Dictionary() + { + [PeriodicExportingMetricReaderOptions.OTelMetricExportIntervalEnvVarKey] = "18", + [PeriodicExportingMetricReaderOptions.OTelMetricExportTimeoutEnvVarKey] = "19", + }; + + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(values) + .Build(); + + var options = new MetricReaderOptions(configuration); + + Assert.Equal(18, options.PeriodicExportingMetricReaderOptions.ExportIntervalMilliseconds); + Assert.Equal(19, options.PeriodicExportingMetricReaderOptions.ExportTimeoutMilliseconds); + } + [Fact] public void EnvironmentVariableNames() { - Assert.Equal("OTEL_METRIC_EXPORT_INTERVAL", PeriodicExportingMetricReaderHelper.OTelMetricExportIntervalEnvVarKey); - Assert.Equal("OTEL_METRIC_EXPORT_TIMEOUT", PeriodicExportingMetricReaderHelper.OTelMetricExportTimeoutEnvVarKey); + Assert.Equal("OTEL_METRIC_EXPORT_INTERVAL", PeriodicExportingMetricReaderOptions.OTelMetricExportIntervalEnvVarKey); + Assert.Equal("OTEL_METRIC_EXPORT_TIMEOUT", PeriodicExportingMetricReaderOptions.OTelMetricExportTimeoutEnvVarKey); } private static void ClearEnvVars() { - Environment.SetEnvironmentVariable(PeriodicExportingMetricReaderHelper.OTelMetricExportIntervalEnvVarKey, null); - Environment.SetEnvironmentVariable(PeriodicExportingMetricReaderHelper.OTelMetricExportTimeoutEnvVarKey, null); + Environment.SetEnvironmentVariable(PeriodicExportingMetricReaderOptions.OTelMetricExportIntervalEnvVarKey, null); + Environment.SetEnvironmentVariable(PeriodicExportingMetricReaderOptions.OTelMetricExportTimeoutEnvVarKey, null); } private static PeriodicExportingMetricReader CreatePeriodicExportingMetricReader(