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

[Tracing] Improve dependency injection support in tracing build-up using SDK #3533

Merged
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
7c0d427
TracerBuilder depedency injection improvements.
CodeBlanch Aug 3, 2022
4c01825
Fixes and API updates.
CodeBlanch Aug 3, 2022
a64ae6b
Update skipped test.
CodeBlanch Aug 3, 2022
816736e
Tweak.
CodeBlanch Aug 3, 2022
ae8a856
Tweaks.
CodeBlanch Aug 3, 2022
96e29c2
Test fix.
CodeBlanch Aug 4, 2022
bb17782
Turn on options in TracerProviderBuilderBase.
CodeBlanch Aug 4, 2022
ed11c2b
Updated CHANGELOGs.
CodeBlanch Aug 4, 2022
95f71d3
Merge remote-tracking branch 'upstream/main' into tracerprovider-depe…
CodeBlanch Aug 4, 2022
dcfb85a
Added XML comments to AddOpenTelemetryTracing methods.
CodeBlanch Aug 4, 2022
a22dad3
Merge remote-tracking branch 'upstream/main' into tracerprovider-depe…
CodeBlanch Aug 5, 2022
a1ea05d
Tweaks.
CodeBlanch Aug 5, 2022
b5d285d
Merge from main.
CodeBlanch Aug 6, 2022
e02a951
Added export helpers and restored removed API from hosting library so…
CodeBlanch Aug 6, 2022
d3b0ac6
Export extension tweaks.
CodeBlanch Aug 6, 2022
c0eee21
Tweak.
CodeBlanch Aug 6, 2022
f3f0e85
Tracer builder improvements.
CodeBlanch Aug 8, 2022
d8338cd
Fix hosting multiple configurations test.
CodeBlanch Aug 8, 2022
2a7906d
Cleanup.
CodeBlanch Aug 8, 2022
dea2152
Cleanup and fixes.
CodeBlanch Aug 9, 2022
8be5f98
Added "UseOpenTelemetry" extensions.
CodeBlanch Aug 15, 2022
9e02797
Cleanup.
CodeBlanch Aug 15, 2022
b458552
Code review.
CodeBlanch Aug 17, 2022
489ae0c
Code review.
CodeBlanch Aug 17, 2022
d953928
Rename SDK extension "Configure" and restore "Add" in the hosting lib.
CodeBlanch Aug 17, 2022
cd95c32
Merging from main.
CodeBlanch Aug 19, 2022
57e3b49
Doc clarification.
CodeBlanch Aug 19, 2022
6467f6d
Some test coverage.
CodeBlanch Aug 19, 2022
cb37f39
README updates.
CodeBlanch Aug 19, 2022
ecd1df4
Fix double dispose of TracerProvider when using Sdk.CreateTracerProvi…
CodeBlanch Aug 19, 2022
59979e2
AddExporter tests.
CodeBlanch Aug 19, 2022
923211d
More test coverage.
CodeBlanch Aug 19, 2022
ae64512
More test coverage.
CodeBlanch Aug 19, 2022
856c751
Code review.
CodeBlanch Aug 23, 2022
b3a46b5
Merge branch 'main' into tracerprovider-dependencyinjection
CodeBlanch Aug 23, 2022
c91f02d
Merge branch 'main' into tracerprovider-dependencyinjection
CodeBlanch Aug 29, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/MicroserviceExample/WorkerService/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public static IHostBuilder CreateHostBuilder(string[] args) =>

services.AddSingleton<MessageReceiver>();

services.AddOpenTelemetryTracing((builder) =>
services.AddOpenTelemetryTracing(builder =>
{
builder
.AddSource(nameof(MessageReceiver))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
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
Expand All @@ -10,9 +9,3 @@ static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader<T>(this Op
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
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.Configure(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, System.Action<System.IServiceProvider, OpenTelemetry.Trace.TracerProviderBuilder> configure) -> OpenTelemetry.Trace.TracerProviderBuilder
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.GetServices(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder) -> Microsoft.Extensions.DependencyInjection.IServiceCollection
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.SetSampler<T>(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder
4 changes: 4 additions & 0 deletions src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

* Dependency injection support when configuring
`TracerProvider` has been moved into the SDK.
([#3533](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3533))

## 1.0.0-rc9.6

Released 2022-Aug-18
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,49 +15,56 @@
// </copyright>

using System;
using System.Diagnostics;
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
namespace OpenTelemetry.Extensions.Hosting.Implementation;

internal sealed class TelemetryHostedService : IHostedService
{
internal class TelemetryHostedService : IHostedService
private readonly IServiceProvider serviceProvider;

public TelemetryHostedService(IServiceProvider serviceProvider)
{
private readonly IServiceProvider serviceProvider;
this.serviceProvider = serviceProvider;
}

public TelemetryHostedService(IServiceProvider serviceProvider)
public Task StartAsync(CancellationToken cancellationToken)
{
try
{
this.serviceProvider = serviceProvider;
// The sole purpose of this HostedService is to ensure all
// instrumentations, exporters, etc., are created and started.
Initialize(this.serviceProvider);
}

public Task StartAsync(CancellationToken cancellationToken)
catch (Exception ex)
{
try
{
// 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)
{
HostingExtensionsEventSource.Log.FailedOpenTelemetrySDK(ex);
}

return Task.CompletedTask;
HostingExtensionsEventSource.Log.FailedOpenTelemetrySDK(ex);
}

public Task StopAsync(CancellationToken cancellationToken)
return Task.CompletedTask;
}

public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}

internal static void Initialize(IServiceProvider serviceProvider)
{
Debug.Assert(serviceProvider != null, "serviceProvider was null");

var meterProvider = serviceProvider.GetService<MeterProvider>();
var tracerProvider = serviceProvider.GetService<TracerProvider>();

if (meterProvider == null && tracerProvider == null)
{
return Task.CompletedTask;
throw new InvalidOperationException("Could not resolve either MeterProvider or TracerProvider through application ServiceProvider, OpenTelemetry SDK has not been initialized.");
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- OmniSharp/VS Code requires TargetFrameworks to be in descending order for IntelliSense and analysis. -->
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<Description>Startup extensions to register OpenTelemetry into the applications using Microsoft.Extensions.DependencyInjection and Microsoft.Extensions.Hosting</Description>
<Description>Contains extensions to register and start OpenTelemetry in applications using Microsoft.Extensions.Hosting</Description>
<RootNamespace>OpenTelemetry</RootNamespace>
</PropertyGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,28 +32,38 @@ namespace Microsoft.Extensions.DependencyInjection
public static class OpenTelemetryServicesExtensions
{
/// <summary>
/// Adds OpenTelemetry TracerProvider to the specified <see cref="IServiceCollection" />.
/// Configure OpenTelemetry and register a <see cref="IHostedService"/>
/// to automatically start tracing services in the supplied <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>
/// <remarks>
/// Note: This is safe to be called multiple times and by library authors.
/// Only a single <see cref="TracerProvider"/> will be created for a given
/// <see cref="IServiceCollection"/>.
/// </remarks>
/// <param name="services"><see cref="IServiceCollection"/>.</param>
/// <returns>Supplied <see cref="IServiceCollection"/> for chaining calls.</returns>
public static IServiceCollection AddOpenTelemetryTracing(this IServiceCollection services)
{
return services.AddOpenTelemetryTracing(builder => { });
}
=> AddOpenTelemetryTracing(services, (b) => { });

/// <summary>
/// Adds OpenTelemetry TracerProvider to the specified <see cref="IServiceCollection" />.
/// Configure OpenTelemetry and register a <see cref="IHostedService"/>
/// to automatically start tracing services in the supplied <see
/// cref="IServiceCollection" />.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
/// <remarks><inheritdoc cref="AddOpenTelemetryTracing(IServiceCollection)" path="/remarks"/></remarks>
/// <param name="services"><see cref="IServiceCollection"/>.</param>
/// <param name="configure">Callback action to configure the <see cref="TracerProviderBuilder"/>.</param>
/// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns>
/// <returns>Supplied <see cref="IServiceCollection"/> for chaining calls.</returns>
public static IServiceCollection AddOpenTelemetryTracing(this IServiceCollection services, Action<TracerProviderBuilder> configure)
{
Guard.ThrowIfNull(configure);
Guard.ThrowIfNull(services);

var builder = new TracerProviderBuilderHosting(services);
configure(builder);
return services.AddOpenTelemetryTracing(sp => builder.Build(sp));
services.ConfigureOpenTelemetryTracing(configure);

services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService, TelemetryHostedService>());

return services;
}

/// <summary>
Expand Down Expand Up @@ -81,34 +91,6 @@ public static IServiceCollection AddOpenTelemetryMetrics(this IServiceCollection
return services.AddOpenTelemetryMetrics(sp => builder.Build(sp));
}

/// <summary>
/// Adds OpenTelemetry TracerProvider to the specified <see cref="IServiceCollection" />.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
/// <param name="createTracerProvider">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 AddOpenTelemetryTracing(this IServiceCollection services, Func<IServiceProvider, TracerProvider> createTracerProvider)
{
Guard.ThrowIfNull(services);
Guard.ThrowIfNull(createTracerProvider);

// Accessing Sdk class is just to trigger its static ctor,
// which sets default Propagators and default Activity Id format
_ = Sdk.SuppressInstrumentation;

try
{
services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService, TelemetryHostedService>());
return services.AddSingleton(s => createTracerProvider(s));
}
catch (Exception ex)
{
HostingExtensionsEventSource.Log.FailedInitialize(ex);
}

return services;
}

/// <summary>
/// Adds OpenTelemetry MeterProvider to the specified <see cref="IServiceCollection" />.
/// </summary>
Expand Down
24 changes: 11 additions & 13 deletions src/OpenTelemetry.Extensions.Hosting/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,27 +45,27 @@ Similar methods exist for registering instrumentation (`AddInstrumentation<T>`)
and setting a sampler (`SetSampler<T>`).

You can also access the application `IServiceProvider` directly and accomplish
the same registration using the `Configure` extension like this:
the same registration using the `ConfigureBuilder` extension like this:

```csharp
services.AddSingleton<MyProcessor>();

services.AddOpenTelemetryTracing(hostingBuilder => hostingBuilder
.Configure((sp, builder) => builder
.ConfigureBuilder((sp, builder) => builder
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddProcessor(sp.GetRequiredService<MyProcessor>())));
```

**Note:** `Configure` is called _after_ the `IServiceProvider` has been built
**Note:** `ConfigureBuilder` is called _after_ the `IServiceProvider` has been built
from the application `IServiceCollection` so any services registered in the
`Configure` callback will be ignored.
`ConfigureBuilder` callback will be ignored.

#### Building Extension Methods

Library authors may want to configure the OpenTelemetry `TracerProvider` and
register application services to provide more complex features. This can be
accomplished concisely by using the `TracerProviderBuilder.GetServices`
accomplished concisely by using the `TracerProviderBuilder.ConfigureServices`
extension method inside of a more general `TracerProviderBuilder` configuration
extension like this:

Expand All @@ -74,15 +74,13 @@ public static class MyLibraryExtensions
{
public static TracerProviderBuilder AddMyFeature(this TracerProviderBuilder tracerProviderBuilder)
{
(tracerProviderBuilder.GetServices()
?? throw new NotSupportedException(
"MyFeature requires a hosting TracerProviderBuilder instance."))
.AddHostedService<MyHostedService>()
.AddSingleton<MyService>()
.AddSingleton<MyProcessor>()
.AddSingleton<MySampler>();

return tracerProviderBuilder
.ConfigureServices(services =>
services
.AddHostedService<MyHostedService>()
.AddSingleton<MyService>()
.AddSingleton<MyProcessor>()
.AddSingleton<MySampler>())
.AddProcessor<MyProcessor>()
.SetSampler<MySampler>();
}
Expand Down
Loading