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()
|
||||
.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();
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ OpenTelemetry.Context.RemotingRuntimeContextSlot<T>.Value.get -> object
|
|||
OpenTelemetry.Context.RemotingRuntimeContextSlot<T>.Value.set -> void
|
||||
OpenTelemetry.Context.ThreadLocalRuntimeContextSlot<T>.Value.get -> object
|
||||
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>.Set(T value) -> void
|
||||
OpenTelemetry.Context.AsyncLocalRuntimeContextSlot<T>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ OpenTelemetry.Context.IRuntimeContextSlotValueAccessor.Value.get -> object
|
|||
OpenTelemetry.Context.IRuntimeContextSlotValueAccessor.Value.set -> void
|
||||
OpenTelemetry.Context.ThreadLocalRuntimeContextSlot<T>.Value.get -> object
|
||||
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<T>(string slotName) -> T
|
||||
static OpenTelemetry.Context.RuntimeContext.SetValue(string slotName, object value) -> void
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
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 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);
|
||||
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
|
||||
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<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, 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.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
|
||||
|
|
|
|||
|
|
@ -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<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
|
||||
|
||||
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 Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using OpenTelemetry.Metrics;
|
||||
using OpenTelemetry.Trace;
|
||||
|
||||
namespace OpenTelemetry.Extensions.Hosting.Implementation
|
||||
|
|
@ -36,12 +37,15 @@ namespace OpenTelemetry.Extensions.Hosting.Implementation
|
|||
{
|
||||
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<TracerProvider>();
|
||||
// The sole purpose of this HostedService is to ensure all
|
||||
// instrumentations, exporters, etc., are created and started.
|
||||
var meterProvider = this.serviceProvider.GetService<MeterProvider>();
|
||||
var tracerProvider = this.serviceProvider.GetService<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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -47,10 +47,16 @@ namespace OpenTelemetry.Trace
|
|||
|
||||
public TracerProvider Build(IServiceProvider serviceProvider)
|
||||
{
|
||||
int i = 0;
|
||||
while (i < this.configurationActions.Count)
|
||||
if (serviceProvider == null)
|
||||
{
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -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.Hosting;
|
||||
using OpenTelemetry.Extensions.Hosting.Implementation;
|
||||
using OpenTelemetry.Metrics;
|
||||
using OpenTelemetry.Trace;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
|
|
@ -55,6 +56,34 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
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>
|
||||
/// Adds OpenTelemetry TracerProvider to the specified <see cref="IServiceCollection" />.
|
||||
/// </summary>
|
||||
|
|
@ -85,5 +114,36 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
|
||||
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.
|
||||
// </copyright>
|
||||
|
||||
using System;
|
||||
using OpenTelemetry.Resources;
|
||||
|
||||
namespace OpenTelemetry.Metrics
|
||||
|
|
@ -24,16 +25,16 @@ namespace OpenTelemetry.Metrics
|
|||
public static class MeterProviderBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Add metric reader.
|
||||
/// Adds a reader to the provider.
|
||||
/// </summary>
|
||||
/// <param name="meterProviderBuilder"><see cref="MeterProviderBuilder"/>.</param>
|
||||
/// <param name="metricReader">Metricreader.</param>
|
||||
/// <param name="reader"><see cref="MetricReader"/>.</param>
|
||||
/// <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;
|
||||
|
|
@ -48,9 +49,9 @@ namespace OpenTelemetry.Metrics
|
|||
/// <returns>Returns <see cref="MeterProviderBuilder"/> for chaining.</returns>
|
||||
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 @@ namespace OpenTelemetry.Metrics
|
|||
/// <returns><see cref="MeterProvider"/>.</returns>
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -14,99 +14,10 @@
|
|||
// limitations under the License.
|
||||
// </copyright>
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenTelemetry.Resources;
|
||||
|
||||
namespace OpenTelemetry.Metrics
|
||||
{
|
||||
internal class MeterProviderBuilderSdk : MeterProviderBuilder
|
||||
internal class MeterProviderBuilderSdk : MeterProviderBuilderBase
|
||||
{
|
||||
private readonly List<InstrumentationFactory> instrumentationFactories = new List<InstrumentationFactory>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
internal MeterProvider BuildSdk() => this.Build();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,6 +136,10 @@ namespace OpenTelemetry.Metrics
|
|||
|
||||
internal Resource Resource { get; }
|
||||
|
||||
internal List<object> Instrumentations => this.instrumentations;
|
||||
|
||||
internal MetricReader Reader => this.reader;
|
||||
|
||||
internal void MeasurementsCompleted(Instrument instrument, object state)
|
||||
{
|
||||
Console.WriteLine($"Instrument {instrument.Meter.Name}:{instrument.Name} completed.");
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ namespace OpenTelemetry.Trace
|
|||
{
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ namespace Benchmarks.Metrics
|
|||
};
|
||||
this.provider = Sdk.CreateMeterProviderBuilder()
|
||||
.AddSource("TestMeter")
|
||||
.AddMetricReader(this.reader)
|
||||
.AddReader(this.reader)
|
||||
.Build();
|
||||
|
||||
this.meter = new Meter("TestMeter");
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests
|
|||
using var provider = Sdk.CreateMeterProviderBuilder()
|
||||
.SetResourceBuilder(resourceBuilder)
|
||||
.AddSource("TestMeter")
|
||||
.AddMetricReader(metricReader)
|
||||
.AddReader(metricReader)
|
||||
.Build();
|
||||
|
||||
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
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
|
@ -25,7 +25,7 @@ using Xunit;
|
|||
|
||||
namespace OpenTelemetry.Extensions.Hosting.Tests
|
||||
{
|
||||
public class HostingExtensionsTests
|
||||
public class HostingTracerExtensionTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task AddOpenTelemetryTracerProviderInstrumentationCreationAndDisposal()
|
||||
|
|
@ -69,7 +69,7 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Tests
|
|||
};
|
||||
this.meterProvider = Sdk.CreateMeterProviderBuilder()
|
||||
.AddAspNetCoreInstrumentation()
|
||||
.AddMetricReader(metricReader)
|
||||
.AddReader(metricReader)
|
||||
.Build();
|
||||
|
||||
using (var client = this.factory.CreateClient())
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ namespace OpenTelemetry.Instrumentation.Http.Tests
|
|||
};
|
||||
var meterProvider = Sdk.CreateMeterProviderBuilder()
|
||||
.AddHttpClientInstrumentation()
|
||||
.AddMetricReader(metricReader)
|
||||
.AddReader(metricReader)
|
||||
.Build();
|
||||
|
||||
using (serverLifeTime)
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ namespace OpenTelemetry.Metrics.Tests
|
|||
|
||||
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
||||
.AddSource("InMemoryExporterTests")
|
||||
.AddMetricReader(inMemoryReader)
|
||||
.AddReader(inMemoryReader)
|
||||
.Build();
|
||||
|
||||
var counter = meter.CreateCounter<long>("meter");
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ namespace OpenTelemetry.Metrics.Tests
|
|||
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
||||
.AddSource("TestDuplicateMetricName1")
|
||||
.AddSource("TestDuplicateMetricName2")
|
||||
.AddMetricReader(metricReader)
|
||||
.AddReader(metricReader)
|
||||
.Build();
|
||||
|
||||
// Expecting one metric stream.
|
||||
|
|
@ -117,7 +117,7 @@ namespace OpenTelemetry.Metrics.Tests
|
|||
var counterLong = meter.CreateCounter<long>("mycounter");
|
||||
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
||||
.AddSource("TestMeter")
|
||||
.AddMetricReader(metricReader)
|
||||
.AddReader(metricReader)
|
||||
.Build();
|
||||
|
||||
counterLong.Add(10);
|
||||
|
|
@ -202,7 +202,7 @@ namespace OpenTelemetry.Metrics.Tests
|
|||
});
|
||||
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
||||
.AddSource(meterName)
|
||||
.AddMetricReader(metricReader)
|
||||
.AddReader(metricReader)
|
||||
.Build();
|
||||
|
||||
metricReader.Collect();
|
||||
|
|
@ -262,7 +262,7 @@ namespace OpenTelemetry.Metrics.Tests
|
|||
var counterLong = meter.CreateCounter<long>("mycounterCapTest");
|
||||
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
||||
.AddSource("TestPointCapMeter")
|
||||
.AddMetricReader(metricReader)
|
||||
.AddReader(metricReader)
|
||||
.Build();
|
||||
|
||||
// Make one Add with no tags.
|
||||
|
|
@ -314,7 +314,7 @@ namespace OpenTelemetry.Metrics.Tests
|
|||
var counterLong = meter.CreateCounter<long>("mycounter");
|
||||
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
||||
.AddSource("TestLongCounterMeter")
|
||||
.AddMetricReader(metricReader)
|
||||
.AddReader(metricReader)
|
||||
.Build();
|
||||
|
||||
// setup args to threads.
|
||||
|
|
@ -383,7 +383,7 @@ namespace OpenTelemetry.Metrics.Tests
|
|||
var counterDouble = meter.CreateCounter<double>("mycounter");
|
||||
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
||||
.AddSource("TestDoubleCounterMeter")
|
||||
.AddMetricReader(metricReader)
|
||||
.AddReader(metricReader)
|
||||
.Build();
|
||||
|
||||
// setup args to threads.
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ namespace OpenTelemetry.Metrics.Tests
|
|||
|
||||
var reader = new BaseExportingMetricReader(exporter);
|
||||
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
||||
.AddMetricReader(reader)
|
||||
.AddReader(reader)
|
||||
.Build();
|
||||
|
||||
switch (mode)
|
||||
|
|
|
|||
Loading…
Reference in New Issue