Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hosting: Support metrics registration via IServiceCollection & deferred configuration #2412

Merged
merged 11 commits into from
Sep 27, 2021
4 changes: 2 additions & 2 deletions docs/metrics/extending-the-sdk/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ public static void Main(string[] args)
{
using var meterProvider = Sdk.CreateMeterProviderBuilder()
.AddSource("MyCompany.MyProduct.MyLibrary")
.AddMetricReader(new MyReader())
.AddReader(new MyReader())
CodeBlanch marked this conversation as resolved.
Show resolved Hide resolved
/** /
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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions src/OpenTelemetry.Api/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
36 changes: 36 additions & 0 deletions src/OpenTelemetry.Api/Metrics/IDeferredMeterProviderBuilder.cs
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ public static MeterProviderBuilder AddConsoleExporter(this MeterProviderBuilder

if (options.MetricExportIntervalMilliseconds == Timeout.Infinite)
{
return builder.AddMetricReader(new BaseExportingMetricReader(exporter));
return builder.AddReader(new BaseExportingMetricReader(exporter));
}

return builder.AddMetricReader(new PeriodicExportingMetricReader(exporter, options.MetricExportIntervalMilliseconds));
return builder.AddReader(new PeriodicExportingMetricReader(exporter, options.MetricExportIntervalMilliseconds));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public static MeterProviderBuilder AddInMemoryExporter(this MeterProviderBuilder
throw new ArgumentNullException(nameof(exportedItems));
}

return builder.AddMetricReader(new BaseExportingMetricReader(new InMemoryExporter<Metric>(exportedItems)));
return builder.AddReader(new BaseExportingMetricReader(new InMemoryExporter<Metric>(exportedItems)));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public static MeterProviderBuilder AddOtlpExporter(this MeterProviderBuilder bui

var metricExporter = new OtlpMetricsExporter(options);
var metricReader = new PeriodicExportingMetricReader(metricExporter, options.MetricExportIntervalMilliseconds);
return builder.AddMetricReader(metricReader);
return builder.AddReader(metricReader);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public static MeterProviderBuilder AddPrometheusExporter(this MeterProviderBuild

var metricsHttpServer = new PrometheusExporterMetricsHttpServer(exporter);
metricsHttpServer.Start();
return builder.AddMetricReader(reader);
return builder.AddReader(reader);
}
}
}
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Expand Down
6 changes: 6 additions & 0 deletions src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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>`, & `Configure` extensions on
CodeBlanch marked this conversation as resolved.
Show resolved Hide resolved
`MeterProviderBuilder` to support dependency injection scenarios.
([#2412](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2412))

## 1.0.0-rc7

Released 2021-Jul-12
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// <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)
CodeBlanch marked this conversation as resolved.
Show resolved Hide resolved
{
// 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();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;

namespace OpenTelemetry.Extensions.Hosting.Implementation
Expand All @@ -36,12 +37,15 @@ public Task StartAsync(CancellationToken cancellationToken)
{
try
{
// The sole purpose of this HostedService is to ensure
// all instrumentations are created and started.
// This method is invoked when host starts, and
// by requesting the TracerProvider from DI
// it ensures all instrumentations gets started.
this.serviceProvider.GetRequiredService<TracerProvider>();
// The sole purpose of this HostedService is to ensure all
// instrumentations, exporters, etc., are created and started.
var meterProvider = this.serviceProvider.GetService<MeterProvider>();
CodeBlanch marked this conversation as resolved.
Show resolved Hide resolved
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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,11 @@ public TracerProviderBuilder Configure(Action<IServiceProvider, TracerProviderBu

public TracerProvider Build(IServiceProvider serviceProvider)
{
int i = 0;
while (i < this.configurationActions.Count)
// 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);
this.configurationActions[i](serviceProvider, this);
}

return this.Build();
Expand Down
Loading