Hosting: Support metrics registration via IServiceCollection & deferred configuration (#2412)
* Add metrics support to hosting lib. * Bug fixes and some public api additions. * Added missing zipkin publicapi files. * Unit tests. * CHANGELOG updates * Fixes * Code review. * Update src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md Co-authored-by: Reiley Yang <reyang@microsoft.com> * Code review. * Warning fixup. Co-authored-by: Reiley Yang <reyang@microsoft.com> Co-authored-by: Cijo Thomas <cithomas@microsoft.com>
This commit is contained in:
parent
c60dc3697c
commit
38ee521b24
|
|
@ -29,10 +29,10 @@ public class Program
|
||||||
{
|
{
|
||||||
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
||||||
.AddSource("MyCompany.MyProduct.MyLibrary")
|
.AddSource("MyCompany.MyProduct.MyLibrary")
|
||||||
.AddMetricReader(new MyReader())
|
.AddReader(new MyReader())
|
||||||
/** /
|
/** /
|
||||||
TODO: revisit once this exception is removed "System.InvalidOperationException: Only one Metricreader is allowed.".
|
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();
|
.Build();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ OpenTelemetry.Context.RemotingRuntimeContextSlot<T>.Value.get -> object
|
||||||
OpenTelemetry.Context.RemotingRuntimeContextSlot<T>.Value.set -> void
|
OpenTelemetry.Context.RemotingRuntimeContextSlot<T>.Value.set -> void
|
||||||
OpenTelemetry.Context.ThreadLocalRuntimeContextSlot<T>.Value.get -> object
|
OpenTelemetry.Context.ThreadLocalRuntimeContextSlot<T>.Value.get -> object
|
||||||
OpenTelemetry.Context.ThreadLocalRuntimeContextSlot<T>.Value.set -> void
|
OpenTelemetry.Context.ThreadLocalRuntimeContextSlot<T>.Value.set -> void
|
||||||
|
OpenTelemetry.Metrics.IDeferredMeterProviderBuilder
|
||||||
|
OpenTelemetry.Metrics.IDeferredMeterProviderBuilder.Configure(System.Action<System.IServiceProvider, OpenTelemetry.Metrics.MeterProviderBuilder> configure) -> OpenTelemetry.Metrics.MeterProviderBuilder
|
||||||
override OpenTelemetry.Context.AsyncLocalRuntimeContextSlot<T>.Get() -> T
|
override OpenTelemetry.Context.AsyncLocalRuntimeContextSlot<T>.Get() -> T
|
||||||
override OpenTelemetry.Context.AsyncLocalRuntimeContextSlot<T>.Set(T value) -> void
|
override OpenTelemetry.Context.AsyncLocalRuntimeContextSlot<T>.Set(T value) -> void
|
||||||
OpenTelemetry.Context.AsyncLocalRuntimeContextSlot<T>
|
OpenTelemetry.Context.AsyncLocalRuntimeContextSlot<T>
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ OpenTelemetry.Context.IRuntimeContextSlotValueAccessor.Value.get -> object
|
||||||
OpenTelemetry.Context.IRuntimeContextSlotValueAccessor.Value.set -> void
|
OpenTelemetry.Context.IRuntimeContextSlotValueAccessor.Value.set -> void
|
||||||
OpenTelemetry.Context.ThreadLocalRuntimeContextSlot<T>.Value.get -> object
|
OpenTelemetry.Context.ThreadLocalRuntimeContextSlot<T>.Value.get -> object
|
||||||
OpenTelemetry.Context.ThreadLocalRuntimeContextSlot<T>.Value.set -> void
|
OpenTelemetry.Context.ThreadLocalRuntimeContextSlot<T>.Value.set -> void
|
||||||
|
OpenTelemetry.Metrics.IDeferredMeterProviderBuilder
|
||||||
|
OpenTelemetry.Metrics.IDeferredMeterProviderBuilder.Configure(System.Action<System.IServiceProvider, OpenTelemetry.Metrics.MeterProviderBuilder> configure) -> OpenTelemetry.Metrics.MeterProviderBuilder
|
||||||
static OpenTelemetry.Context.RuntimeContext.GetValue(string slotName) -> object
|
static OpenTelemetry.Context.RuntimeContext.GetValue(string slotName) -> object
|
||||||
static OpenTelemetry.Context.RuntimeContext.GetValue<T>(string slotName) -> T
|
static OpenTelemetry.Context.RuntimeContext.GetValue<T>(string slotName) -> T
|
||||||
static OpenTelemetry.Context.RuntimeContext.SetValue(string slotName, object value) -> void
|
static OpenTelemetry.Context.RuntimeContext.SetValue(string slotName, object value) -> void
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
* Added `IDeferredMeterProviderBuilder`
|
||||||
|
([#2412](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2412))
|
||||||
|
|
||||||
## 1.2.0-alpha4
|
## 1.2.0-alpha4
|
||||||
|
|
||||||
Released 2021-Sep-23
|
Released 2021-Sep-23
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
// <copyright file="IDeferredMeterProviderBuilder.cs" company="OpenTelemetry Authors">
|
||||||
|
// 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.
|
||||||
|
// </copyright>
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace OpenTelemetry.Metrics
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Describes a meter provider builder that supports deferred initialization
|
||||||
|
/// using an <see cref="IServiceProvider"/> to perform dependency injection.
|
||||||
|
/// </summary>
|
||||||
|
public interface IDeferredMeterProviderBuilder
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Register a callback action to configure the <see
|
||||||
|
/// cref="MeterProviderBuilder"/> once the application <see
|
||||||
|
/// cref="IServiceProvider"/> is available.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configure">Configuration callback.</param>
|
||||||
|
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
|
||||||
|
MeterProviderBuilder Configure(Action<IServiceProvider, MeterProviderBuilder> configure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -43,10 +43,10 @@ namespace OpenTelemetry.Metrics
|
||||||
|
|
||||||
if (options.MetricExportIntervalMilliseconds == Timeout.Infinite)
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ namespace OpenTelemetry.Metrics
|
||||||
throw new ArgumentNullException(nameof(exportedItems));
|
throw new ArgumentNullException(nameof(exportedItems));
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.AddMetricReader(new BaseExportingMetricReader(new InMemoryExporter<Metric>(exportedItems)));
|
return builder.AddReader(new BaseExportingMetricReader(new InMemoryExporter<Metric>(exportedItems)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ namespace OpenTelemetry.Metrics
|
||||||
|
|
||||||
var metricExporter = new OtlpMetricsExporter(options);
|
var metricExporter = new OtlpMetricsExporter(options);
|
||||||
var metricReader = new PeriodicExportingMetricReader(metricExporter, options.MetricExportIntervalMilliseconds);
|
var metricReader = new PeriodicExportingMetricReader(metricExporter, options.MetricExportIntervalMilliseconds);
|
||||||
return builder.AddMetricReader(metricReader);
|
return builder.AddReader(metricReader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ namespace OpenTelemetry.Metrics
|
||||||
|
|
||||||
var metricsHttpServer = new PrometheusExporterMetricsHttpServer(exporter);
|
var metricsHttpServer = new PrometheusExporterMetricsHttpServer(exporter);
|
||||||
metricsHttpServer.Start();
|
metricsHttpServer.Start();
|
||||||
return builder.AddMetricReader(reader);
|
return builder.AddReader(reader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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<System.Diagnostics.Activity>
|
||||||
|
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<System.Diagnostics.Activity> batch) -> OpenTelemetry.ExportResult
|
||||||
|
static OpenTelemetry.Trace.ZipkinExporterHelperExtensions.AddZipkinExporter(this OpenTelemetry.Trace.TracerProviderBuilder builder, System.Action<OpenTelemetry.Exporter.ZipkinExporterOptions> configure = null) -> OpenTelemetry.Trace.TracerProviderBuilder
|
||||||
|
|
@ -1,7 +1,15 @@
|
||||||
Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions
|
Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions
|
||||||
|
OpenTelemetry.Metrics.MeterProviderBuilderExtensions
|
||||||
OpenTelemetry.Trace.TracerProviderBuilderExtensions
|
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<OpenTelemetry.Metrics.MeterProviderBuilder> 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) -> Microsoft.Extensions.DependencyInjection.IServiceCollection
|
||||||
static Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions.AddOpenTelemetryTracing(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<OpenTelemetry.Trace.TracerProviderBuilder> configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection
|
static Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions.AddOpenTelemetryTracing(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<OpenTelemetry.Trace.TracerProviderBuilder> configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection
|
||||||
|
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder
|
||||||
|
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader<T>(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<System.IServiceProvider, OpenTelemetry.Metrics.MeterProviderBuilder> configure) -> OpenTelemetry.Metrics.MeterProviderBuilder
|
||||||
|
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.GetServices(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder) -> Microsoft.Extensions.DependencyInjection.IServiceCollection
|
||||||
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder
|
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder
|
||||||
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddProcessor<T>(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder
|
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddProcessor<T>(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder
|
||||||
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.Build(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, System.IServiceProvider serviceProvider) -> OpenTelemetry.Trace.TracerProvider
|
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.Build(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, System.IServiceProvider serviceProvider) -> OpenTelemetry.Trace.TracerProvider
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,12 @@
|
||||||
* Removes upper constraint for Microsoft.Extensions.Hosting.Abstractions
|
* Removes upper constraint for Microsoft.Extensions.Hosting.Abstractions
|
||||||
dependency. ([#2179](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2179))
|
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<T>`, `AddReader<T>`, and `Configure` extensions on
|
||||||
|
`MeterProviderBuilder` to support dependency injection scenarios.
|
||||||
|
([#2412](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2412))
|
||||||
|
|
||||||
## 1.0.0-rc7
|
## 1.0.0-rc7
|
||||||
|
|
||||||
Released 2021-Jul-12
|
Released 2021-Jul-12
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
// <copyright file="MeterProviderBuilderHosting.cs" company="OpenTelemetry Authors">
|
||||||
|
// 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.
|
||||||
|
// </copyright>
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace OpenTelemetry.Metrics
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A <see cref="MeterProviderBuilderBase"/> with support for deferred initialization using <see cref="IServiceProvider"/> for dependency injection.
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class MeterProviderBuilderHosting : MeterProviderBuilderBase, IDeferredMeterProviderBuilder
|
||||||
|
{
|
||||||
|
private readonly List<Action<IServiceProvider, MeterProviderBuilder>> configurationActions = new List<Action<IServiceProvider, MeterProviderBuilder>>();
|
||||||
|
|
||||||
|
public MeterProviderBuilderHosting(IServiceCollection services)
|
||||||
|
{
|
||||||
|
this.Services = services ?? throw new ArgumentNullException(nameof(services));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IServiceCollection Services { get; }
|
||||||
|
|
||||||
|
public MeterProviderBuilder Configure(Action<IServiceProvider, MeterProviderBuilder> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,6 +19,7 @@ using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using OpenTelemetry.Metrics;
|
||||||
using OpenTelemetry.Trace;
|
using OpenTelemetry.Trace;
|
||||||
|
|
||||||
namespace OpenTelemetry.Extensions.Hosting.Implementation
|
namespace OpenTelemetry.Extensions.Hosting.Implementation
|
||||||
|
|
@ -36,12 +37,15 @@ namespace OpenTelemetry.Extensions.Hosting.Implementation
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// The sole purpose of this HostedService is to ensure
|
// The sole purpose of this HostedService is to ensure all
|
||||||
// all instrumentations are created and started.
|
// instrumentations, exporters, etc., are created and started.
|
||||||
// This method is invoked when host starts, and
|
var meterProvider = this.serviceProvider.GetService<MeterProvider>();
|
||||||
// by requesting the TracerProvider from DI
|
var tracerProvider = this.serviceProvider.GetService<TracerProvider>();
|
||||||
// it ensures all instrumentations gets started.
|
|
||||||
this.serviceProvider.GetRequiredService<TracerProvider>();
|
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)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -47,10 +47,16 @@ namespace OpenTelemetry.Trace
|
||||||
|
|
||||||
public TracerProvider Build(IServiceProvider serviceProvider)
|
public TracerProvider Build(IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
int i = 0;
|
if (serviceProvider == null)
|
||||||
while (i < this.configurationActions.Count)
|
|
||||||
{
|
{
|
||||||
this.configurationActions[i++](serviceProvider, this);
|
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();
|
return this.Build();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,119 @@
|
||||||
|
// <copyright file="MeterProviderBuilderExtensions.cs" company="OpenTelemetry Authors">
|
||||||
|
// 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.
|
||||||
|
// </copyright>
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace OpenTelemetry.Metrics
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains extension methods for the <see cref="MeterProviderBuilder"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public static class MeterProviderBuilderExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds instrumentation to the provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Instrumentation type.</typeparam>
|
||||||
|
/// <param name="meterProviderBuilder"><see cref="MeterProviderBuilder"/>.</param>
|
||||||
|
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
|
||||||
|
public static MeterProviderBuilder AddInstrumentation<T>(this MeterProviderBuilder meterProviderBuilder)
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
if (meterProviderBuilder is MeterProviderBuilderHosting meterProviderBuilderHosting)
|
||||||
|
{
|
||||||
|
meterProviderBuilderHosting.Configure((sp, builder) => builder
|
||||||
|
.AddInstrumentation(() => sp.GetRequiredService<T>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return meterProviderBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a reader to the provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Reader type.</typeparam>
|
||||||
|
/// <param name="meterProviderBuilder"><see cref="MeterProviderBuilder"/>.</param>
|
||||||
|
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
|
||||||
|
public static MeterProviderBuilder AddReader<T>(this MeterProviderBuilder meterProviderBuilder)
|
||||||
|
where T : MetricReader
|
||||||
|
{
|
||||||
|
if (meterProviderBuilder is MeterProviderBuilderHosting meterProviderBuilderHosting)
|
||||||
|
{
|
||||||
|
meterProviderBuilderHosting.Configure((sp, builder) => builder
|
||||||
|
.AddReader(sp.GetRequiredService<T>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return meterProviderBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Register a callback action to configure the <see
|
||||||
|
/// cref="MeterProviderBuilder"/> once the application <see
|
||||||
|
/// cref="IServiceProvider"/> is available.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="meterProviderBuilder"><see cref="MeterProviderBuilder"/>.</param>
|
||||||
|
/// <param name="configure">Configuration callback.</param>
|
||||||
|
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
|
||||||
|
public static MeterProviderBuilder Configure(this MeterProviderBuilder meterProviderBuilder, Action<IServiceProvider, MeterProviderBuilder> configure)
|
||||||
|
{
|
||||||
|
if (meterProviderBuilder is IDeferredMeterProviderBuilder deferredMeterProviderBuilder)
|
||||||
|
{
|
||||||
|
deferredMeterProviderBuilder.Configure(configure);
|
||||||
|
}
|
||||||
|
|
||||||
|
return meterProviderBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the application <see cref="IServiceCollection"/> attached to
|
||||||
|
/// the <see cref="MeterProviderBuilder"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="meterProviderBuilder"><see cref="MeterProviderBuilder"/>.</param>
|
||||||
|
/// <returns><see cref="IServiceCollection"/> or <see langword="null"/>
|
||||||
|
/// if services are unavailable.</returns>
|
||||||
|
public static IServiceCollection GetServices(this MeterProviderBuilder meterProviderBuilder)
|
||||||
|
{
|
||||||
|
if (meterProviderBuilder is MeterProviderBuilderHosting meterProviderBuilderHosting)
|
||||||
|
{
|
||||||
|
return meterProviderBuilderHosting.Services;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Run the configured actions to initialize the <see cref="MeterProvider"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="meterProviderBuilder"><see cref="MeterProviderBuilder"/>.</param>
|
||||||
|
/// <param name="serviceProvider"><see cref="IServiceProvider"/>.</param>
|
||||||
|
/// <returns><see cref="MeterProvider"/>.</returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -18,6 +18,7 @@ using System;
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using OpenTelemetry.Extensions.Hosting.Implementation;
|
using OpenTelemetry.Extensions.Hosting.Implementation;
|
||||||
|
using OpenTelemetry.Metrics;
|
||||||
using OpenTelemetry.Trace;
|
using OpenTelemetry.Trace;
|
||||||
|
|
||||||
namespace Microsoft.Extensions.DependencyInjection
|
namespace Microsoft.Extensions.DependencyInjection
|
||||||
|
|
@ -55,6 +56,34 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
return services.AddOpenTelemetryTracing(sp => builder.Build(sp));
|
return services.AddOpenTelemetryTracing(sp => builder.Build(sp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds OpenTelemetry MeterProvider to the specified <see cref="IServiceCollection" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
|
||||||
|
/// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns>
|
||||||
|
public static IServiceCollection AddOpenTelemetryMetrics(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
return services.AddOpenTelemetryMetrics(builder => { });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds OpenTelemetry MeterProvider to the specified <see cref="IServiceCollection" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
|
||||||
|
/// <param name="configure">Callback action to configure the <see cref="MeterProviderBuilder"/>.</param>
|
||||||
|
/// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns>
|
||||||
|
public static IServiceCollection AddOpenTelemetryMetrics(this IServiceCollection services, Action<MeterProviderBuilder> configure)
|
||||||
|
{
|
||||||
|
if (configure is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(configure));
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder = new MeterProviderBuilderHosting(services);
|
||||||
|
configure(builder);
|
||||||
|
return services.AddOpenTelemetryMetrics(sp => builder.Build(sp));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds OpenTelemetry TracerProvider to the specified <see cref="IServiceCollection" />.
|
/// Adds OpenTelemetry TracerProvider to the specified <see cref="IServiceCollection" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -85,5 +114,36 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds OpenTelemetry MeterProvider to the specified <see cref="IServiceCollection" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
|
||||||
|
/// <param name="createMeterProvider">A delegate that provides the tracer provider to be registered.</param>
|
||||||
|
/// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns>
|
||||||
|
private static IServiceCollection AddOpenTelemetryMetrics(this IServiceCollection services, Func<IServiceProvider, MeterProvider> createMeterProvider)
|
||||||
|
{
|
||||||
|
if (services is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(services));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (createMeterProvider is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(createMeterProvider));
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService, TelemetryHostedService>());
|
||||||
|
return services.AddSingleton(s => createMeterProvider(s));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
HostingExtensionsEventSource.Log.FailedInitialize(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,120 @@
|
||||||
|
// <copyright file="MeterProviderBuilderBase.cs" company="OpenTelemetry Authors">
|
||||||
|
// 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.
|
||||||
|
// </copyright>
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using OpenTelemetry.Resources;
|
||||||
|
|
||||||
|
namespace OpenTelemetry.Metrics
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Build MeterProvider with Resource, Readers, and Instrumentation.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class MeterProviderBuilderBase : MeterProviderBuilder
|
||||||
|
{
|
||||||
|
private readonly List<InstrumentationFactory> instrumentationFactories = new List<InstrumentationFactory>();
|
||||||
|
private readonly List<string> meterSources = new List<string>();
|
||||||
|
private ResourceBuilder resourceBuilder = ResourceBuilder.CreateDefault();
|
||||||
|
|
||||||
|
protected MeterProviderBuilderBase()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal List<MetricReader> MetricReaders { get; } = new List<MetricReader>();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override MeterProviderBuilder AddInstrumentation<TInstrumentation>(Func<TInstrumentation> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Run the configured actions to initialize the <see cref="MeterProvider"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns><see cref="MeterProvider"/>.</returns>
|
||||||
|
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<object> Factory;
|
||||||
|
|
||||||
|
internal InstrumentationFactory(string name, string version, Func<object> factory)
|
||||||
|
{
|
||||||
|
this.Name = name;
|
||||||
|
this.Version = version;
|
||||||
|
this.Factory = factory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
// </copyright>
|
// </copyright>
|
||||||
|
|
||||||
|
using System;
|
||||||
using OpenTelemetry.Resources;
|
using OpenTelemetry.Resources;
|
||||||
|
|
||||||
namespace OpenTelemetry.Metrics
|
namespace OpenTelemetry.Metrics
|
||||||
|
|
@ -24,16 +25,16 @@ namespace OpenTelemetry.Metrics
|
||||||
public static class MeterProviderBuilderExtensions
|
public static class MeterProviderBuilderExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add metric reader.
|
/// Adds a reader to the provider.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="meterProviderBuilder"><see cref="MeterProviderBuilder"/>.</param>
|
/// <param name="meterProviderBuilder"><see cref="MeterProviderBuilder"/>.</param>
|
||||||
/// <param name="metricReader">Metricreader.</param>
|
/// <param name="reader"><see cref="MetricReader"/>.</param>
|
||||||
/// <returns><see cref="MeterProvider"/>.</returns>
|
/// <returns><see cref="MeterProvider"/>.</returns>
|
||||||
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;
|
return meterProviderBuilder;
|
||||||
|
|
@ -48,9 +49,9 @@ namespace OpenTelemetry.Metrics
|
||||||
/// <returns>Returns <see cref="MeterProviderBuilder"/> for chaining.</returns>
|
/// <returns>Returns <see cref="MeterProviderBuilder"/> for chaining.</returns>
|
||||||
public static MeterProviderBuilder SetResourceBuilder(this MeterProviderBuilder meterProviderBuilder, ResourceBuilder resourceBuilder)
|
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;
|
return meterProviderBuilder;
|
||||||
|
|
@ -63,9 +64,14 @@ namespace OpenTelemetry.Metrics
|
||||||
/// <returns><see cref="MeterProvider"/>.</returns>
|
/// <returns><see cref="MeterProvider"/>.</returns>
|
||||||
public static MeterProvider Build(this MeterProviderBuilder 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)
|
if (meterProviderBuilder is MeterProviderBuilderSdk meterProviderBuilderSdk)
|
||||||
{
|
{
|
||||||
return meterProviderBuilderSdk.Build();
|
return meterProviderBuilderSdk.BuildSdk();
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -14,99 +14,10 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
// </copyright>
|
// </copyright>
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using OpenTelemetry.Resources;
|
|
||||||
|
|
||||||
namespace OpenTelemetry.Metrics
|
namespace OpenTelemetry.Metrics
|
||||||
{
|
{
|
||||||
internal class MeterProviderBuilderSdk : MeterProviderBuilder
|
internal class MeterProviderBuilderSdk : MeterProviderBuilderBase
|
||||||
{
|
{
|
||||||
private readonly List<InstrumentationFactory> instrumentationFactories = new List<InstrumentationFactory>();
|
internal MeterProvider BuildSdk() => this.Build();
|
||||||
private readonly List<string> meterSources = new List<string>();
|
|
||||||
private ResourceBuilder resourceBuilder = ResourceBuilder.CreateDefault();
|
|
||||||
|
|
||||||
internal MeterProviderBuilderSdk()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
internal List<MetricReader> MetricReaders { get; } = new List<MetricReader>();
|
|
||||||
|
|
||||||
public override MeterProviderBuilder AddInstrumentation<TInstrumentation>(Func<TInstrumentation> 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<object> Factory;
|
|
||||||
|
|
||||||
internal InstrumentationFactory(string name, string version, Func<object> factory)
|
|
||||||
{
|
|
||||||
this.Name = name;
|
|
||||||
this.Version = version;
|
|
||||||
this.Factory = factory;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -136,6 +136,10 @@ namespace OpenTelemetry.Metrics
|
||||||
|
|
||||||
internal Resource Resource { get; }
|
internal Resource Resource { get; }
|
||||||
|
|
||||||
|
internal List<object> Instrumentations => this.instrumentations;
|
||||||
|
|
||||||
|
internal MetricReader Reader => this.reader;
|
||||||
|
|
||||||
internal void MeasurementsCompleted(Instrument instrument, object state)
|
internal void MeasurementsCompleted(Instrument instrument, object state)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Instrument {instrument.Meter.Name}:{instrument.Name} completed.");
|
Console.WriteLine($"Instrument {instrument.Meter.Name}:{instrument.Name} completed.");
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ namespace OpenTelemetry.Trace
|
||||||
{
|
{
|
||||||
if (tracerProviderBuilder is IDeferredTracerProviderBuilder)
|
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)
|
if (tracerProviderBuilder is TracerProviderBuilderSdk tracerProviderBuilderSdk)
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ namespace Benchmarks.Metrics
|
||||||
};
|
};
|
||||||
this.provider = Sdk.CreateMeterProviderBuilder()
|
this.provider = Sdk.CreateMeterProviderBuilder()
|
||||||
.AddSource("TestMeter")
|
.AddSource("TestMeter")
|
||||||
.AddMetricReader(this.reader)
|
.AddReader(this.reader)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
this.meter = new Meter("TestMeter");
|
this.meter = new Meter("TestMeter");
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests
|
||||||
using var provider = Sdk.CreateMeterProviderBuilder()
|
using var provider = Sdk.CreateMeterProviderBuilder()
|
||||||
.SetResourceBuilder(resourceBuilder)
|
.SetResourceBuilder(resourceBuilder)
|
||||||
.AddSource("TestMeter")
|
.AddSource("TestMeter")
|
||||||
.AddMetricReader(metricReader)
|
.AddReader(metricReader)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
exporter.ParentProvider = provider;
|
exporter.ParentProvider = provider;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,238 @@
|
||||||
|
// <copyright file="HostingMeterExtensionTests.cs" company="OpenTelemetry Authors">
|
||||||
|
// 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.
|
||||||
|
// </copyright>
|
||||||
|
|
||||||
|
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<MeterProvider>();
|
||||||
|
var meterProvider2 = host.Services.GetRequiredService<MeterProvider>();
|
||||||
|
|
||||||
|
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<TestInstrumentation>()));
|
||||||
|
});
|
||||||
|
|
||||||
|
var serviceProvider = services.BuildServiceProvider();
|
||||||
|
|
||||||
|
var meterFactory = serviceProvider.GetRequiredService<MeterProvider>();
|
||||||
|
Assert.NotNull(meterFactory);
|
||||||
|
|
||||||
|
Assert.False(testInstrumentation.Disposed);
|
||||||
|
|
||||||
|
serviceProvider.Dispose();
|
||||||
|
|
||||||
|
Assert.True(testInstrumentation.Disposed);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AddOpenTelemetryMeterProvider_BadArgs_NullServiceCollection()
|
||||||
|
{
|
||||||
|
ServiceCollection services = null;
|
||||||
|
Assert.Throws<ArgumentNullException>(() => services.AddOpenTelemetryMetrics(null));
|
||||||
|
Assert.Throws<ArgumentNullException>(() =>
|
||||||
|
services.AddOpenTelemetryMetrics(builder =>
|
||||||
|
{
|
||||||
|
builder.Configure(
|
||||||
|
(sp, b) => b.AddInstrumentation(() => sp.GetRequiredService<TestInstrumentation>()));
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AddOpenTelemetryMeterProvider_GetServicesExtension()
|
||||||
|
{
|
||||||
|
var services = new ServiceCollection();
|
||||||
|
services.AddOpenTelemetryMetrics(builder => AddMyFeature(builder));
|
||||||
|
|
||||||
|
using var serviceProvider = services.BuildServiceProvider();
|
||||||
|
|
||||||
|
var meterProvider = (MeterProviderSdk)serviceProvider.GetRequiredService<MeterProvider>();
|
||||||
|
|
||||||
|
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<MeterProvider>();
|
||||||
|
|
||||||
|
Assert.Equal(2, configureCalls);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AddOpenTelemetryMeterProvider_ConfigureCallbacksUsingExtensions()
|
||||||
|
{
|
||||||
|
var services = new ServiceCollection();
|
||||||
|
|
||||||
|
services.AddSingleton<TestInstrumentation>();
|
||||||
|
services.AddSingleton<TestReader>();
|
||||||
|
|
||||||
|
services.AddOpenTelemetryMetrics(builder => builder
|
||||||
|
.Configure((sp1, builder1) =>
|
||||||
|
{
|
||||||
|
builder1
|
||||||
|
.AddInstrumentation<TestInstrumentation>()
|
||||||
|
.AddReader<TestReader>();
|
||||||
|
}));
|
||||||
|
|
||||||
|
using var serviceProvider = services.BuildServiceProvider();
|
||||||
|
|
||||||
|
var meterProvider = (MeterProviderSdk)serviceProvider.GetRequiredService<MeterProvider>();
|
||||||
|
|
||||||
|
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<MeterProvider>();
|
||||||
|
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<TestReader>();
|
||||||
|
|
||||||
|
return meterProviderBuilder.AddReader<TestReader>();
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Metric> metrics, int timeoutMilliseconds)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// <copyright file="HostingExtensionsTests.cs" company="OpenTelemetry Authors">
|
// <copyright file="HostingTracerExtensionTests.cs" company="OpenTelemetry Authors">
|
||||||
// Copyright The OpenTelemetry Authors
|
// Copyright The OpenTelemetry Authors
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
|
@ -25,7 +25,7 @@ using Xunit;
|
||||||
|
|
||||||
namespace OpenTelemetry.Extensions.Hosting.Tests
|
namespace OpenTelemetry.Extensions.Hosting.Tests
|
||||||
{
|
{
|
||||||
public class HostingExtensionsTests
|
public class HostingTracerExtensionTests
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task AddOpenTelemetryTracerProviderInstrumentationCreationAndDisposal()
|
public async Task AddOpenTelemetryTracerProviderInstrumentationCreationAndDisposal()
|
||||||
|
|
@ -69,7 +69,7 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Tests
|
||||||
};
|
};
|
||||||
this.meterProvider = Sdk.CreateMeterProviderBuilder()
|
this.meterProvider = Sdk.CreateMeterProviderBuilder()
|
||||||
.AddAspNetCoreInstrumentation()
|
.AddAspNetCoreInstrumentation()
|
||||||
.AddMetricReader(metricReader)
|
.AddReader(metricReader)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
using (var client = this.factory.CreateClient())
|
using (var client = this.factory.CreateClient())
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ namespace OpenTelemetry.Instrumentation.Http.Tests
|
||||||
};
|
};
|
||||||
var meterProvider = Sdk.CreateMeterProviderBuilder()
|
var meterProvider = Sdk.CreateMeterProviderBuilder()
|
||||||
.AddHttpClientInstrumentation()
|
.AddHttpClientInstrumentation()
|
||||||
.AddMetricReader(metricReader)
|
.AddReader(metricReader)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
using (serverLifeTime)
|
using (serverLifeTime)
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ namespace OpenTelemetry.Metrics.Tests
|
||||||
|
|
||||||
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
||||||
.AddSource("InMemoryExporterTests")
|
.AddSource("InMemoryExporterTests")
|
||||||
.AddMetricReader(inMemoryReader)
|
.AddReader(inMemoryReader)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var counter = meter.CreateCounter<long>("meter");
|
var counter = meter.CreateCounter<long>("meter");
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ namespace OpenTelemetry.Metrics.Tests
|
||||||
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
||||||
.AddSource("TestDuplicateMetricName1")
|
.AddSource("TestDuplicateMetricName1")
|
||||||
.AddSource("TestDuplicateMetricName2")
|
.AddSource("TestDuplicateMetricName2")
|
||||||
.AddMetricReader(metricReader)
|
.AddReader(metricReader)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
// Expecting one metric stream.
|
// Expecting one metric stream.
|
||||||
|
|
@ -117,7 +117,7 @@ namespace OpenTelemetry.Metrics.Tests
|
||||||
var counterLong = meter.CreateCounter<long>("mycounter");
|
var counterLong = meter.CreateCounter<long>("mycounter");
|
||||||
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
||||||
.AddSource("TestMeter")
|
.AddSource("TestMeter")
|
||||||
.AddMetricReader(metricReader)
|
.AddReader(metricReader)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
counterLong.Add(10);
|
counterLong.Add(10);
|
||||||
|
|
@ -202,7 +202,7 @@ namespace OpenTelemetry.Metrics.Tests
|
||||||
});
|
});
|
||||||
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
||||||
.AddSource(meterName)
|
.AddSource(meterName)
|
||||||
.AddMetricReader(metricReader)
|
.AddReader(metricReader)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
metricReader.Collect();
|
metricReader.Collect();
|
||||||
|
|
@ -262,7 +262,7 @@ namespace OpenTelemetry.Metrics.Tests
|
||||||
var counterLong = meter.CreateCounter<long>("mycounterCapTest");
|
var counterLong = meter.CreateCounter<long>("mycounterCapTest");
|
||||||
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
||||||
.AddSource("TestPointCapMeter")
|
.AddSource("TestPointCapMeter")
|
||||||
.AddMetricReader(metricReader)
|
.AddReader(metricReader)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
// Make one Add with no tags.
|
// Make one Add with no tags.
|
||||||
|
|
@ -314,7 +314,7 @@ namespace OpenTelemetry.Metrics.Tests
|
||||||
var counterLong = meter.CreateCounter<long>("mycounter");
|
var counterLong = meter.CreateCounter<long>("mycounter");
|
||||||
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
||||||
.AddSource("TestLongCounterMeter")
|
.AddSource("TestLongCounterMeter")
|
||||||
.AddMetricReader(metricReader)
|
.AddReader(metricReader)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
// setup args to threads.
|
// setup args to threads.
|
||||||
|
|
@ -383,7 +383,7 @@ namespace OpenTelemetry.Metrics.Tests
|
||||||
var counterDouble = meter.CreateCounter<double>("mycounter");
|
var counterDouble = meter.CreateCounter<double>("mycounter");
|
||||||
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
||||||
.AddSource("TestDoubleCounterMeter")
|
.AddSource("TestDoubleCounterMeter")
|
||||||
.AddMetricReader(metricReader)
|
.AddReader(metricReader)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
// setup args to threads.
|
// setup args to threads.
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ namespace OpenTelemetry.Metrics.Tests
|
||||||
|
|
||||||
var reader = new BaseExportingMetricReader(exporter);
|
var reader = new BaseExportingMetricReader(exporter);
|
||||||
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
||||||
.AddMetricReader(reader)
|
.AddReader(reader)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
switch (mode)
|
switch (mode)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue