From cc906f42818c445009db7f6cde96c93226e2724e Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Tue, 18 Oct 2022 13:18:05 -0700 Subject: [PATCH 1/4] Support dependency injection in ResourceBuilder and load envvars from IConfiguration. --- .../OpenTelemetry.Exporter.Console.csproj | 1 - .../.publicApi/net462/PublicAPI.Shipped.txt | 18 +- .../.publicApi/net462/PublicAPI.Unshipped.txt | 1 + .../.publicApi/net6.0/PublicAPI.Shipped.txt | 18 +- .../.publicApi/net6.0/PublicAPI.Unshipped.txt | 1 + .../netstandard2.0/PublicAPI.Shipped.txt | 18 +- .../netstandard2.0/PublicAPI.Unshipped.txt | 1 + .../netstandard2.1/PublicAPI.Shipped.txt | 18 +- .../netstandard2.1/PublicAPI.Unshipped.txt | 1 + src/OpenTelemetry/CHANGELOG.md | 5 + .../Internal/EnvironmentVariableHelper.cs | 162 ----------------- src/OpenTelemetry/Metrics/MeterProviderSdk.cs | 5 +- .../Resources/OtelEnvResourceDetector.cs | 12 +- .../OtelServiceNameEnvVarDetector.cs | 12 +- .../Resources/ResourceBuilder.cs | 95 ++++++++-- .../Resources/ResourceBuilderExtensions.cs | 20 ++- src/OpenTelemetry/Trace/TracerProviderSdk.cs | 5 +- .../EnvironmentVariableHelperTests.cs | 165 ------------------ .../MeterProviderBuilderExtensionsTests.cs | 8 +- .../Resources/OtelEnvResourceDetectorTest.cs | 32 +++- .../OtelServiceNameEnvVarDetectorTests.cs | 27 ++- .../TracerProviderBuilderExtensionsTest.cs | 8 +- 22 files changed, 233 insertions(+), 400 deletions(-) delete mode 100644 src/OpenTelemetry/Internal/EnvironmentVariableHelper.cs delete mode 100644 test/OpenTelemetry.Tests/Internal/EnvironmentVariableHelperTests.cs diff --git a/src/OpenTelemetry.Exporter.Console/OpenTelemetry.Exporter.Console.csproj b/src/OpenTelemetry.Exporter.Console/OpenTelemetry.Exporter.Console.csproj index e91623caf6b..02f8ed650bc 100644 --- a/src/OpenTelemetry.Exporter.Console/OpenTelemetry.Exporter.Console.csproj +++ b/src/OpenTelemetry.Exporter.Console/OpenTelemetry.Exporter.Console.csproj @@ -21,7 +21,6 @@ - diff --git a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Shipped.txt b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Shipped.txt index 782248e7e3a..5cb58ce6d58 100644 --- a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Shipped.txt +++ b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Shipped.txt @@ -42,9 +42,9 @@ OpenTelemetry.Metrics.MetricReaderOptions.PeriodicExportingMetricReaderOptions.s ~OpenTelemetry.Resources.Resource.Attributes.get -> System.Collections.Generic.IEnumerable> ~OpenTelemetry.Resources.Resource.Merge(OpenTelemetry.Resources.Resource other) -> OpenTelemetry.Resources.Resource ~OpenTelemetry.Resources.Resource.Resource(System.Collections.Generic.IEnumerable> attributes) -> void -~OpenTelemetry.Resources.ResourceBuilder.AddDetector(OpenTelemetry.Resources.IResourceDetector resourceDetector) -> OpenTelemetry.Resources.ResourceBuilder -~OpenTelemetry.Resources.ResourceBuilder.Build() -> OpenTelemetry.Resources.Resource -~OpenTelemetry.Resources.ResourceBuilder.Clear() -> OpenTelemetry.Resources.ResourceBuilder +OpenTelemetry.Resources.ResourceBuilder.AddDetector(OpenTelemetry.Resources.IResourceDetector! resourceDetector) -> OpenTelemetry.Resources.ResourceBuilder! +OpenTelemetry.Resources.ResourceBuilder.Build() -> OpenTelemetry.Resources.Resource! +OpenTelemetry.Resources.ResourceBuilder.Clear() -> OpenTelemetry.Resources.ResourceBuilder! ~OpenTelemetry.SimpleActivityExportProcessor.SimpleActivityExportProcessor(OpenTelemetry.BaseExporter exporter) -> void OpenTelemetry.SimpleExportProcessor OpenTelemetry.SimpleExportProcessor.SimpleExportProcessor(OpenTelemetry.BaseExporter! exporter) -> void @@ -88,12 +88,12 @@ static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.SetResourceBuilder(t ~static OpenTelemetry.ProviderExtensions.GetDefaultResource(this OpenTelemetry.BaseProvider baseProvider) -> OpenTelemetry.Resources.Resource ~static OpenTelemetry.ProviderExtensions.GetResource(this OpenTelemetry.BaseProvider baseProvider) -> OpenTelemetry.Resources.Resource ~static OpenTelemetry.Resources.Resource.Empty.get -> OpenTelemetry.Resources.Resource -~static OpenTelemetry.Resources.ResourceBuilder.CreateDefault() -> OpenTelemetry.Resources.ResourceBuilder -~static OpenTelemetry.Resources.ResourceBuilder.CreateEmpty() -> OpenTelemetry.Resources.ResourceBuilder -~static OpenTelemetry.Resources.ResourceBuilderExtensions.AddAttributes(this OpenTelemetry.Resources.ResourceBuilder resourceBuilder, System.Collections.Generic.IEnumerable> attributes) -> OpenTelemetry.Resources.ResourceBuilder -~static OpenTelemetry.Resources.ResourceBuilderExtensions.AddEnvironmentVariableDetector(this OpenTelemetry.Resources.ResourceBuilder resourceBuilder) -> OpenTelemetry.Resources.ResourceBuilder -~static OpenTelemetry.Resources.ResourceBuilderExtensions.AddService(this OpenTelemetry.Resources.ResourceBuilder resourceBuilder, string serviceName, string serviceNamespace = null, string serviceVersion = null, bool autoGenerateServiceInstanceId = true, string serviceInstanceId = null) -> OpenTelemetry.Resources.ResourceBuilder -~static OpenTelemetry.Resources.ResourceBuilderExtensions.AddTelemetrySdk(this OpenTelemetry.Resources.ResourceBuilder resourceBuilder) -> OpenTelemetry.Resources.ResourceBuilder +static OpenTelemetry.Resources.ResourceBuilder.CreateDefault() -> OpenTelemetry.Resources.ResourceBuilder! +static OpenTelemetry.Resources.ResourceBuilder.CreateEmpty() -> OpenTelemetry.Resources.ResourceBuilder! +static OpenTelemetry.Resources.ResourceBuilderExtensions.AddAttributes(this OpenTelemetry.Resources.ResourceBuilder! resourceBuilder, System.Collections.Generic.IEnumerable>! attributes) -> OpenTelemetry.Resources.ResourceBuilder! +static OpenTelemetry.Resources.ResourceBuilderExtensions.AddEnvironmentVariableDetector(this OpenTelemetry.Resources.ResourceBuilder! resourceBuilder) -> OpenTelemetry.Resources.ResourceBuilder! +static OpenTelemetry.Resources.ResourceBuilderExtensions.AddService(this OpenTelemetry.Resources.ResourceBuilder! resourceBuilder, string! serviceName, string? serviceNamespace = null, string? serviceVersion = null, bool autoGenerateServiceInstanceId = true, string? serviceInstanceId = null) -> OpenTelemetry.Resources.ResourceBuilder! +static OpenTelemetry.Resources.ResourceBuilderExtensions.AddTelemetrySdk(this OpenTelemetry.Resources.ResourceBuilder! resourceBuilder) -> OpenTelemetry.Resources.ResourceBuilder! static OpenTelemetry.Sdk.CreateMeterProviderBuilder() -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Sdk.CreateTracerProviderBuilder() -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Sdk.SetDefaultTextMapPropagator(OpenTelemetry.Context.Propagation.TextMapPropagator! textMapPropagator) -> void diff --git a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt index 4bd71b5f99c..3eda3ba51a9 100644 --- a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt @@ -17,6 +17,7 @@ OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double OpenTelemetry.Metrics.MetricPoint.HasMinMax() -> bool +OpenTelemetry.Resources.ResourceBuilder.AddDetector(System.Func! resourceDetectorFactory) -> OpenTelemetry.Resources.ResourceBuilder! OpenTelemetry.Trace.BatchExportActivityProcessorOptions.BatchExportActivityProcessorOptions(Microsoft.Extensions.Configuration.IConfiguration! configuration) -> void static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! diff --git a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Shipped.txt b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Shipped.txt index 782248e7e3a..5cb58ce6d58 100644 --- a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Shipped.txt +++ b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Shipped.txt @@ -42,9 +42,9 @@ OpenTelemetry.Metrics.MetricReaderOptions.PeriodicExportingMetricReaderOptions.s ~OpenTelemetry.Resources.Resource.Attributes.get -> System.Collections.Generic.IEnumerable> ~OpenTelemetry.Resources.Resource.Merge(OpenTelemetry.Resources.Resource other) -> OpenTelemetry.Resources.Resource ~OpenTelemetry.Resources.Resource.Resource(System.Collections.Generic.IEnumerable> attributes) -> void -~OpenTelemetry.Resources.ResourceBuilder.AddDetector(OpenTelemetry.Resources.IResourceDetector resourceDetector) -> OpenTelemetry.Resources.ResourceBuilder -~OpenTelemetry.Resources.ResourceBuilder.Build() -> OpenTelemetry.Resources.Resource -~OpenTelemetry.Resources.ResourceBuilder.Clear() -> OpenTelemetry.Resources.ResourceBuilder +OpenTelemetry.Resources.ResourceBuilder.AddDetector(OpenTelemetry.Resources.IResourceDetector! resourceDetector) -> OpenTelemetry.Resources.ResourceBuilder! +OpenTelemetry.Resources.ResourceBuilder.Build() -> OpenTelemetry.Resources.Resource! +OpenTelemetry.Resources.ResourceBuilder.Clear() -> OpenTelemetry.Resources.ResourceBuilder! ~OpenTelemetry.SimpleActivityExportProcessor.SimpleActivityExportProcessor(OpenTelemetry.BaseExporter exporter) -> void OpenTelemetry.SimpleExportProcessor OpenTelemetry.SimpleExportProcessor.SimpleExportProcessor(OpenTelemetry.BaseExporter! exporter) -> void @@ -88,12 +88,12 @@ static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.SetResourceBuilder(t ~static OpenTelemetry.ProviderExtensions.GetDefaultResource(this OpenTelemetry.BaseProvider baseProvider) -> OpenTelemetry.Resources.Resource ~static OpenTelemetry.ProviderExtensions.GetResource(this OpenTelemetry.BaseProvider baseProvider) -> OpenTelemetry.Resources.Resource ~static OpenTelemetry.Resources.Resource.Empty.get -> OpenTelemetry.Resources.Resource -~static OpenTelemetry.Resources.ResourceBuilder.CreateDefault() -> OpenTelemetry.Resources.ResourceBuilder -~static OpenTelemetry.Resources.ResourceBuilder.CreateEmpty() -> OpenTelemetry.Resources.ResourceBuilder -~static OpenTelemetry.Resources.ResourceBuilderExtensions.AddAttributes(this OpenTelemetry.Resources.ResourceBuilder resourceBuilder, System.Collections.Generic.IEnumerable> attributes) -> OpenTelemetry.Resources.ResourceBuilder -~static OpenTelemetry.Resources.ResourceBuilderExtensions.AddEnvironmentVariableDetector(this OpenTelemetry.Resources.ResourceBuilder resourceBuilder) -> OpenTelemetry.Resources.ResourceBuilder -~static OpenTelemetry.Resources.ResourceBuilderExtensions.AddService(this OpenTelemetry.Resources.ResourceBuilder resourceBuilder, string serviceName, string serviceNamespace = null, string serviceVersion = null, bool autoGenerateServiceInstanceId = true, string serviceInstanceId = null) -> OpenTelemetry.Resources.ResourceBuilder -~static OpenTelemetry.Resources.ResourceBuilderExtensions.AddTelemetrySdk(this OpenTelemetry.Resources.ResourceBuilder resourceBuilder) -> OpenTelemetry.Resources.ResourceBuilder +static OpenTelemetry.Resources.ResourceBuilder.CreateDefault() -> OpenTelemetry.Resources.ResourceBuilder! +static OpenTelemetry.Resources.ResourceBuilder.CreateEmpty() -> OpenTelemetry.Resources.ResourceBuilder! +static OpenTelemetry.Resources.ResourceBuilderExtensions.AddAttributes(this OpenTelemetry.Resources.ResourceBuilder! resourceBuilder, System.Collections.Generic.IEnumerable>! attributes) -> OpenTelemetry.Resources.ResourceBuilder! +static OpenTelemetry.Resources.ResourceBuilderExtensions.AddEnvironmentVariableDetector(this OpenTelemetry.Resources.ResourceBuilder! resourceBuilder) -> OpenTelemetry.Resources.ResourceBuilder! +static OpenTelemetry.Resources.ResourceBuilderExtensions.AddService(this OpenTelemetry.Resources.ResourceBuilder! resourceBuilder, string! serviceName, string? serviceNamespace = null, string? serviceVersion = null, bool autoGenerateServiceInstanceId = true, string? serviceInstanceId = null) -> OpenTelemetry.Resources.ResourceBuilder! +static OpenTelemetry.Resources.ResourceBuilderExtensions.AddTelemetrySdk(this OpenTelemetry.Resources.ResourceBuilder! resourceBuilder) -> OpenTelemetry.Resources.ResourceBuilder! static OpenTelemetry.Sdk.CreateMeterProviderBuilder() -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Sdk.CreateTracerProviderBuilder() -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Sdk.SetDefaultTextMapPropagator(OpenTelemetry.Context.Propagation.TextMapPropagator! textMapPropagator) -> void diff --git a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt index 4bd71b5f99c..3eda3ba51a9 100644 --- a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt @@ -17,6 +17,7 @@ OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double OpenTelemetry.Metrics.MetricPoint.HasMinMax() -> bool +OpenTelemetry.Resources.ResourceBuilder.AddDetector(System.Func! resourceDetectorFactory) -> OpenTelemetry.Resources.ResourceBuilder! OpenTelemetry.Trace.BatchExportActivityProcessorOptions.BatchExportActivityProcessorOptions(Microsoft.Extensions.Configuration.IConfiguration! configuration) -> void static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! diff --git a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Shipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Shipped.txt index 782248e7e3a..5cb58ce6d58 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Shipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Shipped.txt @@ -42,9 +42,9 @@ OpenTelemetry.Metrics.MetricReaderOptions.PeriodicExportingMetricReaderOptions.s ~OpenTelemetry.Resources.Resource.Attributes.get -> System.Collections.Generic.IEnumerable> ~OpenTelemetry.Resources.Resource.Merge(OpenTelemetry.Resources.Resource other) -> OpenTelemetry.Resources.Resource ~OpenTelemetry.Resources.Resource.Resource(System.Collections.Generic.IEnumerable> attributes) -> void -~OpenTelemetry.Resources.ResourceBuilder.AddDetector(OpenTelemetry.Resources.IResourceDetector resourceDetector) -> OpenTelemetry.Resources.ResourceBuilder -~OpenTelemetry.Resources.ResourceBuilder.Build() -> OpenTelemetry.Resources.Resource -~OpenTelemetry.Resources.ResourceBuilder.Clear() -> OpenTelemetry.Resources.ResourceBuilder +OpenTelemetry.Resources.ResourceBuilder.AddDetector(OpenTelemetry.Resources.IResourceDetector! resourceDetector) -> OpenTelemetry.Resources.ResourceBuilder! +OpenTelemetry.Resources.ResourceBuilder.Build() -> OpenTelemetry.Resources.Resource! +OpenTelemetry.Resources.ResourceBuilder.Clear() -> OpenTelemetry.Resources.ResourceBuilder! ~OpenTelemetry.SimpleActivityExportProcessor.SimpleActivityExportProcessor(OpenTelemetry.BaseExporter exporter) -> void OpenTelemetry.SimpleExportProcessor OpenTelemetry.SimpleExportProcessor.SimpleExportProcessor(OpenTelemetry.BaseExporter! exporter) -> void @@ -88,12 +88,12 @@ static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.SetResourceBuilder(t ~static OpenTelemetry.ProviderExtensions.GetDefaultResource(this OpenTelemetry.BaseProvider baseProvider) -> OpenTelemetry.Resources.Resource ~static OpenTelemetry.ProviderExtensions.GetResource(this OpenTelemetry.BaseProvider baseProvider) -> OpenTelemetry.Resources.Resource ~static OpenTelemetry.Resources.Resource.Empty.get -> OpenTelemetry.Resources.Resource -~static OpenTelemetry.Resources.ResourceBuilder.CreateDefault() -> OpenTelemetry.Resources.ResourceBuilder -~static OpenTelemetry.Resources.ResourceBuilder.CreateEmpty() -> OpenTelemetry.Resources.ResourceBuilder -~static OpenTelemetry.Resources.ResourceBuilderExtensions.AddAttributes(this OpenTelemetry.Resources.ResourceBuilder resourceBuilder, System.Collections.Generic.IEnumerable> attributes) -> OpenTelemetry.Resources.ResourceBuilder -~static OpenTelemetry.Resources.ResourceBuilderExtensions.AddEnvironmentVariableDetector(this OpenTelemetry.Resources.ResourceBuilder resourceBuilder) -> OpenTelemetry.Resources.ResourceBuilder -~static OpenTelemetry.Resources.ResourceBuilderExtensions.AddService(this OpenTelemetry.Resources.ResourceBuilder resourceBuilder, string serviceName, string serviceNamespace = null, string serviceVersion = null, bool autoGenerateServiceInstanceId = true, string serviceInstanceId = null) -> OpenTelemetry.Resources.ResourceBuilder -~static OpenTelemetry.Resources.ResourceBuilderExtensions.AddTelemetrySdk(this OpenTelemetry.Resources.ResourceBuilder resourceBuilder) -> OpenTelemetry.Resources.ResourceBuilder +static OpenTelemetry.Resources.ResourceBuilder.CreateDefault() -> OpenTelemetry.Resources.ResourceBuilder! +static OpenTelemetry.Resources.ResourceBuilder.CreateEmpty() -> OpenTelemetry.Resources.ResourceBuilder! +static OpenTelemetry.Resources.ResourceBuilderExtensions.AddAttributes(this OpenTelemetry.Resources.ResourceBuilder! resourceBuilder, System.Collections.Generic.IEnumerable>! attributes) -> OpenTelemetry.Resources.ResourceBuilder! +static OpenTelemetry.Resources.ResourceBuilderExtensions.AddEnvironmentVariableDetector(this OpenTelemetry.Resources.ResourceBuilder! resourceBuilder) -> OpenTelemetry.Resources.ResourceBuilder! +static OpenTelemetry.Resources.ResourceBuilderExtensions.AddService(this OpenTelemetry.Resources.ResourceBuilder! resourceBuilder, string! serviceName, string? serviceNamespace = null, string? serviceVersion = null, bool autoGenerateServiceInstanceId = true, string? serviceInstanceId = null) -> OpenTelemetry.Resources.ResourceBuilder! +static OpenTelemetry.Resources.ResourceBuilderExtensions.AddTelemetrySdk(this OpenTelemetry.Resources.ResourceBuilder! resourceBuilder) -> OpenTelemetry.Resources.ResourceBuilder! static OpenTelemetry.Sdk.CreateMeterProviderBuilder() -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Sdk.CreateTracerProviderBuilder() -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Sdk.SetDefaultTextMapPropagator(OpenTelemetry.Context.Propagation.TextMapPropagator! textMapPropagator) -> void diff --git a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index 4bd71b5f99c..3eda3ba51a9 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -17,6 +17,7 @@ OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double OpenTelemetry.Metrics.MetricPoint.HasMinMax() -> bool +OpenTelemetry.Resources.ResourceBuilder.AddDetector(System.Func! resourceDetectorFactory) -> OpenTelemetry.Resources.ResourceBuilder! OpenTelemetry.Trace.BatchExportActivityProcessorOptions.BatchExportActivityProcessorOptions(Microsoft.Extensions.Configuration.IConfiguration! configuration) -> void static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! diff --git a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Shipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Shipped.txt index 782248e7e3a..5cb58ce6d58 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Shipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Shipped.txt @@ -42,9 +42,9 @@ OpenTelemetry.Metrics.MetricReaderOptions.PeriodicExportingMetricReaderOptions.s ~OpenTelemetry.Resources.Resource.Attributes.get -> System.Collections.Generic.IEnumerable> ~OpenTelemetry.Resources.Resource.Merge(OpenTelemetry.Resources.Resource other) -> OpenTelemetry.Resources.Resource ~OpenTelemetry.Resources.Resource.Resource(System.Collections.Generic.IEnumerable> attributes) -> void -~OpenTelemetry.Resources.ResourceBuilder.AddDetector(OpenTelemetry.Resources.IResourceDetector resourceDetector) -> OpenTelemetry.Resources.ResourceBuilder -~OpenTelemetry.Resources.ResourceBuilder.Build() -> OpenTelemetry.Resources.Resource -~OpenTelemetry.Resources.ResourceBuilder.Clear() -> OpenTelemetry.Resources.ResourceBuilder +OpenTelemetry.Resources.ResourceBuilder.AddDetector(OpenTelemetry.Resources.IResourceDetector! resourceDetector) -> OpenTelemetry.Resources.ResourceBuilder! +OpenTelemetry.Resources.ResourceBuilder.Build() -> OpenTelemetry.Resources.Resource! +OpenTelemetry.Resources.ResourceBuilder.Clear() -> OpenTelemetry.Resources.ResourceBuilder! ~OpenTelemetry.SimpleActivityExportProcessor.SimpleActivityExportProcessor(OpenTelemetry.BaseExporter exporter) -> void OpenTelemetry.SimpleExportProcessor OpenTelemetry.SimpleExportProcessor.SimpleExportProcessor(OpenTelemetry.BaseExporter! exporter) -> void @@ -88,12 +88,12 @@ static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.SetResourceBuilder(t ~static OpenTelemetry.ProviderExtensions.GetDefaultResource(this OpenTelemetry.BaseProvider baseProvider) -> OpenTelemetry.Resources.Resource ~static OpenTelemetry.ProviderExtensions.GetResource(this OpenTelemetry.BaseProvider baseProvider) -> OpenTelemetry.Resources.Resource ~static OpenTelemetry.Resources.Resource.Empty.get -> OpenTelemetry.Resources.Resource -~static OpenTelemetry.Resources.ResourceBuilder.CreateDefault() -> OpenTelemetry.Resources.ResourceBuilder -~static OpenTelemetry.Resources.ResourceBuilder.CreateEmpty() -> OpenTelemetry.Resources.ResourceBuilder -~static OpenTelemetry.Resources.ResourceBuilderExtensions.AddAttributes(this OpenTelemetry.Resources.ResourceBuilder resourceBuilder, System.Collections.Generic.IEnumerable> attributes) -> OpenTelemetry.Resources.ResourceBuilder -~static OpenTelemetry.Resources.ResourceBuilderExtensions.AddEnvironmentVariableDetector(this OpenTelemetry.Resources.ResourceBuilder resourceBuilder) -> OpenTelemetry.Resources.ResourceBuilder -~static OpenTelemetry.Resources.ResourceBuilderExtensions.AddService(this OpenTelemetry.Resources.ResourceBuilder resourceBuilder, string serviceName, string serviceNamespace = null, string serviceVersion = null, bool autoGenerateServiceInstanceId = true, string serviceInstanceId = null) -> OpenTelemetry.Resources.ResourceBuilder -~static OpenTelemetry.Resources.ResourceBuilderExtensions.AddTelemetrySdk(this OpenTelemetry.Resources.ResourceBuilder resourceBuilder) -> OpenTelemetry.Resources.ResourceBuilder +static OpenTelemetry.Resources.ResourceBuilder.CreateDefault() -> OpenTelemetry.Resources.ResourceBuilder! +static OpenTelemetry.Resources.ResourceBuilder.CreateEmpty() -> OpenTelemetry.Resources.ResourceBuilder! +static OpenTelemetry.Resources.ResourceBuilderExtensions.AddAttributes(this OpenTelemetry.Resources.ResourceBuilder! resourceBuilder, System.Collections.Generic.IEnumerable>! attributes) -> OpenTelemetry.Resources.ResourceBuilder! +static OpenTelemetry.Resources.ResourceBuilderExtensions.AddEnvironmentVariableDetector(this OpenTelemetry.Resources.ResourceBuilder! resourceBuilder) -> OpenTelemetry.Resources.ResourceBuilder! +static OpenTelemetry.Resources.ResourceBuilderExtensions.AddService(this OpenTelemetry.Resources.ResourceBuilder! resourceBuilder, string! serviceName, string? serviceNamespace = null, string? serviceVersion = null, bool autoGenerateServiceInstanceId = true, string? serviceInstanceId = null) -> OpenTelemetry.Resources.ResourceBuilder! +static OpenTelemetry.Resources.ResourceBuilderExtensions.AddTelemetrySdk(this OpenTelemetry.Resources.ResourceBuilder! resourceBuilder) -> OpenTelemetry.Resources.ResourceBuilder! static OpenTelemetry.Sdk.CreateMeterProviderBuilder() -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Sdk.CreateTracerProviderBuilder() -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Sdk.SetDefaultTextMapPropagator(OpenTelemetry.Context.Propagation.TextMapPropagator! textMapPropagator) -> void diff --git a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt index 4bd71b5f99c..3eda3ba51a9 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt @@ -17,6 +17,7 @@ OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double OpenTelemetry.Metrics.MetricPoint.HasMinMax() -> bool +OpenTelemetry.Resources.ResourceBuilder.AddDetector(System.Func! resourceDetectorFactory) -> OpenTelemetry.Resources.ResourceBuilder! OpenTelemetry.Trace.BatchExportActivityProcessorOptions.BatchExportActivityProcessorOptions(Microsoft.Extensions.Configuration.IConfiguration! configuration) -> void static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index 563550db2a1..60696a792b6 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -8,6 +8,11 @@ ([#3760](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3760), [#3776](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3776)) +* Added dependency injection support in the `ResourceBuilder` class and added + support for loading environment variables from `IConfiguration` for the + `AddEnvironmentVariableDetector` extension + ([#XXXX](https://github.com/open-telemetry/opentelemetry-dotnet/pull/XXXX)) + ## 1.4.0-beta.2 Released 2022-Oct-17 diff --git a/src/OpenTelemetry/Internal/EnvironmentVariableHelper.cs b/src/OpenTelemetry/Internal/EnvironmentVariableHelper.cs deleted file mode 100644 index 6a745e4ad11..00000000000 --- a/src/OpenTelemetry/Internal/EnvironmentVariableHelper.cs +++ /dev/null @@ -1,162 +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 System.Globalization; -using System.Security; - -namespace OpenTelemetry.Internal -{ - /// - /// EnvironmentVariableHelper facilitates parsing environment variable values as defined by - /// - /// the specification. - /// - internal static class EnvironmentVariableHelper - { - /// - /// Reads an environment variable without any parsing. - /// - /// The name of the environment variable. - /// The parsed value of the environment variable. - /// - /// Returns true when a non-empty value was read; otherwise, false. - /// - public static bool LoadString(string envVarKey, out string result) - { - result = null; - - try - { - result = Environment.GetEnvironmentVariable(envVarKey); - } - catch (SecurityException ex) - { - // The caller does not have the required permission to - // retrieve the value of an environment variable from the current process. - OpenTelemetrySdkEventSource.Log.MissingPermissionsToReadEnvironmentVariable(ex); - return false; - } - - return !string.IsNullOrEmpty(result); - } - - /// - /// Reads an environment variable and parses is as a - /// - /// numeric value - a non-negative decimal integer. - /// - /// The name of the environment variable. - /// The parsed value of the environment variable. - /// - /// Returns true when a non-empty value was read; otherwise, false. - /// - /// - /// Thrown when failed to parse the non-empty value. - /// - public static bool LoadNumeric(string envVarKey, out int result) - { - result = 0; - - if (!LoadString(envVarKey, out string value)) - { - return false; - } - - return LoadNumeric(envVarKey, value, out result); - } - - /// - /// Reads an environment variable and parses is as a - /// - /// numeric value - a non-negative decimal integer. - /// - /// The name of the environment variable. - /// The value of the environment variable. - /// The parsed value of the environment variable. - /// - /// Returns true when a non-empty value was read; otherwise, false. - /// - /// - /// Thrown when failed to parse the non-empty value. - /// - public static bool LoadNumeric(string envVarKey, string value, out int result) - { - if (!int.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out result)) - { - throw new FormatException($"{envVarKey} environment variable has an invalid value: '{value}'"); - } - - return true; - } - - /// - /// Reads an environment variable and parses it as a . - /// - /// The name of the environment variable. - /// The parsed value of the environment variable. - /// - /// Returns true when a non-empty value was read; otherwise, false. - /// - /// - /// Thrown when failed to parse the non-empty value. - /// - public static bool LoadUri(string envVarKey, out Uri result) - { - result = null; - - if (!LoadString(envVarKey, out string value)) - { - return false; - } - - if (!Uri.TryCreate(value, UriKind.Absolute, out result)) - { - throw new FormatException($"{envVarKey} environment variable has an invalid value: '${value}'"); - } - - return true; - } - - /// - /// Reads an environment variable and parses it as a . - /// - /// The name of the environment variable. - /// The parsed value of the environment variable. - /// - /// Returns true when a non-empty value was read; otherwise, false. - /// - /// - /// Thrown when failed to parse the non-empty value. - /// - public static bool LoadBoolean(string envVarKey, out bool result) - { - result = default; - - if (!LoadString(envVarKey, out string value)) - { - return false; - } - - if (!bool.TryParse(value, out result)) - { - throw new FormatException($"{envVarKey} environment variable has an invalid value: '${value}'"); - } - - return true; - } - } -} diff --git a/src/OpenTelemetry/Metrics/MeterProviderSdk.cs b/src/OpenTelemetry/Metrics/MeterProviderSdk.cs index 223290a210e..de38cf4d8a0 100644 --- a/src/OpenTelemetry/Metrics/MeterProviderSdk.cs +++ b/src/OpenTelemetry/Metrics/MeterProviderSdk.cs @@ -61,7 +61,10 @@ internal MeterProviderSdk( StringBuilder exportersAdded = new StringBuilder(); StringBuilder instrumentationFactoriesAdded = new StringBuilder(); - this.Resource = (state.ResourceBuilder ?? ResourceBuilder.CreateDefault()).Build(); + var resourceBuilder = state.ResourceBuilder ?? ResourceBuilder.CreateDefault(); + resourceBuilder.ServiceProvider = serviceProvider; + this.Resource = resourceBuilder.Build(); + this.viewConfigs = state.ViewConfigs; foreach (var reader in state.Readers) diff --git a/src/OpenTelemetry/Resources/OtelEnvResourceDetector.cs b/src/OpenTelemetry/Resources/OtelEnvResourceDetector.cs index fd78b3eba4f..06ca1d44875 100644 --- a/src/OpenTelemetry/Resources/OtelEnvResourceDetector.cs +++ b/src/OpenTelemetry/Resources/OtelEnvResourceDetector.cs @@ -15,21 +15,29 @@ // using System.Collections.Generic; +using Microsoft.Extensions.Configuration; using OpenTelemetry.Internal; namespace OpenTelemetry.Resources { - internal class OtelEnvResourceDetector : IResourceDetector + internal sealed class OtelEnvResourceDetector : IResourceDetector { public const string EnvVarKey = "OTEL_RESOURCE_ATTRIBUTES"; private const char AttributeListSplitter = ','; private const char AttributeKeyValueSplitter = '='; + private readonly IConfiguration configuration; + + public OtelEnvResourceDetector(IConfiguration configuration) + { + this.configuration = configuration; + } + public Resource Detect() { var resource = Resource.Empty; - if (EnvironmentVariableHelper.LoadString(EnvVarKey, out string envResourceAttributeValue)) + if (this.configuration.TryGetStringValue(EnvVarKey, out string envResourceAttributeValue)) { var attributes = ParseResourceAttributes(envResourceAttributeValue); resource = new Resource(attributes); diff --git a/src/OpenTelemetry/Resources/OtelServiceNameEnvVarDetector.cs b/src/OpenTelemetry/Resources/OtelServiceNameEnvVarDetector.cs index 5233f2004a4..1cca514a026 100644 --- a/src/OpenTelemetry/Resources/OtelServiceNameEnvVarDetector.cs +++ b/src/OpenTelemetry/Resources/OtelServiceNameEnvVarDetector.cs @@ -15,19 +15,27 @@ // using System.Collections.Generic; +using Microsoft.Extensions.Configuration; using OpenTelemetry.Internal; namespace OpenTelemetry.Resources { - internal class OtelServiceNameEnvVarDetector : IResourceDetector + internal sealed class OtelServiceNameEnvVarDetector : IResourceDetector { public const string EnvVarKey = "OTEL_SERVICE_NAME"; + private readonly IConfiguration configuration; + + public OtelServiceNameEnvVarDetector(IConfiguration configuration) + { + this.configuration = configuration; + } + public Resource Detect() { var resource = Resource.Empty; - if (EnvironmentVariableHelper.LoadString(EnvVarKey, out string envResourceAttributeValue)) + if (this.configuration.TryGetStringValue(EnvVarKey, out string envResourceAttributeValue)) { resource = new Resource(new Dictionary { diff --git a/src/OpenTelemetry/Resources/ResourceBuilder.cs b/src/OpenTelemetry/Resources/ResourceBuilder.cs index fec087699c1..b2bf0370470 100644 --- a/src/OpenTelemetry/Resources/ResourceBuilder.cs +++ b/src/OpenTelemetry/Resources/ResourceBuilder.cs @@ -14,6 +14,9 @@ // limitations under the License. // +#nullable enable + +using System; using System.Collections.Generic; using System.Diagnostics; using OpenTelemetry.Internal; @@ -25,7 +28,8 @@ namespace OpenTelemetry.Resources /// public class ResourceBuilder { - internal readonly List Resources = new(); + internal readonly List ResourceDetectors = new(); + private static readonly Resource DefaultResource; static ResourceBuilder() { @@ -54,7 +58,7 @@ private ResourceBuilder() { } - private static Resource DefaultResource { get; } + internal IServiceProvider? ServiceProvider { get; set; } /// /// Creates a instance with Default @@ -83,7 +87,7 @@ public static ResourceBuilder CreateEmpty() /// for chaining. public ResourceBuilder Clear() { - this.Resources.Clear(); + this.ResourceDetectors.Clear(); return this; } @@ -96,24 +100,55 @@ public Resource Build() { Resource finalResource = Resource.Empty; - foreach (Resource resource in this.Resources) + foreach (IResourceDetector resourceDetector in this.ResourceDetectors) { - finalResource = finalResource.Merge(resource); + if (resourceDetector is ResolvingResourceDetector resolvingResourceDetector) + { + resolvingResourceDetector.Resolve(this.ServiceProvider); + } + + var resource = resourceDetector.Detect(); + if (resource != null) + { + finalResource = finalResource.Merge(resource); + } } return finalResource; } + /// + /// Add a to the builder. + /// + /// . + /// Supplied for call chaining. public ResourceBuilder AddDetector(IResourceDetector resourceDetector) { Guard.ThrowIfNull(resourceDetector); - Resource resource = resourceDetector.Detect(); + this.ResourceDetectors.Add(resourceDetector); - if (resource != null) - { - this.Resources.Add(resource); - } + return this; + } + + /// + /// Add a to the builder which will be resolved using the application . + /// + /// + /// Note: The supplied may be + /// called with a + /// for detached instances. Factories + /// should either throw if a cannot be handled, + /// or return a default when is not available. + /// + /// Resource detector factory. + /// Supplied for call chaining. + public ResourceBuilder AddDetector(Func resourceDetectorFactory) + { + Guard.ThrowIfNull(resourceDetectorFactory); + + this.ResourceDetectors.Add(new ResolvingResourceDetector(resourceDetectorFactory)); return this; } @@ -122,9 +157,47 @@ internal ResourceBuilder AddResource(Resource resource) { Guard.ThrowIfNull(resource); - this.Resources.Add(resource); + this.ResourceDetectors.Add(new WrapperResourceDetector(resource)); return this; } + + private sealed class WrapperResourceDetector : IResourceDetector + { + private readonly Resource resource; + + public WrapperResourceDetector(Resource resource) + { + this.resource = resource; + } + + public Resource Detect() => this.resource; + } + + private sealed class ResolvingResourceDetector : IResourceDetector + { + private readonly Func resourceDetectorFactory; + private IResourceDetector? resourceDetector; + + public ResolvingResourceDetector(Func resourceDetectorFactory) + { + this.resourceDetectorFactory = resourceDetectorFactory; + } + + public void Resolve(IServiceProvider? serviceProvider) + { + this.resourceDetector = this.resourceDetectorFactory(serviceProvider) + ?? throw new InvalidOperationException("ResourceDetector factory did not return a ResourceDetector instance."); + } + + public Resource Detect() + { + var detector = this.resourceDetector; + + Debug.Assert(detector != null, "detector was null"); + + return detector?.Detect() ?? Resource.Empty; + } + } } } diff --git a/src/OpenTelemetry/Resources/ResourceBuilderExtensions.cs b/src/OpenTelemetry/Resources/ResourceBuilderExtensions.cs index 338ef61341b..c68ee7ece59 100644 --- a/src/OpenTelemetry/Resources/ResourceBuilderExtensions.cs +++ b/src/OpenTelemetry/Resources/ResourceBuilderExtensions.cs @@ -14,9 +14,13 @@ // limitations under the License. // +#nullable enable + using System; using System.Collections.Generic; using System.Reflection; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; using OpenTelemetry.Internal; namespace OpenTelemetry.Resources @@ -49,10 +53,10 @@ public static class ResourceBuilderExtensions public static ResourceBuilder AddService( this ResourceBuilder resourceBuilder, string serviceName, - string serviceNamespace = null, - string serviceVersion = null, + string? serviceNamespace = null, + string? serviceVersion = null, bool autoGenerateServiceInstanceId = true, - string serviceInstanceId = null) + string? serviceInstanceId = null) { Dictionary resourceAttributes = new Dictionary(); @@ -62,12 +66,12 @@ public static ResourceBuilder AddService( if (!string.IsNullOrEmpty(serviceNamespace)) { - resourceAttributes.Add(ResourceSemanticConventions.AttributeServiceNamespace, serviceNamespace); + resourceAttributes.Add(ResourceSemanticConventions.AttributeServiceNamespace, serviceNamespace!); } if (!string.IsNullOrEmpty(serviceVersion)) { - resourceAttributes.Add(ResourceSemanticConventions.AttributeServiceVersion, serviceVersion); + resourceAttributes.Add(ResourceSemanticConventions.AttributeServiceVersion, serviceVersion!); } if (serviceInstanceId == null && autoGenerateServiceInstanceId) @@ -117,7 +121,11 @@ public static ResourceBuilder AddAttributes(this ResourceBuilder resourceBuilder /// Returns for chaining. public static ResourceBuilder AddEnvironmentVariableDetector(this ResourceBuilder resourceBuilder) { - return resourceBuilder.AddDetector(new OtelEnvResourceDetector()).AddDetector(new OtelServiceNameEnvVarDetector()); + Lazy configuration = new Lazy(() => new ConfigurationBuilder().AddEnvironmentVariables().Build()); + + return resourceBuilder + .AddDetector(sp => new OtelEnvResourceDetector(sp?.GetService() ?? configuration.Value)) + .AddDetector(sp => new OtelServiceNameEnvVarDetector(sp?.GetService() ?? configuration.Value)); } private static string GetFileVersion() diff --git a/src/OpenTelemetry/Trace/TracerProviderSdk.cs b/src/OpenTelemetry/Trace/TracerProviderSdk.cs index b8b0f14919f..20485c43a62 100644 --- a/src/OpenTelemetry/Trace/TracerProviderSdk.cs +++ b/src/OpenTelemetry/Trace/TracerProviderSdk.cs @@ -66,7 +66,10 @@ internal TracerProviderSdk( state.EnableErrorStatusOnException(); } - this.Resource = (state.ResourceBuilder ?? ResourceBuilder.CreateDefault()).Build(); + var resourceBuilder = state.ResourceBuilder ?? ResourceBuilder.CreateDefault(); + resourceBuilder.ServiceProvider = serviceProvider; + this.Resource = resourceBuilder.Build(); + this.sampler = state.Sampler ?? new ParentBasedSampler(new AlwaysOnSampler()); this.supportLegacyActivity = state.LegacyActivityOperationNames.Count > 0; diff --git a/test/OpenTelemetry.Tests/Internal/EnvironmentVariableHelperTests.cs b/test/OpenTelemetry.Tests/Internal/EnvironmentVariableHelperTests.cs deleted file mode 100644 index 738fa27b9b3..00000000000 --- a/test/OpenTelemetry.Tests/Internal/EnvironmentVariableHelperTests.cs +++ /dev/null @@ -1,165 +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 Xunit; - -namespace OpenTelemetry.Internal.Tests -{ - public class EnvironmentVariableHelperTests : IDisposable - { - private const string EnvVar = "OTEL_EXAMPLE_VARIABLE"; - - public EnvironmentVariableHelperTests() - { - Environment.SetEnvironmentVariable(EnvVar, null); - } - - public void Dispose() - { - Environment.SetEnvironmentVariable(EnvVar, null); - GC.SuppressFinalize(this); - } - - [Fact] - public void LoadString() - { - const string value = "something"; - Environment.SetEnvironmentVariable(EnvVar, value); - - bool actualBool = EnvironmentVariableHelper.LoadString(EnvVar, out string actualValue); - - Assert.True(actualBool); - Assert.Equal(value, actualValue); - } - - [Fact] - public void LoadString_NoValue() - { - bool actualBool = EnvironmentVariableHelper.LoadString(EnvVar, out string actualValue); - - Assert.False(actualBool); - Assert.Null(actualValue); - } - - [Theory] - [InlineData("true", true)] - [InlineData("TRUE", true)] - [InlineData("false", false)] - [InlineData("FALSE", false)] - [InlineData(" true ", true)] - [InlineData(" false ", false)] - public void LoadBoolean(string value, bool expectedValue) - { - Environment.SetEnvironmentVariable(EnvVar, value); - - bool actualBool = EnvironmentVariableHelper.LoadBoolean(EnvVar, out bool actualValue); - - Assert.True(actualBool); - Assert.Equal(expectedValue, actualValue); - } - - [Fact] - public void LoadBoolean_NoValue() - { - bool actualBool = EnvironmentVariableHelper.LoadBoolean(EnvVar, out bool actualValue); - - Assert.False(actualBool); - Assert.False(actualValue); - } - - [Theory] - [InlineData("something")] // non true/false - [InlineData(" ")] // whitespaces - [InlineData("0")] // 0 - [InlineData("1")] // 1 - public void LoadBoolean_Invalid(string value) - { - Environment.SetEnvironmentVariable(EnvVar, value); - - Assert.Throws(() => EnvironmentVariableHelper.LoadBoolean(EnvVar, out bool _)); - } - - [Theory] - [InlineData("123", 123)] - [InlineData("0", 0)] - public void LoadNumeric(string value, int expectedValue) - { - Environment.SetEnvironmentVariable(EnvVar, value); - - bool actualBool = EnvironmentVariableHelper.LoadNumeric(EnvVar, out int actualValue); - - Assert.True(actualBool); - Assert.Equal(expectedValue, actualValue); - } - - [Fact] - public void LoadNumeric_NoValue() - { - bool actualBool = EnvironmentVariableHelper.LoadNumeric(EnvVar, out int actualValue); - - Assert.False(actualBool); - Assert.Equal(0, actualValue); - } - - [Theory] - [InlineData("something")] // NaN - [InlineData("-12")] // negative number not allowed - [InlineData("-0")] // sign not allowed - [InlineData("-1")] // -1 is not allowed - [InlineData(" 123 ")] // whitespaces not allowed - [InlineData("0xFF")] // only decimal number allowed - public void LoadNumeric_Invalid(string value) - { - Environment.SetEnvironmentVariable(EnvVar, value); - - Assert.Throws(() => EnvironmentVariableHelper.LoadNumeric(EnvVar, out int _)); - } - - [Theory] - [InlineData("http://www.example.com", "http://www.example.com/")] - [InlineData("http://www.example.com/space%20here.html", "http://www.example.com/space here.html")] // characters are converted - [InlineData("http://www.example.com/space here.html", "http://www.example.com/space here.html")] // characters are escaped - public void LoadUri(string value, string expectedValue) - { - Environment.SetEnvironmentVariable(EnvVar, value); - - bool actualBool = EnvironmentVariableHelper.LoadUri(EnvVar, out Uri actualValue); - - Assert.True(actualBool); - Assert.Equal(expectedValue, actualValue.ToString()); - } - - [Fact] - public void LoadUri_NoValue() - { - bool actualBool = EnvironmentVariableHelper.LoadUri(EnvVar, out Uri actualValue); - - Assert.False(actualBool); - Assert.Null(actualValue); - } - - [Theory] - [InlineData("invalid")] // invalid format - [InlineData(" ")] // whitespace - public void LoadUri_Invalid(string value) - { - Environment.SetEnvironmentVariable(EnvVar, value); - - Assert.Throws(() => EnvironmentVariableHelper.LoadUri(EnvVar, out Uri _)); - } - } -} diff --git a/test/OpenTelemetry.Tests/Metrics/MeterProviderBuilderExtensionsTests.cs b/test/OpenTelemetry.Tests/Metrics/MeterProviderBuilderExtensionsTests.cs index 7691f22f349..93728977d7a 100644 --- a/test/OpenTelemetry.Tests/Metrics/MeterProviderBuilderExtensionsTests.cs +++ b/test/OpenTelemetry.Tests/Metrics/MeterProviderBuilderExtensionsTests.cs @@ -174,22 +174,22 @@ public void SetAndConfigureResourceTest() { configureInvocations++; - Assert.Single(builder.Resources); + Assert.Single(builder.ResourceDetectors); builder.AddAttributes(new Dictionary() { ["key1"] = "value1" }); - Assert.Equal(2, builder.Resources.Count); + Assert.Equal(2, builder.ResourceDetectors.Count); }); builder.SetResourceBuilder(ResourceBuilder.CreateEmpty()); builder.ConfigureResource(builder => { configureInvocations++; - Assert.Empty(builder.Resources); + Assert.Empty(builder.ResourceDetectors); builder.AddAttributes(new Dictionary() { ["key2"] = "value2" }); - Assert.Single(builder.Resources); + Assert.Single(builder.ResourceDetectors); }); using var provider = builder.Build() as MeterProviderSdk; diff --git a/test/OpenTelemetry.Tests/Resources/OtelEnvResourceDetectorTest.cs b/test/OpenTelemetry.Tests/Resources/OtelEnvResourceDetectorTest.cs index b0d445c16cc..3485874a17b 100644 --- a/test/OpenTelemetry.Tests/Resources/OtelEnvResourceDetectorTest.cs +++ b/test/OpenTelemetry.Tests/Resources/OtelEnvResourceDetectorTest.cs @@ -16,6 +16,7 @@ using System; using System.Collections.Generic; +using Microsoft.Extensions.Configuration; using Xunit; namespace OpenTelemetry.Resources.Tests @@ -43,7 +44,9 @@ public void OtelEnvResource_EnvVarKey() public void OtelEnvResource_NullEnvVar() { // Arrange - var resource = new OtelEnvResourceDetector().Detect(); + var resource = new OtelEnvResourceDetector( + new ConfigurationBuilder().AddEnvironmentVariables().Build()) + .Detect(); // Assert Assert.Equal(Resource.Empty, resource); @@ -55,7 +58,9 @@ public void OtelEnvResource_WithEnvVar_1() // Arrange var envVarValue = "Key1=Val1,Key2=Val2"; Environment.SetEnvironmentVariable(OtelEnvResourceDetector.EnvVarKey, envVarValue); - var resource = new OtelEnvResourceDetector().Detect(); + var resource = new OtelEnvResourceDetector( + new ConfigurationBuilder().AddEnvironmentVariables().Build()) + .Detect(); // Assert Assert.NotEqual(Resource.Empty, resource); @@ -68,12 +73,33 @@ public void OtelEnvResource_WithEnvVar_2() // Arrange var envVarValue = "Key1,Key2=Val2"; Environment.SetEnvironmentVariable(OtelEnvResourceDetector.EnvVarKey, envVarValue); - var resource = new OtelEnvResourceDetector().Detect(); + var resource = new OtelEnvResourceDetector( + new ConfigurationBuilder().AddEnvironmentVariables().Build()) + .Detect(); // Assert Assert.NotEqual(Resource.Empty, resource); Assert.Single(resource.Attributes); Assert.Contains(new KeyValuePair("Key2", "Val2"), resource.Attributes); } + + [Fact] + public void OtelEnvResource_UsingIConfiguration() + { + var values = new Dictionary() + { + [OtelEnvResourceDetector.EnvVarKey] = "Key1=Val1,Key2=Val2", + }; + + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(values) + .Build(); + + var resource = new OtelEnvResourceDetector(configuration).Detect(); + + Assert.NotEqual(Resource.Empty, resource); + Assert.Contains(new KeyValuePair("Key1", "Val1"), resource.Attributes); + Assert.Contains(new KeyValuePair("Key2", "Val2"), resource.Attributes); + } } } diff --git a/test/OpenTelemetry.Tests/Resources/OtelServiceNameEnvVarDetectorTests.cs b/test/OpenTelemetry.Tests/Resources/OtelServiceNameEnvVarDetectorTests.cs index 8d5e5f1aeed..c60de6b9ece 100644 --- a/test/OpenTelemetry.Tests/Resources/OtelServiceNameEnvVarDetectorTests.cs +++ b/test/OpenTelemetry.Tests/Resources/OtelServiceNameEnvVarDetectorTests.cs @@ -16,6 +16,7 @@ using System; using System.Collections.Generic; +using Microsoft.Extensions.Configuration; using Xunit; namespace OpenTelemetry.Resources.Tests @@ -43,7 +44,9 @@ public void OtelServiceNameEnvVar_EnvVarKey() public void OtelServiceNameEnvVar_Null() { // Act - var resource = new OtelServiceNameEnvVarDetector().Detect(); + var resource = new OtelServiceNameEnvVarDetector( + new ConfigurationBuilder().AddEnvironmentVariables().Build()) + .Detect(); // Assert Assert.Equal(Resource.Empty, resource); @@ -57,11 +60,31 @@ public void OtelServiceNameEnvVar_WithValue() Environment.SetEnvironmentVariable(OtelServiceNameEnvVarDetector.EnvVarKey, envVarValue); // Act - var resource = new OtelServiceNameEnvVarDetector().Detect(); + var resource = new OtelServiceNameEnvVarDetector( + new ConfigurationBuilder().AddEnvironmentVariables().Build()) + .Detect(); // Assert Assert.NotEqual(Resource.Empty, resource); Assert.Contains(new KeyValuePair(ResourceSemanticConventions.AttributeServiceName, envVarValue), resource.Attributes); } + + [Fact] + public void OtelServiceNameEnvVar_UsingIConfiguration() + { + var values = new Dictionary() + { + [OtelServiceNameEnvVarDetector.EnvVarKey] = "my-service", + }; + + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(values) + .Build(); + + var resource = new OtelServiceNameEnvVarDetector(configuration).Detect(); + + Assert.NotEqual(Resource.Empty, resource); + Assert.Contains(new KeyValuePair(ResourceSemanticConventions.AttributeServiceName, "my-service"), resource.Attributes); + } } } diff --git a/test/OpenTelemetry.Tests/Trace/TracerProviderBuilderExtensionsTest.cs b/test/OpenTelemetry.Tests/Trace/TracerProviderBuilderExtensionsTest.cs index 34cc5a8e3ec..dc6462b2ff2 100644 --- a/test/OpenTelemetry.Tests/Trace/TracerProviderBuilderExtensionsTest.cs +++ b/test/OpenTelemetry.Tests/Trace/TracerProviderBuilderExtensionsTest.cs @@ -260,22 +260,22 @@ public void SetAndConfigureResourceTest() { configureInvocations++; - Assert.Single(builder.Resources); + Assert.Single(builder.ResourceDetectors); builder.AddAttributes(new Dictionary() { ["key1"] = "value1" }); - Assert.Equal(2, builder.Resources.Count); + Assert.Equal(2, builder.ResourceDetectors.Count); }); builder.SetResourceBuilder(ResourceBuilder.CreateEmpty()); builder.ConfigureResource(builder => { configureInvocations++; - Assert.Empty(builder.Resources); + Assert.Empty(builder.ResourceDetectors); builder.AddAttributes(new Dictionary() { ["key2"] = "value2" }); - Assert.Single(builder.Resources); + Assert.Single(builder.ResourceDetectors); }); using var provider = builder.Build() as TracerProviderSdk; From 473a7dcb2c294f43320193c93f30dffa23348ccc Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Tue, 18 Oct 2022 13:24:24 -0700 Subject: [PATCH 2/4] Patch CHANGELOG. --- src/OpenTelemetry/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index 60696a792b6..a98ce37a322 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -11,7 +11,7 @@ * Added dependency injection support in the `ResourceBuilder` class and added support for loading environment variables from `IConfiguration` for the `AddEnvironmentVariableDetector` extension - ([#XXXX](https://github.com/open-telemetry/opentelemetry-dotnet/pull/XXXX)) + ([#3782](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3782)) ## 1.4.0-beta.2 From 1d165246faaadb7ce8b1060b6ac158f60146efd2 Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Tue, 18 Oct 2022 13:33:27 -0700 Subject: [PATCH 3/4] Add ResourceBuilder service provider test. --- .../Resources/ResourceTest.cs | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/test/OpenTelemetry.Tests/Resources/ResourceTest.cs b/test/OpenTelemetry.Tests/Resources/ResourceTest.cs index bd8ab12516d..0777ba092d9 100644 --- a/test/OpenTelemetry.Tests/Resources/ResourceTest.cs +++ b/test/OpenTelemetry.Tests/Resources/ResourceTest.cs @@ -17,6 +17,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.DependencyInjection; using Xunit; namespace OpenTelemetry.Resources.Tests @@ -499,6 +500,45 @@ public void GetResource_WithServiceNameSetWithTwoEnvVarsAndCode() Assert.Contains(new KeyValuePair("service.name", "from-code"), attributes); } + [Fact] + public void ResourceBuilder_ServiceProvider_Available() + { + var builder = ResourceBuilder.CreateDefault(); + + bool nullTestRun = false; + + builder.AddDetector(sp => + { + nullTestRun = true; + Assert.Null(sp); + return new NoopResourceDetector(); + }); + + builder.Build(); + + Assert.True(nullTestRun); + + builder = ResourceBuilder.CreateDefault(); + + bool validTestRun = false; + + var serviceCollection = new ServiceCollection(); + using var serviceProvider = serviceCollection.BuildServiceProvider(); + + builder.ServiceProvider = serviceProvider; + + builder.AddDetector(sp => + { + validTestRun = true; + Assert.NotNull(sp); + return new NoopResourceDetector(); + }); + + builder.Build(); + + Assert.True(validTestRun); + } + private static void ClearEnvVars() { Environment.SetEnvironmentVariable(OtelEnvResourceDetector.EnvVarKey, null); @@ -552,5 +592,10 @@ private static Dictionary CreateAttributes(int attributeCount, i AddAttributes(attributes, attributeCount, startIndex); return attributes; } + + private sealed class NoopResourceDetector : IResourceDetector + { + public Resource Detect() => Resource.Empty; + } } } From 2cf986d2f50c7c4f0734e2513e0f5eff07bba672 Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Tue, 18 Oct 2022 13:44:21 -0700 Subject: [PATCH 4/4] Provider tests. --- src/OpenTelemetry/Resources/ResourceBuilder.cs | 2 +- .../Metrics/MeterProviderBuilderExtensionsTests.cs | 9 ++++++++- .../Trace/TracerProviderBuilderExtensionsTest.cs | 9 ++++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/OpenTelemetry/Resources/ResourceBuilder.cs b/src/OpenTelemetry/Resources/ResourceBuilder.cs index b2bf0370470..7c1ef54fdaa 100644 --- a/src/OpenTelemetry/Resources/ResourceBuilder.cs +++ b/src/OpenTelemetry/Resources/ResourceBuilder.cs @@ -162,7 +162,7 @@ internal ResourceBuilder AddResource(Resource resource) return this; } - private sealed class WrapperResourceDetector : IResourceDetector + internal sealed class WrapperResourceDetector : IResourceDetector { private readonly Resource resource; diff --git a/test/OpenTelemetry.Tests/Metrics/MeterProviderBuilderExtensionsTests.cs b/test/OpenTelemetry.Tests/Metrics/MeterProviderBuilderExtensionsTests.cs index 93728977d7a..1bcd70a9263 100644 --- a/test/OpenTelemetry.Tests/Metrics/MeterProviderBuilderExtensionsTests.cs +++ b/test/OpenTelemetry.Tests/Metrics/MeterProviderBuilderExtensionsTests.cs @@ -168,6 +168,7 @@ public void SetAndConfigureResourceTest() var builder = Sdk.CreateMeterProviderBuilder(); int configureInvocations = 0; + bool serviceProviderTestExecuted = false; builder.SetResourceBuilder(ResourceBuilder.CreateEmpty().AddService("Test")); builder.ConfigureResource(builder => @@ -187,13 +188,19 @@ public void SetAndConfigureResourceTest() Assert.Empty(builder.ResourceDetectors); - builder.AddAttributes(new Dictionary() { ["key2"] = "value2" }); + builder.AddDetector(sp => + { + serviceProviderTestExecuted = true; + Assert.NotNull(sp); + return new ResourceBuilder.WrapperResourceDetector(new Resource(new Dictionary() { ["key2"] = "value2" })); + }); Assert.Single(builder.ResourceDetectors); }); using var provider = builder.Build() as MeterProviderSdk; + Assert.True(serviceProviderTestExecuted); Assert.Equal(2, configureInvocations); Assert.Single(provider.Resource.Attributes); diff --git a/test/OpenTelemetry.Tests/Trace/TracerProviderBuilderExtensionsTest.cs b/test/OpenTelemetry.Tests/Trace/TracerProviderBuilderExtensionsTest.cs index dc6462b2ff2..6060bc7934b 100644 --- a/test/OpenTelemetry.Tests/Trace/TracerProviderBuilderExtensionsTest.cs +++ b/test/OpenTelemetry.Tests/Trace/TracerProviderBuilderExtensionsTest.cs @@ -254,6 +254,7 @@ public void SetAndConfigureResourceTest() var builder = Sdk.CreateTracerProviderBuilder(); int configureInvocations = 0; + bool serviceProviderTestExecuted = false; builder.SetResourceBuilder(ResourceBuilder.CreateEmpty().AddService("Test")); builder.ConfigureResource(builder => @@ -273,13 +274,19 @@ public void SetAndConfigureResourceTest() Assert.Empty(builder.ResourceDetectors); - builder.AddAttributes(new Dictionary() { ["key2"] = "value2" }); + builder.AddDetector(sp => + { + serviceProviderTestExecuted = true; + Assert.NotNull(sp); + return new ResourceBuilder.WrapperResourceDetector(new Resource(new Dictionary() { ["key2"] = "value2" })); + }); Assert.Single(builder.ResourceDetectors); }); using var provider = builder.Build() as TracerProviderSdk; + Assert.True(serviceProviderTestExecuted); Assert.Equal(2, configureInvocations); Assert.Single(provider.Resource.Attributes);