From 9c565ffc04b7abcef695a27c23c872515a0a739c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Paj=C4=85k?= Date: Fri, 1 Jul 2022 10:10:47 +0200 Subject: [PATCH 1/3] Support OTEL_METRIC_EXPORT_INTERVAL and OTEL_METRIC_EXPORT_TIMEOUT --- .../CHANGELOG.md | 6 + .../OpenTelemetry.Exporter.Console.csproj | 1 + .../CHANGELOG.md | 6 + .../CHANGELOG.md | 6 + .../OtlpMetricExporterExtensions.cs | 7 +- .../PeriodicExportingMetricReaderHelper.cs | 40 ++++-- .../Metrics/PeriodicExportingMetricReader.cs | 10 +- ...eriodicExportingMetricReaderHelperTests.cs | 133 ++++++++++++++++++ 8 files changed, 190 insertions(+), 19 deletions(-) create mode 100644 test/OpenTelemetry.Tests/Internal/PeriodicExportingMetricReaderHelperTests.cs diff --git a/src/OpenTelemetry.Exporter.Console/CHANGELOG.md b/src/OpenTelemetry.Exporter.Console/CHANGELOG.md index 227e032b5d1..781d1454627 100644 --- a/src/OpenTelemetry.Exporter.Console/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Console/CHANGELOG.md @@ -2,6 +2,12 @@ ## Unreleased +* The `MetricReaderOptions` defaults can be overridden using + `OTEL_METRIC_EXPORT_INTERVAL` and `OTEL_METRIC_EXPORT_TIMEOUT` + environmental variables as defined in the + [specification](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.12.0/specification/sdk-environment-variables.md#periodic-exporting-metricreader). + ([#3424](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3424)) + ## 1.3.0 Released 2022-Jun-03 diff --git a/src/OpenTelemetry.Exporter.Console/OpenTelemetry.Exporter.Console.csproj b/src/OpenTelemetry.Exporter.Console/OpenTelemetry.Exporter.Console.csproj index 028440a5896..d0f69330b15 100644 --- a/src/OpenTelemetry.Exporter.Console/OpenTelemetry.Exporter.Console.csproj +++ b/src/OpenTelemetry.Exporter.Console/OpenTelemetry.Exporter.Console.csproj @@ -21,6 +21,7 @@ + diff --git a/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md b/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md index 7b528d516d4..20be374518e 100644 --- a/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md @@ -5,6 +5,12 @@ * `InMemoryExporter` will now buffer scopes when exporting `LogRecord` ([#3360](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3360)) +* The `MetricReaderOptions` defaults can be overridden using + `OTEL_METRIC_EXPORT_INTERVAL` and `OTEL_METRIC_EXPORT_TIMEOUT` + environmental variables as defined in the + [specification](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.12.0/specification/sdk-environment-variables.md#periodic-exporting-metricreader). + ([#3424](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3424)) + ## 1.3.0 Released 2022-Jun-03 diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md index d90417bb3de..6199a199208 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md @@ -2,6 +2,12 @@ ## Unreleased +* The `MetricReaderOptions` defaults can be overridden using + `OTEL_METRIC_EXPORT_INTERVAL` and `OTEL_METRIC_EXPORT_TIMEOUT` + environmental variables as defined in the + [specification](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.12.0/specification/sdk-environment-variables.md#periodic-exporting-metricreader). + ([#3424](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3424)) + ## 1.3.0 Released 2022-Jun-03 diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporterExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporterExtensions.cs index 3cdf4c29664..f3c1547f181 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporterExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporterExtensions.cs @@ -25,9 +25,6 @@ namespace OpenTelemetry.Metrics /// public static class OtlpMetricExporterExtensions { - private const int DefaultExportIntervalMilliseconds = 60000; - private const int DefaultExportTimeoutMilliseconds = 30000; - /// /// Adds to the using default options. /// @@ -111,9 +108,7 @@ internal static MeterProviderBuilder AddOtlpExporter( var metricReader = PeriodicExportingMetricReaderHelper.CreatePeriodicExportingMetricReader( metricExporter, - metricReaderOptions, - DefaultExportIntervalMilliseconds, - DefaultExportTimeoutMilliseconds); + metricReaderOptions); return builder.AddReader(metricReader); } diff --git a/src/OpenTelemetry/Internal/PeriodicExportingMetricReaderHelper.cs b/src/OpenTelemetry/Internal/PeriodicExportingMetricReaderHelper.cs index 0d04984eb47..0fa1fc9058b 100644 --- a/src/OpenTelemetry/Internal/PeriodicExportingMetricReaderHelper.cs +++ b/src/OpenTelemetry/Internal/PeriodicExportingMetricReaderHelper.cs @@ -14,23 +14,32 @@ // 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( BaseExporter exporter, MetricReaderOptions options, - int defaultExportIntervalMilliseconds, - int defaultExportTimeoutMilliseconds) + int defaultExportIntervalMilliseconds = DefaultExportIntervalMilliseconds, + int defaultExportTimeoutMilliseconds = DefaultExportTimeoutMilliseconds) { - var exportInterval = - options.PeriodicExportingMetricReaderOptions?.ExportIntervalMilliseconds - ?? defaultExportIntervalMilliseconds; + var exportInterval = GetValue( + options.PeriodicExportingMetricReaderOptions?.ExportIntervalMilliseconds, + OTelMetricExportIntervalEnvVarKey, + defaultExportIntervalMilliseconds); - var exportTimeout = - options.PeriodicExportingMetricReaderOptions?.ExportTimeoutMilliseconds - ?? defaultExportTimeoutMilliseconds; + var exportTimeout = GetValue( + options.PeriodicExportingMetricReaderOptions?.ExportTimeoutMilliseconds, + OTelMetricExportTimeoutEnvVarKey, + defaultExportTimeoutMilliseconds); var metricReader = new PeriodicExportingMetricReader(exporter, exportInterval, exportTimeout) { @@ -39,4 +48,19 @@ 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/PeriodicExportingMetricReader.cs b/src/OpenTelemetry/Metrics/PeriodicExportingMetricReader.cs index 6b464f02b26..d008d20282d 100644 --- a/src/OpenTelemetry/Metrics/PeriodicExportingMetricReader.cs +++ b/src/OpenTelemetry/Metrics/PeriodicExportingMetricReader.cs @@ -32,7 +32,7 @@ public class PeriodicExportingMetricReader : BaseExportingMetricReader internal const int DefaultExportTimeoutMilliseconds = 30000; internal readonly int ExportIntervalMilliseconds; - private readonly int exportTimeoutMilliseconds; + internal readonly int ExportTimeoutMilliseconds; private readonly Thread exporterThread; private readonly AutoResetEvent exportTrigger = new(false); private readonly ManualResetEvent shutdownTrigger = new(false); @@ -60,7 +60,7 @@ public PeriodicExportingMetricReader( } this.ExportIntervalMilliseconds = exportIntervalMilliseconds; - this.exportTimeoutMilliseconds = exportTimeoutMilliseconds; + this.ExportTimeoutMilliseconds = exportTimeoutMilliseconds; this.exporterThread = new Thread(new ThreadStart(this.ExporterProc)) { @@ -141,15 +141,15 @@ private void ExporterProc() { case 0: // export OpenTelemetrySdkEventSource.Log.MetricReaderEvent("PeriodicExportingMetricReader calling MetricReader.Collect because Export was triggered."); - this.Collect(this.exportTimeoutMilliseconds); + this.Collect(this.ExportTimeoutMilliseconds); break; case 1: // shutdown OpenTelemetrySdkEventSource.Log.MetricReaderEvent("PeriodicExportingMetricReader calling MetricReader.Collect because Shutdown was triggered."); - this.Collect(this.exportTimeoutMilliseconds); // TODO: do we want to use the shutdown timeout here? + this.Collect(this.ExportTimeoutMilliseconds); // TODO: do we want to use the shutdown timeout here? return; case WaitHandle.WaitTimeout: // timer OpenTelemetrySdkEventSource.Log.MetricReaderEvent("PeriodicExportingMetricReader calling MetricReader.Collect because the export interval has elapsed."); - this.Collect(this.exportTimeoutMilliseconds); + this.Collect(this.ExportTimeoutMilliseconds); break; } } diff --git a/test/OpenTelemetry.Tests/Internal/PeriodicExportingMetricReaderHelperTests.cs b/test/OpenTelemetry.Tests/Internal/PeriodicExportingMetricReaderHelperTests.cs new file mode 100644 index 00000000000..b3e1766016c --- /dev/null +++ b/test/OpenTelemetry.Tests/Internal/PeriodicExportingMetricReaderHelperTests.cs @@ -0,0 +1,133 @@ +// +// 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.Exporter; +using OpenTelemetry.Metrics; +using Xunit; + +namespace OpenTelemetry.Internal.Tests +{ + public class PeriodicExportingMetricReaderHelperTests : IDisposable + { + public PeriodicExportingMetricReaderHelperTests() + { + ClearEnvVars(); + } + + public void Dispose() + { + ClearEnvVars(); + } + + [Fact] + public void CreatePeriodicExportingMetricReader_Defaults() + { + var reader = CreatePeriodicExportingMetricReader(); + + Assert.Equal(60000, reader.ExportIntervalMilliseconds); + Assert.Equal(30000, reader.ExportTimeoutMilliseconds); + Assert.Equal(MetricReaderTemporalityPreference.Cumulative, reader.TemporalityPreference); + } + + [Fact] + public void CreatePeriodicExportingMetricReader_TemporalityPreference_FromOptions() + { + var value = MetricReaderTemporalityPreference.Delta; + var reader = CreatePeriodicExportingMetricReader(new() + { + TemporalityPreference = value, + }); + + Assert.Equal(value, reader.TemporalityPreference); + } + + [Fact] + public void CreatePeriodicExportingMetricReader_ExportIntervalMilliseconds_FromOptions() + { + var value = 123; + var reader = CreatePeriodicExportingMetricReader(new() + { + PeriodicExportingMetricReaderOptions = new() + { + ExportIntervalMilliseconds = value, + }, + }); + + Assert.Equal(value, reader.ExportIntervalMilliseconds); + } + + [Fact] + public void CreatePeriodicExportingMetricReader_ExportTimeoutMilliseconds_FromOptions() + { + var value = 456; + var reader = CreatePeriodicExportingMetricReader(new() + { + PeriodicExportingMetricReaderOptions = new() + { + ExportTimeoutMilliseconds = value, + }, + }); + + Assert.Equal(value, reader.ExportTimeoutMilliseconds); + } + + [Fact] + public void CreatePeriodicExportingMetricReader_ExportIntervalMilliseconds_FromEnvVar() + { + var value = 789; + Environment.SetEnvironmentVariable(PeriodicExportingMetricReaderHelper.OTelMetricExportIntervalEnvVarKey, value.ToString()); + var reader = CreatePeriodicExportingMetricReader(); + + Assert.Equal(value, reader.ExportIntervalMilliseconds); + } + + [Fact] + public void CreatePeriodicExportingMetricReader_ExportTimeoutMilliseconds_FromEnvVar() + { + var value = 246; + Environment.SetEnvironmentVariable(PeriodicExportingMetricReaderHelper.OTelMetricExportTimeoutEnvVarKey, value.ToString()); + var reader = CreatePeriodicExportingMetricReader(); + + Assert.Equal(value, reader.ExportTimeoutMilliseconds); + } + + [Fact] + public void EnvironmentVariableNames() + { + Assert.Equal("OTEL_METRIC_EXPORT_INTERVAL", PeriodicExportingMetricReaderHelper.OTelMetricExportIntervalEnvVarKey); + Assert.Equal("OTEL_METRIC_EXPORT_TIMEOUT", PeriodicExportingMetricReaderHelper.OTelMetricExportTimeoutEnvVarKey); + } + + private static void ClearEnvVars() + { + Environment.SetEnvironmentVariable(PeriodicExportingMetricReaderHelper.OTelMetricExportIntervalEnvVarKey, null); + Environment.SetEnvironmentVariable(PeriodicExportingMetricReaderHelper.OTelMetricExportTimeoutEnvVarKey, null); + } + + private static PeriodicExportingMetricReader CreatePeriodicExportingMetricReader( + MetricReaderOptions options = null) + { + if (options == null) + { + options = new(); + } + + var dummyMetricExporter = new InMemoryExporter(new Metric[0]); + return PeriodicExportingMetricReaderHelper.CreatePeriodicExportingMetricReader(dummyMetricExporter, options); + } + } +} From a33c20b787200fc0d538be334fcea012009c8130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Paj=C4=85k?= Date: Fri, 1 Jul 2022 10:25:22 +0200 Subject: [PATCH 2/3] Refine tests --- .../Internal/PeriodicExportingMetricReaderHelperTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/OpenTelemetry.Tests/Internal/PeriodicExportingMetricReaderHelperTests.cs b/test/OpenTelemetry.Tests/Internal/PeriodicExportingMetricReaderHelperTests.cs index b3e1766016c..78fe549436a 100644 --- a/test/OpenTelemetry.Tests/Internal/PeriodicExportingMetricReaderHelperTests.cs +++ b/test/OpenTelemetry.Tests/Internal/PeriodicExportingMetricReaderHelperTests.cs @@ -58,6 +58,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 var value = 123; var reader = CreatePeriodicExportingMetricReader(new() { @@ -73,6 +74,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 var value = 456; var reader = CreatePeriodicExportingMetricReader(new() { From bd025a4d509ab66cb6f754e1b72f21ad9d7dc6db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Paj=C4=85k?= Date: Tue, 5 Jul 2022 15:31:47 +0200 Subject: [PATCH 3/3] Update docs --- src/OpenTelemetry.Exporter.Console/README.md | 24 +++++++++++++++++++ src/OpenTelemetry.Exporter.InMemory/README.md | 18 ++++++++++++++ .../README.md | 15 +++++++++--- 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/src/OpenTelemetry.Exporter.Console/README.md b/src/OpenTelemetry.Exporter.Console/README.md index 309f7718d81..440e5d22adf 100644 --- a/src/OpenTelemetry.Exporter.Console/README.md +++ b/src/OpenTelemetry.Exporter.Console/README.md @@ -23,6 +23,30 @@ used: * [Metrics](../../docs/metrics/getting-started/Program.cs) * [Traces](../../docs/trace/getting-started/Program.cs) +## Configuration + +See the +[`TestConsoleExporter.cs`](../../examples/Console/TestConsoleExporter.cs) for +an example of how to use the exporter for exporting traces to a collection. + +You can configure the `ConsoleExporter` through `Options` types properties +and environment variables. +The `Options` type setters take precedence over the environment variables. + +## Environment Variables + +The following environment variables can be used to override the default +values of the `PeriodicExportingMetricReaderOptions` +(following the [OpenTelemetry specification](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.12.0/specification/sdk-environment-variables.md#periodic-exporting-metricreader). + +| Environment variable | `PeriodicExportingMetricReaderOptions` property | +| ------------------------------| ------------------------------------------------| +| `OTEL_METRIC_EXPORT_INTERVAL` | `ExportIntervalMilliseconds` | +| `OTEL_METRIC_EXPORT_TIMEOUT` | `ExportTimeoutMilliseconds` | + +`FormatException` is thrown in case of an invalid value for any of the +supported environment variables. + ## References * [OpenTelemetry Project](https://opentelemetry.io/) diff --git a/src/OpenTelemetry.Exporter.InMemory/README.md b/src/OpenTelemetry.Exporter.InMemory/README.md index d886ecb3543..30ef04f1c52 100644 --- a/src/OpenTelemetry.Exporter.InMemory/README.md +++ b/src/OpenTelemetry.Exporter.InMemory/README.md @@ -17,6 +17,24 @@ See the [`TestInMemoryExporter.cs`](../../examples/Console/TestInMemoryExporter.cs) for an example of how to use the exporter for exporting traces to a collection. +You can configure the `InMemoryExporter` through `Options` types properties +and environment variables. +The `Options` type setters take precedence over the environment variables. + +## Environment Variables + +The following environment variables can be used to override the default +values of the `PeriodicExportingMetricReaderOptions` +(following the [OpenTelemetry specification](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.12.0/specification/sdk-environment-variables.md#periodic-exporting-metricreader). + +| Environment variable | `PeriodicExportingMetricReaderOptions` property | +| ------------------------------| ------------------------------------------------| +| `OTEL_METRIC_EXPORT_INTERVAL` | `ExportIntervalMilliseconds` | +| `OTEL_METRIC_EXPORT_TIMEOUT` | `ExportTimeoutMilliseconds` | + +`FormatException` is thrown in case of an invalid value for any of the +supported environment variables. + ## References * [OpenTelemetry Project](https://opentelemetry.io/) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md index 85fae396d50..2d7588afb56 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md @@ -18,9 +18,9 @@ dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol ## Configuration -You can configure the `OtlpExporter` through `OtlpExporterOptions` -properties and environment variables. The `OtlpExporterOptions` -setters take precedence over the environment variables. +You can configure the `OtlpExporter` through `Options` types properties +and environment variables. +The `Options` type setters take precedence over the environment variables. ## Options Properties @@ -63,6 +63,15 @@ values of the `OtlpExporterOptions` | `OTEL_EXPORTER_OTLP_TIMEOUT` | `TimeoutMilliseconds` | | `OTEL_EXPORTER_OTLP_PROTOCOL` | `Protocol` (`grpc` or `http/protobuf`)| +The following environment variables can be used to override the default +values of the `PeriodicExportingMetricReaderOptions` +(following the [OpenTelemetry specification](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.12.0/specification/sdk-environment-variables.md#periodic-exporting-metricreader). + +| Environment variable | `PeriodicExportingMetricReaderOptions` property | +| ------------------------------| ------------------------------------------------| +| `OTEL_METRIC_EXPORT_INTERVAL` | `ExportIntervalMilliseconds` | +| `OTEL_METRIC_EXPORT_TIMEOUT` | `ExportTimeoutMilliseconds` | + `FormatException` is thrown in case of an invalid value for any of the supported environment variables.