diff --git a/docs/metrics/extending-the-sdk/Program.cs b/docs/metrics/extending-the-sdk/Program.cs index 59eaa6b1c2f..4cc5c3858c8 100644 --- a/docs/metrics/extending-the-sdk/Program.cs +++ b/docs/metrics/extending-the-sdk/Program.cs @@ -29,10 +29,10 @@ public static void Main(string[] args) { using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddSource("MyCompany.MyProduct.MyLibrary") - .AddMetricReader(new MyReader()) + .AddReader(new MyReader()) /** / TODO: revisit once this exception is removed "System.InvalidOperationException: Only one Metricreader is allowed.". - .AddMetricReader(new BaseExportingMetricReader(new MyExporter())) + .AddReader(new BaseExportingMetricReader(new MyExporter())) /**/ .Build(); diff --git a/src/OpenTelemetry.Api/.publicApi/net461/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Api/.publicApi/net461/PublicAPI.Unshipped.txt index 1c27b84e69a..edd7c7e467b 100644 --- a/src/OpenTelemetry.Api/.publicApi/net461/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Api/.publicApi/net461/PublicAPI.Unshipped.txt @@ -7,6 +7,8 @@ OpenTelemetry.Context.RemotingRuntimeContextSlot.Value.get -> object OpenTelemetry.Context.RemotingRuntimeContextSlot.Value.set -> void OpenTelemetry.Context.ThreadLocalRuntimeContextSlot.Value.get -> object OpenTelemetry.Context.ThreadLocalRuntimeContextSlot.Value.set -> void +OpenTelemetry.Metrics.IDeferredMeterProviderBuilder +OpenTelemetry.Metrics.IDeferredMeterProviderBuilder.Configure(System.Action configure) -> OpenTelemetry.Metrics.MeterProviderBuilder override OpenTelemetry.Context.AsyncLocalRuntimeContextSlot.Get() -> T override OpenTelemetry.Context.AsyncLocalRuntimeContextSlot.Set(T value) -> void OpenTelemetry.Context.AsyncLocalRuntimeContextSlot diff --git a/src/OpenTelemetry.Api/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Api/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index 30e2441b221..47cdcc3d64f 100644 --- a/src/OpenTelemetry.Api/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Api/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -5,6 +5,8 @@ OpenTelemetry.Context.IRuntimeContextSlotValueAccessor.Value.get -> object OpenTelemetry.Context.IRuntimeContextSlotValueAccessor.Value.set -> void OpenTelemetry.Context.ThreadLocalRuntimeContextSlot.Value.get -> object OpenTelemetry.Context.ThreadLocalRuntimeContextSlot.Value.set -> void +OpenTelemetry.Metrics.IDeferredMeterProviderBuilder +OpenTelemetry.Metrics.IDeferredMeterProviderBuilder.Configure(System.Action configure) -> OpenTelemetry.Metrics.MeterProviderBuilder static OpenTelemetry.Context.RuntimeContext.GetValue(string slotName) -> object static OpenTelemetry.Context.RuntimeContext.GetValue(string slotName) -> T static OpenTelemetry.Context.RuntimeContext.SetValue(string slotName, object value) -> void diff --git a/src/OpenTelemetry.Api/CHANGELOG.md b/src/OpenTelemetry.Api/CHANGELOG.md index 273ab4fba3a..4906e9b943d 100644 --- a/src/OpenTelemetry.Api/CHANGELOG.md +++ b/src/OpenTelemetry.Api/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +* Added `IDeferredMeterProviderBuilder` + ([#2412](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2412)) + ## 1.2.0-alpha4 Released 2021-Sep-23 diff --git a/src/OpenTelemetry.Api/Metrics/IDeferredMeterProviderBuilder.cs b/src/OpenTelemetry.Api/Metrics/IDeferredMeterProviderBuilder.cs new file mode 100644 index 00000000000..d0a98a05db8 --- /dev/null +++ b/src/OpenTelemetry.Api/Metrics/IDeferredMeterProviderBuilder.cs @@ -0,0 +1,36 @@ +// +// 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; + +namespace OpenTelemetry.Metrics +{ + /// + /// Describes a meter provider builder that supports deferred initialization + /// using an to perform dependency injection. + /// + public interface IDeferredMeterProviderBuilder + { + /// + /// Register a callback action to configure the once the application is available. + /// + /// Configuration callback. + /// The supplied for chaining. + MeterProviderBuilder Configure(Action configure); + } +} diff --git a/src/OpenTelemetry.Exporter.Console/ConsoleExporterMetricsExtensions.cs b/src/OpenTelemetry.Exporter.Console/ConsoleExporterMetricsExtensions.cs index 258d418ce92..8748a0a44ee 100644 --- a/src/OpenTelemetry.Exporter.Console/ConsoleExporterMetricsExtensions.cs +++ b/src/OpenTelemetry.Exporter.Console/ConsoleExporterMetricsExtensions.cs @@ -43,10 +43,10 @@ public static MeterProviderBuilder AddConsoleExporter(this MeterProviderBuilder if (options.MetricExportIntervalMilliseconds == Timeout.Infinite) { - return builder.AddMetricReader(new BaseExportingMetricReader(exporter)); + return builder.AddReader(new BaseExportingMetricReader(exporter)); } - return builder.AddMetricReader(new PeriodicExportingMetricReader(exporter, options.MetricExportIntervalMilliseconds)); + return builder.AddReader(new PeriodicExportingMetricReader(exporter, options.MetricExportIntervalMilliseconds)); } } } diff --git a/src/OpenTelemetry.Exporter.InMemory/InMemoryExporterMetricsExtensions.cs b/src/OpenTelemetry.Exporter.InMemory/InMemoryExporterMetricsExtensions.cs index e9eac67f26a..77ca217bb68 100644 --- a/src/OpenTelemetry.Exporter.InMemory/InMemoryExporterMetricsExtensions.cs +++ b/src/OpenTelemetry.Exporter.InMemory/InMemoryExporterMetricsExtensions.cs @@ -40,7 +40,7 @@ public static MeterProviderBuilder AddInMemoryExporter(this MeterProviderBuilder throw new ArgumentNullException(nameof(exportedItems)); } - return builder.AddMetricReader(new BaseExportingMetricReader(new InMemoryExporter(exportedItems))); + return builder.AddReader(new BaseExportingMetricReader(new InMemoryExporter(exportedItems))); } } } diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporterExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporterExtensions.cs index 205b666f6ca..b159ebea8bb 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporterExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporterExtensions.cs @@ -42,7 +42,7 @@ public static MeterProviderBuilder AddOtlpExporter(this MeterProviderBuilder bui var metricExporter = new OtlpMetricsExporter(options); var metricReader = new PeriodicExportingMetricReader(metricExporter, options.MetricExportIntervalMilliseconds); - return builder.AddMetricReader(metricReader); + return builder.AddReader(metricReader); } } } diff --git a/src/OpenTelemetry.Exporter.Prometheus/MeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus/MeterProviderBuilderExtensions.cs index 443d0968768..f7bfb6c337d 100644 --- a/src/OpenTelemetry.Exporter.Prometheus/MeterProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Exporter.Prometheus/MeterProviderBuilderExtensions.cs @@ -43,7 +43,7 @@ public static MeterProviderBuilder AddPrometheusExporter(this MeterProviderBuild var metricsHttpServer = new PrometheusExporterMetricsHttpServer(exporter); metricsHttpServer.Start(); - return builder.AddMetricReader(reader); + return builder.AddReader(reader); } } } diff --git a/src/OpenTelemetry.Exporter.Zipkin/.publicApi/net5.0/PublicAPI.Shipped.txt b/src/OpenTelemetry.Exporter.Zipkin/.publicApi/net5.0/PublicAPI.Shipped.txt new file mode 100644 index 00000000000..30a9861d7bb --- /dev/null +++ b/src/OpenTelemetry.Exporter.Zipkin/.publicApi/net5.0/PublicAPI.Shipped.txt @@ -0,0 +1,17 @@ +OpenTelemetry.Exporter.ZipkinExporter +OpenTelemetry.Exporter.ZipkinExporter.ZipkinExporter(OpenTelemetry.Exporter.ZipkinExporterOptions options, System.Net.Http.HttpClient client = null) -> void +OpenTelemetry.Exporter.ZipkinExporterOptions +OpenTelemetry.Exporter.ZipkinExporterOptions.BatchExportProcessorOptions.get -> OpenTelemetry.BatchExportProcessorOptions +OpenTelemetry.Exporter.ZipkinExporterOptions.BatchExportProcessorOptions.set -> void +OpenTelemetry.Exporter.ZipkinExporterOptions.Endpoint.get -> System.Uri +OpenTelemetry.Exporter.ZipkinExporterOptions.Endpoint.set -> void +OpenTelemetry.Exporter.ZipkinExporterOptions.ExportProcessorType.get -> OpenTelemetry.ExportProcessorType +OpenTelemetry.Exporter.ZipkinExporterOptions.ExportProcessorType.set -> void +OpenTelemetry.Exporter.ZipkinExporterOptions.MaxPayloadSizeInBytes.get -> int? +OpenTelemetry.Exporter.ZipkinExporterOptions.MaxPayloadSizeInBytes.set -> void +OpenTelemetry.Exporter.ZipkinExporterOptions.UseShortTraceIds.get -> bool +OpenTelemetry.Exporter.ZipkinExporterOptions.UseShortTraceIds.set -> void +OpenTelemetry.Exporter.ZipkinExporterOptions.ZipkinExporterOptions() -> void +OpenTelemetry.Trace.ZipkinExporterHelperExtensions +override OpenTelemetry.Exporter.ZipkinExporter.Export(in OpenTelemetry.Batch batch) -> OpenTelemetry.ExportResult +static OpenTelemetry.Trace.ZipkinExporterHelperExtensions.AddZipkinExporter(this OpenTelemetry.Trace.TracerProviderBuilder builder, System.Action configure = null) -> OpenTelemetry.Trace.TracerProviderBuilder diff --git a/src/OpenTelemetry.Exporter.Zipkin/.publicApi/net5.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.Zipkin/.publicApi/net5.0/PublicAPI.Unshipped.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/OpenTelemetry.Extensions.Hosting/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Extensions.Hosting/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index 628695c6867..67477b7fba6 100644 --- a/src/OpenTelemetry.Extensions.Hosting/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Extensions.Hosting/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -1,7 +1,15 @@ Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions +OpenTelemetry.Metrics.MeterProviderBuilderExtensions OpenTelemetry.Trace.TracerProviderBuilderExtensions +static Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions.AddOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection +static Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions.AddOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection static Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions.AddOpenTelemetryTracing(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection static Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions.AddOpenTelemetryTracing(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection +static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder +static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder +static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.Build(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, System.IServiceProvider serviceProvider) -> OpenTelemetry.Metrics.MeterProvider +static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.Configure(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, System.Action configure) -> OpenTelemetry.Metrics.MeterProviderBuilder +static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.GetServices(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder) -> Microsoft.Extensions.DependencyInjection.IServiceCollection static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddProcessor(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder static OpenTelemetry.Trace.TracerProviderBuilderExtensions.Build(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, System.IServiceProvider serviceProvider) -> OpenTelemetry.Trace.TracerProvider diff --git a/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md b/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md index e3801c6ffbb..c550963fa8b 100644 --- a/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md +++ b/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md @@ -5,6 +5,12 @@ * Removes upper constraint for Microsoft.Extensions.Hosting.Abstractions dependency. ([#2179](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2179)) +* Added `AddOpenTelemetryMetrics` extensions on `IServiceCollection` to register + OpenTelemetry `MeterProvider` with application services. Added + `AddInstrumentation`, `AddReader`, and `Configure` extensions on + `MeterProviderBuilder` to support dependency injection scenarios. + ([#2412](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2412)) + ## 1.0.0-rc7 Released 2021-Jul-12 diff --git a/src/OpenTelemetry.Extensions.Hosting/Implementation/MeterProviderBuilderHosting.cs b/src/OpenTelemetry.Extensions.Hosting/Implementation/MeterProviderBuilderHosting.cs new file mode 100644 index 00000000000..e5529bc1b2b --- /dev/null +++ b/src/OpenTelemetry.Extensions.Hosting/Implementation/MeterProviderBuilderHosting.cs @@ -0,0 +1,65 @@ +// +// 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.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; + +namespace OpenTelemetry.Metrics +{ + /// + /// A with support for deferred initialization using for dependency injection. + /// + internal sealed class MeterProviderBuilderHosting : MeterProviderBuilderBase, IDeferredMeterProviderBuilder + { + private readonly List> configurationActions = new List>(); + + public MeterProviderBuilderHosting(IServiceCollection services) + { + this.Services = services ?? throw new ArgumentNullException(nameof(services)); + } + + public IServiceCollection Services { get; } + + public MeterProviderBuilder Configure(Action configure) + { + if (configure == null) + { + throw new ArgumentNullException(nameof(configure)); + } + + this.configurationActions.Add(configure); + return this; + } + + public MeterProvider Build(IServiceProvider serviceProvider) + { + if (serviceProvider == null) + { + throw new ArgumentNullException(nameof(serviceProvider)); + } + + // Note: Not using a foreach loop because additional actions can be + // added during each call. + for (int i = 0; i < this.configurationActions.Count; i++) + { + this.configurationActions[i](serviceProvider, this); + } + + return this.Build(); + } + } +} diff --git a/src/OpenTelemetry.Extensions.Hosting/Implementation/TelemetryHostedService.cs b/src/OpenTelemetry.Extensions.Hosting/Implementation/TelemetryHostedService.cs index ae29353ecce..1551667aa86 100644 --- a/src/OpenTelemetry.Extensions.Hosting/Implementation/TelemetryHostedService.cs +++ b/src/OpenTelemetry.Extensions.Hosting/Implementation/TelemetryHostedService.cs @@ -19,6 +19,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using OpenTelemetry.Metrics; using OpenTelemetry.Trace; namespace OpenTelemetry.Extensions.Hosting.Implementation @@ -36,12 +37,15 @@ public Task StartAsync(CancellationToken cancellationToken) { try { - // The sole purpose of this HostedService is to ensure - // all instrumentations are created and started. - // This method is invoked when host starts, and - // by requesting the TracerProvider from DI - // it ensures all instrumentations gets started. - this.serviceProvider.GetRequiredService(); + // The sole purpose of this HostedService is to ensure all + // instrumentations, exporters, etc., are created and started. + var meterProvider = this.serviceProvider.GetService(); + var tracerProvider = this.serviceProvider.GetService(); + + if (meterProvider == null && tracerProvider == null) + { + throw new InvalidOperationException("Could not resolve either MeterProvider or TracerProvider through application ServiceProvider, OpenTelemetry SDK has not been initialized."); + } } catch (Exception ex) { diff --git a/src/OpenTelemetry.Extensions.Hosting/Implementation/TracerProviderBuilderHosting.cs b/src/OpenTelemetry.Extensions.Hosting/Implementation/TracerProviderBuilderHosting.cs index 73b06dcdaf0..f56e9d12aea 100644 --- a/src/OpenTelemetry.Extensions.Hosting/Implementation/TracerProviderBuilderHosting.cs +++ b/src/OpenTelemetry.Extensions.Hosting/Implementation/TracerProviderBuilderHosting.cs @@ -47,10 +47,16 @@ public TracerProviderBuilder Configure(Action +// 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.DependencyInjection; + +namespace OpenTelemetry.Metrics +{ + /// + /// Contains extension methods for the class. + /// + public static class MeterProviderBuilderExtensions + { + /// + /// Adds instrumentation to the provider. + /// + /// Instrumentation type. + /// . + /// The supplied for chaining. + public static MeterProviderBuilder AddInstrumentation(this MeterProviderBuilder meterProviderBuilder) + where T : class + { + if (meterProviderBuilder is MeterProviderBuilderHosting meterProviderBuilderHosting) + { + meterProviderBuilderHosting.Configure((sp, builder) => builder + .AddInstrumentation(() => sp.GetRequiredService())); + } + + return meterProviderBuilder; + } + + /// + /// Adds a reader to the provider. + /// + /// Reader type. + /// . + /// The supplied for chaining. + public static MeterProviderBuilder AddReader(this MeterProviderBuilder meterProviderBuilder) + where T : MetricReader + { + if (meterProviderBuilder is MeterProviderBuilderHosting meterProviderBuilderHosting) + { + meterProviderBuilderHosting.Configure((sp, builder) => builder + .AddReader(sp.GetRequiredService())); + } + + return meterProviderBuilder; + } + + /// + /// Register a callback action to configure the once the application is available. + /// + /// . + /// Configuration callback. + /// The supplied for chaining. + public static MeterProviderBuilder Configure(this MeterProviderBuilder meterProviderBuilder, Action configure) + { + if (meterProviderBuilder is IDeferredMeterProviderBuilder deferredMeterProviderBuilder) + { + deferredMeterProviderBuilder.Configure(configure); + } + + return meterProviderBuilder; + } + + /// + /// Gets the application attached to + /// the . + /// + /// . + /// or + /// if services are unavailable. + public static IServiceCollection GetServices(this MeterProviderBuilder meterProviderBuilder) + { + if (meterProviderBuilder is MeterProviderBuilderHosting meterProviderBuilderHosting) + { + return meterProviderBuilderHosting.Services; + } + + return null; + } + + /// + /// Run the configured actions to initialize the . + /// + /// . + /// . + /// . + public static MeterProvider Build(this MeterProviderBuilder meterProviderBuilder, IServiceProvider serviceProvider) + { + if (meterProviderBuilder is MeterProviderBuilderHosting meterProviderBuilderHosting) + { + return meterProviderBuilderHosting.Build(serviceProvider); + } + + if (meterProviderBuilder is MeterProviderBuilderBase meterProviderBuilderBase) + { + return meterProviderBuilderBase.Build(); + } + + return null; + } + } +} diff --git a/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryServicesExtensions.cs b/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryServicesExtensions.cs index dc251c64a26..7f180613c27 100644 --- a/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryServicesExtensions.cs +++ b/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryServicesExtensions.cs @@ -18,6 +18,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; using OpenTelemetry.Extensions.Hosting.Implementation; +using OpenTelemetry.Metrics; using OpenTelemetry.Trace; namespace Microsoft.Extensions.DependencyInjection @@ -55,6 +56,34 @@ public static IServiceCollection AddOpenTelemetryTracing(this IServiceCollection return services.AddOpenTelemetryTracing(sp => builder.Build(sp)); } + /// + /// Adds OpenTelemetry MeterProvider to the specified . + /// + /// The to add services to. + /// The so that additional calls can be chained. + public static IServiceCollection AddOpenTelemetryMetrics(this IServiceCollection services) + { + return services.AddOpenTelemetryMetrics(builder => { }); + } + + /// + /// Adds OpenTelemetry MeterProvider to the specified . + /// + /// The to add services to. + /// Callback action to configure the . + /// The so that additional calls can be chained. + public static IServiceCollection AddOpenTelemetryMetrics(this IServiceCollection services, Action configure) + { + if (configure is null) + { + throw new ArgumentNullException(nameof(configure)); + } + + var builder = new MeterProviderBuilderHosting(services); + configure(builder); + return services.AddOpenTelemetryMetrics(sp => builder.Build(sp)); + } + /// /// Adds OpenTelemetry TracerProvider to the specified . /// @@ -85,5 +114,36 @@ private static IServiceCollection AddOpenTelemetryTracing(this IServiceCollectio return services; } + + /// + /// Adds OpenTelemetry MeterProvider to the specified . + /// + /// The to add services to. + /// A delegate that provides the tracer provider to be registered. + /// The so that additional calls can be chained. + private static IServiceCollection AddOpenTelemetryMetrics(this IServiceCollection services, Func createMeterProvider) + { + if (services is null) + { + throw new ArgumentNullException(nameof(services)); + } + + if (createMeterProvider is null) + { + throw new ArgumentNullException(nameof(createMeterProvider)); + } + + try + { + services.TryAddEnumerable(ServiceDescriptor.Singleton()); + return services.AddSingleton(s => createMeterProvider(s)); + } + catch (Exception ex) + { + HostingExtensionsEventSource.Log.FailedInitialize(ex); + } + + return services; + } } } diff --git a/src/OpenTelemetry/Metrics/MeterProviderBuilderBase.cs b/src/OpenTelemetry/Metrics/MeterProviderBuilderBase.cs new file mode 100644 index 00000000000..8a0fe1d4765 --- /dev/null +++ b/src/OpenTelemetry/Metrics/MeterProviderBuilderBase.cs @@ -0,0 +1,120 @@ +// +// 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.Collections.Generic; +using OpenTelemetry.Resources; + +namespace OpenTelemetry.Metrics +{ + /// + /// Build MeterProvider with Resource, Readers, and Instrumentation. + /// + public abstract class MeterProviderBuilderBase : MeterProviderBuilder + { + private readonly List instrumentationFactories = new List(); + private readonly List meterSources = new List(); + private ResourceBuilder resourceBuilder = ResourceBuilder.CreateDefault(); + + protected MeterProviderBuilderBase() + { + } + + internal List MetricReaders { get; } = new List(); + + /// + public override MeterProviderBuilder AddInstrumentation(Func instrumentationFactory) + { + if (instrumentationFactory == null) + { + throw new ArgumentNullException(nameof(instrumentationFactory)); + } + + this.instrumentationFactories.Add( + new InstrumentationFactory( + typeof(TInstrumentation).Name, + "semver:" + typeof(TInstrumentation).Assembly.GetName().Version, + instrumentationFactory)); + + return this; + } + + /// + public override MeterProviderBuilder AddSource(params string[] names) + { + if (names == null) + { + throw new ArgumentNullException(nameof(names)); + } + + foreach (var name in names) + { + if (string.IsNullOrWhiteSpace(name)) + { + throw new ArgumentException($"{nameof(names)} contains null or whitespace string."); + } + + this.meterSources.Add(name); + } + + return this; + } + + internal MeterProviderBuilder AddReader(MetricReader reader) + { + if (this.MetricReaders.Count >= 1) + { + throw new InvalidOperationException("Only one Metricreader is allowed."); + } + + this.MetricReaders.Add(reader); + return this; + } + + internal MeterProviderBuilder SetResourceBuilder(ResourceBuilder resourceBuilder) + { + this.resourceBuilder = resourceBuilder ?? throw new ArgumentNullException(nameof(resourceBuilder)); + return this; + } + + /// + /// Run the configured actions to initialize the . + /// + /// . + protected MeterProvider Build() + { + return new MeterProviderSdk( + this.resourceBuilder.Build(), + this.meterSources, + this.instrumentationFactories, + this.MetricReaders.ToArray()); + } + + internal readonly struct InstrumentationFactory + { + public readonly string Name; + public readonly string Version; + public readonly Func Factory; + + internal InstrumentationFactory(string name, string version, Func factory) + { + this.Name = name; + this.Version = version; + this.Factory = factory; + } + } + } +} diff --git a/src/OpenTelemetry/Metrics/MeterProviderBuilderExtensions.cs b/src/OpenTelemetry/Metrics/MeterProviderBuilderExtensions.cs index 72a8339d030..d54a31e9521 100644 --- a/src/OpenTelemetry/Metrics/MeterProviderBuilderExtensions.cs +++ b/src/OpenTelemetry/Metrics/MeterProviderBuilderExtensions.cs @@ -14,6 +14,7 @@ // limitations under the License. // +using System; using OpenTelemetry.Resources; namespace OpenTelemetry.Metrics @@ -24,16 +25,16 @@ namespace OpenTelemetry.Metrics public static class MeterProviderBuilderExtensions { /// - /// Add metric reader. + /// Adds a reader to the provider. /// /// . - /// Metricreader. + /// . /// . - public static MeterProviderBuilder AddMetricReader(this MeterProviderBuilder meterProviderBuilder, MetricReader metricReader) + public static MeterProviderBuilder AddReader(this MeterProviderBuilder meterProviderBuilder, MetricReader reader) { - if (meterProviderBuilder is MeterProviderBuilderSdk meterProviderBuilderSdk) + if (meterProviderBuilder is MeterProviderBuilderBase meterProviderBuilderBase) { - return meterProviderBuilderSdk.AddMetricReader(metricReader); + return meterProviderBuilderBase.AddReader(reader); } return meterProviderBuilder; @@ -48,9 +49,9 @@ public static MeterProviderBuilder AddMetricReader(this MeterProviderBuilder met /// Returns for chaining. public static MeterProviderBuilder SetResourceBuilder(this MeterProviderBuilder meterProviderBuilder, ResourceBuilder resourceBuilder) { - if (meterProviderBuilder is MeterProviderBuilderSdk meterProviderBuilderSdk) + if (meterProviderBuilder is MeterProviderBuilderBase meterProviderBuilderBase) { - meterProviderBuilderSdk.SetResourceBuilder(resourceBuilder); + meterProviderBuilderBase.SetResourceBuilder(resourceBuilder); } return meterProviderBuilder; @@ -63,9 +64,14 @@ public static MeterProviderBuilder SetResourceBuilder(this MeterProviderBuilder /// . public static MeterProvider Build(this MeterProviderBuilder meterProviderBuilder) { + if (meterProviderBuilder is IDeferredMeterProviderBuilder) + { + throw new NotSupportedException("DeferredMeterProviderBuilder requires a ServiceProvider to build."); + } + if (meterProviderBuilder is MeterProviderBuilderSdk meterProviderBuilderSdk) { - return meterProviderBuilderSdk.Build(); + return meterProviderBuilderSdk.BuildSdk(); } return null; diff --git a/src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs b/src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs index 06bbfa715e0..50572f0849b 100644 --- a/src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs +++ b/src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs @@ -14,99 +14,10 @@ // limitations under the License. // -using System; -using System.Collections.Generic; -using OpenTelemetry.Resources; - namespace OpenTelemetry.Metrics { - internal class MeterProviderBuilderSdk : MeterProviderBuilder + internal class MeterProviderBuilderSdk : MeterProviderBuilderBase { - private readonly List instrumentationFactories = new List(); - private readonly List meterSources = new List(); - private ResourceBuilder resourceBuilder = ResourceBuilder.CreateDefault(); - - internal MeterProviderBuilderSdk() - { - } - - internal List MetricReaders { get; } = new List(); - - public override MeterProviderBuilder AddInstrumentation(Func instrumentationFactory) - { - if (instrumentationFactory == null) - { - throw new ArgumentNullException(nameof(instrumentationFactory)); - } - - this.instrumentationFactories.Add( - new InstrumentationFactory( - typeof(TInstrumentation).Name, - "semver:" + typeof(TInstrumentation).Assembly.GetName().Version, - instrumentationFactory)); - - return this; - } - - public override MeterProviderBuilder AddSource(params string[] names) - { - if (names == null) - { - throw new ArgumentNullException(nameof(names)); - } - - foreach (var name in names) - { - if (string.IsNullOrWhiteSpace(name)) - { - throw new ArgumentException($"{nameof(names)} contains null or whitespace string."); - } - - this.meterSources.Add(name); - } - - return this; - } - - internal MeterProviderBuilderSdk AddMetricReader(MetricReader metricReader) - { - if (this.MetricReaders.Count >= 1) - { - throw new InvalidOperationException("Only one Metricreader is allowed."); - } - - this.MetricReaders.Add(metricReader); - return this; - } - - internal MeterProviderBuilderSdk SetResourceBuilder(ResourceBuilder resourceBuilder) - { - this.resourceBuilder = resourceBuilder ?? throw new ArgumentNullException(nameof(resourceBuilder)); - return this; - } - - internal MeterProvider Build() - { - return new MeterProviderSdk( - this.resourceBuilder.Build(), - this.meterSources, - this.instrumentationFactories, - this.MetricReaders.ToArray()); - } - - // TODO: This is copied from TracerProviderBuilderSdk. Move to common location. - internal readonly struct InstrumentationFactory - { - public readonly string Name; - public readonly string Version; - public readonly Func Factory; - - internal InstrumentationFactory(string name, string version, Func factory) - { - this.Name = name; - this.Version = version; - this.Factory = factory; - } - } + internal MeterProvider BuildSdk() => this.Build(); } } diff --git a/src/OpenTelemetry/Metrics/MeterProviderSdk.cs b/src/OpenTelemetry/Metrics/MeterProviderSdk.cs index 6c268b32c0a..2ca18d51820 100644 --- a/src/OpenTelemetry/Metrics/MeterProviderSdk.cs +++ b/src/OpenTelemetry/Metrics/MeterProviderSdk.cs @@ -136,6 +136,10 @@ internal MeterProviderSdk( internal Resource Resource { get; } + internal List Instrumentations => this.instrumentations; + + internal MetricReader Reader => this.reader; + internal void MeasurementsCompleted(Instrument instrument, object state) { Console.WriteLine($"Instrument {instrument.Meter.Name}:{instrument.Name} completed."); diff --git a/src/OpenTelemetry/Trace/TracerProviderBuilderExtensions.cs b/src/OpenTelemetry/Trace/TracerProviderBuilderExtensions.cs index f6b261e12cf..09bdedca5da 100644 --- a/src/OpenTelemetry/Trace/TracerProviderBuilderExtensions.cs +++ b/src/OpenTelemetry/Trace/TracerProviderBuilderExtensions.cs @@ -100,7 +100,7 @@ public static TracerProvider Build(this TracerProviderBuilder tracerProviderBuil { if (tracerProviderBuilder is IDeferredTracerProviderBuilder) { - throw new NotSupportedException("DeferredTracerBuilder requires a ServiceProvider to build."); + throw new NotSupportedException("DeferredTracerProviderBuilder requires a ServiceProvider to build."); } if (tracerProviderBuilder is TracerProviderBuilderSdk tracerProviderBuilderSdk) diff --git a/test/Benchmarks/Metrics/MetricCollectBenchmarks.cs b/test/Benchmarks/Metrics/MetricCollectBenchmarks.cs index d34c019b95a..4b710ca66b9 100644 --- a/test/Benchmarks/Metrics/MetricCollectBenchmarks.cs +++ b/test/Benchmarks/Metrics/MetricCollectBenchmarks.cs @@ -92,7 +92,7 @@ void ProcessExport(Batch batch) }; this.provider = Sdk.CreateMeterProviderBuilder() .AddSource("TestMeter") - .AddMetricReader(this.reader) + .AddReader(this.reader) .Build(); this.meter = new Meter("TestMeter"); diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpMetricsExporterTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpMetricsExporterTests.cs index 8984497a907..981b7c1919a 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpMetricsExporterTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpMetricsExporterTests.cs @@ -67,7 +67,7 @@ public void ToOtlpResourceMetricsTest(bool includeServiceNameInResource) using var provider = Sdk.CreateMeterProviderBuilder() .SetResourceBuilder(resourceBuilder) .AddSource("TestMeter") - .AddMetricReader(metricReader) + .AddReader(metricReader) .Build(); exporter.ParentProvider = provider; diff --git a/test/OpenTelemetry.Extensions.Hosting.Tests/HostingMeterExtensionTests.cs b/test/OpenTelemetry.Extensions.Hosting.Tests/HostingMeterExtensionTests.cs new file mode 100644 index 00000000000..1c02b6eb14b --- /dev/null +++ b/test/OpenTelemetry.Extensions.Hosting.Tests/HostingMeterExtensionTests.cs @@ -0,0 +1,238 @@ +// +// 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.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using OpenTelemetry.Metrics; +using Xunit; + +namespace OpenTelemetry.Extensions.Hosting.Tests +{ + public class HostingMeterExtensionTests + { + [Fact] + public async Task AddOpenTelemetryMeterProviderInstrumentationCreationAndDisposal() + { + var testInstrumentation = new TestInstrumentation(); + var callbackRun = false; + + var builder = new HostBuilder().ConfigureServices(services => + { + services.AddOpenTelemetryMetrics(builder => + { + builder.AddInstrumentation(() => + { + callbackRun = true; + return testInstrumentation; + }); + }); + }); + + var host = builder.Build(); + + Assert.False(callbackRun); + Assert.False(testInstrumentation.Disposed); + + await host.StartAsync(); + + Assert.True(callbackRun); + Assert.False(testInstrumentation.Disposed); + + await host.StopAsync(); + + Assert.True(callbackRun); + Assert.False(testInstrumentation.Disposed); + + host.Dispose(); + + Assert.True(callbackRun); + Assert.True(testInstrumentation.Disposed); + } + + [Fact] + public void AddOpenTelemetryMeterProvider_HostBuilt_OpenTelemetrySdk_RegisteredAsSingleton() + { + var builder = new HostBuilder().ConfigureServices(services => + { + services.AddOpenTelemetryMetrics(); + }); + + var host = builder.Build(); + + var meterProvider1 = host.Services.GetRequiredService(); + var meterProvider2 = host.Services.GetRequiredService(); + + Assert.Same(meterProvider1, meterProvider2); + } + + [Fact] + public void AddOpenTelemetryMeterProvider_ServiceProviderArgument_ServicesRegistered() + { + var testInstrumentation = new TestInstrumentation(); + + var services = new ServiceCollection(); + services.AddSingleton(testInstrumentation); + services.AddOpenTelemetryMetrics(builder => + { + builder.Configure( + (sp, b) => b.AddInstrumentation(() => sp.GetRequiredService())); + }); + + var serviceProvider = services.BuildServiceProvider(); + + var meterFactory = serviceProvider.GetRequiredService(); + Assert.NotNull(meterFactory); + + Assert.False(testInstrumentation.Disposed); + + serviceProvider.Dispose(); + + Assert.True(testInstrumentation.Disposed); + } + + [Fact] + public void AddOpenTelemetryMeterProvider_BadArgs_NullServiceCollection() + { + ServiceCollection services = null; + Assert.Throws(() => services.AddOpenTelemetryMetrics(null)); + Assert.Throws(() => + services.AddOpenTelemetryMetrics(builder => + { + builder.Configure( + (sp, b) => b.AddInstrumentation(() => sp.GetRequiredService())); + })); + } + + [Fact] + public void AddOpenTelemetryMeterProvider_GetServicesExtension() + { + var services = new ServiceCollection(); + services.AddOpenTelemetryMetrics(builder => AddMyFeature(builder)); + + using var serviceProvider = services.BuildServiceProvider(); + + var meterProvider = (MeterProviderSdk)serviceProvider.GetRequiredService(); + + Assert.True(meterProvider.Reader is TestReader); + } + + [Fact] + public void AddOpenTelemetryMeterProvider_NestedConfigureCallbacks() + { + int configureCalls = 0; + var services = new ServiceCollection(); + services.AddOpenTelemetryMetrics(builder => builder + .Configure((sp1, builder1) => + { + configureCalls++; + builder1.Configure((sp2, builder2) => + { + configureCalls++; + }); + })); + + using var serviceProvider = services.BuildServiceProvider(); + + var meterFactory = serviceProvider.GetRequiredService(); + + Assert.Equal(2, configureCalls); + } + + [Fact] + public void AddOpenTelemetryMeterProvider_ConfigureCallbacksUsingExtensions() + { + var services = new ServiceCollection(); + + services.AddSingleton(); + services.AddSingleton(); + + services.AddOpenTelemetryMetrics(builder => builder + .Configure((sp1, builder1) => + { + builder1 + .AddInstrumentation() + .AddReader(); + })); + + using var serviceProvider = services.BuildServiceProvider(); + + var meterProvider = (MeterProviderSdk)serviceProvider.GetRequiredService(); + + Assert.True(meterProvider.Instrumentations.FirstOrDefault() is TestInstrumentation); + Assert.True(meterProvider.Reader is TestReader); + } + + [Fact(Skip = "Known limitation. See issue 1215.")] + public void AddOpenTelemetryMeterProvider_Idempotent() + { + var testInstrumentation1 = new TestInstrumentation(); + var testInstrumentation2 = new TestInstrumentation(); + + var services = new ServiceCollection(); + services.AddSingleton(testInstrumentation1); + services.AddOpenTelemetryMetrics(builder => + { + builder.AddInstrumentation(() => testInstrumentation1); + }); + + services.AddOpenTelemetryMetrics(builder => + { + builder.AddInstrumentation(() => testInstrumentation2); + }); + + var serviceProvider = services.BuildServiceProvider(); + + var meterFactory = serviceProvider.GetRequiredService(); + Assert.NotNull(meterFactory); + + Assert.False(testInstrumentation1.Disposed); + Assert.False(testInstrumentation2.Disposed); + serviceProvider.Dispose(); + Assert.True(testInstrumentation1.Disposed); + Assert.True(testInstrumentation2.Disposed); + } + + private static MeterProviderBuilder AddMyFeature(MeterProviderBuilder meterProviderBuilder) + { + (meterProviderBuilder.GetServices() ?? throw new NotSupportedException("MyFeature requires a hosting MeterProviderBuilder instance.")) + .AddSingleton(); + + return meterProviderBuilder.AddReader(); + } + + internal class TestInstrumentation : IDisposable + { + public bool Disposed { get; private set; } + + public void Dispose() + { + this.Disposed = true; + } + } + + internal class TestReader : MetricReader + { + protected override bool ProcessMetrics(Batch metrics, int timeoutMilliseconds) + { + return true; + } + } + } +} diff --git a/test/OpenTelemetry.Extensions.Hosting.Tests/HostingExtensionsTests.cs b/test/OpenTelemetry.Extensions.Hosting.Tests/HostingTracerExtensionTests.cs similarity index 98% rename from test/OpenTelemetry.Extensions.Hosting.Tests/HostingExtensionsTests.cs rename to test/OpenTelemetry.Extensions.Hosting.Tests/HostingTracerExtensionTests.cs index 0a56f542e42..b897dd42098 100644 --- a/test/OpenTelemetry.Extensions.Hosting.Tests/HostingExtensionsTests.cs +++ b/test/OpenTelemetry.Extensions.Hosting.Tests/HostingTracerExtensionTests.cs @@ -1,4 +1,4 @@ -// +// // Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,7 +25,7 @@ namespace OpenTelemetry.Extensions.Hosting.Tests { - public class HostingExtensionsTests + public class HostingTracerExtensionTests { [Fact] public async Task AddOpenTelemetryTracerProviderInstrumentationCreationAndDisposal() diff --git a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs index 9f76fe4e6df..c37be430980 100644 --- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs +++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs @@ -69,7 +69,7 @@ void ProcessExport(Batch batch) }; this.meterProvider = Sdk.CreateMeterProviderBuilder() .AddAspNetCoreInstrumentation() - .AddMetricReader(metricReader) + .AddReader(metricReader) .Build(); using (var client = this.factory.CreateClient()) diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs index c2fbccac6a3..0dada635691 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs @@ -71,7 +71,7 @@ void ProcessExport(Batch batch) }; var meterProvider = Sdk.CreateMeterProviderBuilder() .AddHttpClientInstrumentation() - .AddMetricReader(metricReader) + .AddReader(metricReader) .Build(); using (serverLifeTime) diff --git a/test/OpenTelemetry.Tests/Metrics/InMemoryExporterTests.cs b/test/OpenTelemetry.Tests/Metrics/InMemoryExporterTests.cs index 06ad4c71125..79cdba81c94 100644 --- a/test/OpenTelemetry.Tests/Metrics/InMemoryExporterTests.cs +++ b/test/OpenTelemetry.Tests/Metrics/InMemoryExporterTests.cs @@ -36,7 +36,7 @@ public void InMemoryExporterShouldDeepCopyMetricPoints() using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddSource("InMemoryExporterTests") - .AddMetricReader(inMemoryReader) + .AddReader(inMemoryReader) .Build(); var counter = meter.CreateCounter("meter"); diff --git a/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs b/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs index 0ddfa6fb9bf..8111ecd262f 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs @@ -64,7 +64,7 @@ void ProcessExport(Batch batch) using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddSource("TestDuplicateMetricName1") .AddSource("TestDuplicateMetricName2") - .AddMetricReader(metricReader) + .AddReader(metricReader) .Build(); // Expecting one metric stream. @@ -117,7 +117,7 @@ void ProcessExport(Batch batch) var counterLong = meter.CreateCounter("mycounter"); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddSource("TestMeter") - .AddMetricReader(metricReader) + .AddReader(metricReader) .Build(); counterLong.Add(10); @@ -202,7 +202,7 @@ void ProcessExport(Batch batch) }); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddSource(meterName) - .AddMetricReader(metricReader) + .AddReader(metricReader) .Build(); metricReader.Collect(); @@ -262,7 +262,7 @@ void ProcessExport(Batch batch) var counterLong = meter.CreateCounter("mycounterCapTest"); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddSource("TestPointCapMeter") - .AddMetricReader(metricReader) + .AddReader(metricReader) .Build(); // Make one Add with no tags. @@ -314,7 +314,7 @@ void ProcessExport(Batch batch) var counterLong = meter.CreateCounter("mycounter"); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddSource("TestLongCounterMeter") - .AddMetricReader(metricReader) + .AddReader(metricReader) .Build(); // setup args to threads. @@ -383,7 +383,7 @@ void ProcessExport(Batch batch) var counterDouble = meter.CreateCounter("mycounter"); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddSource("TestDoubleCounterMeter") - .AddMetricReader(metricReader) + .AddReader(metricReader) .Build(); // setup args to threads. diff --git a/test/OpenTelemetry.Tests/Metrics/MetricExporterTests.cs b/test/OpenTelemetry.Tests/Metrics/MetricExporterTests.cs index a1aaf603fec..6416551ed9b 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricExporterTests.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricExporterTests.cs @@ -44,7 +44,7 @@ public void FlushMetricExporterTest(ExportModes mode) var reader = new BaseExportingMetricReader(exporter); using var meterProvider = Sdk.CreateMeterProviderBuilder() - .AddMetricReader(reader) + .AddReader(reader) .Build(); switch (mode)