[sdk+hosting] Move AddOpenTelemetry & OpenTelemetryBuilder into Hosting package (#4174)

* Move AddOpenTelemetry & OpenTelemetryBuilder into Hosting package.

* Added Azure Functions warning.

* Test fixes.

* Test fixes.

* Patch CHANGELOGs.

* Hosting README updates.

* Comment tweak.

* Clean up.

* Test cleanup.

* MD lint.

* Test fixes.
This commit is contained in:
Mikel Blanchard 2023-02-10 12:11:26 -08:00 committed by GitHub
parent 94f67d8a8c
commit 74212a2402
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 499 additions and 747 deletions

View File

@ -15,7 +15,6 @@
// </copyright>
using System.Diagnostics;
using OpenTelemetry;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
@ -27,8 +26,7 @@ appBuilder.Services.AddOpenTelemetry()
.AddService(serviceName: "OTel.NET Getting Started"))
.WithTracing(builder => builder
.AddAspNetCoreInstrumentation()
.AddConsoleExporter())
.StartWithHost();
.AddConsoleExporter());
var app = appBuilder.Build();

View File

@ -15,7 +15,6 @@
// </copyright>
using Examples.AspNetCore;
using OpenTelemetry;
using OpenTelemetry.Exporter;
using OpenTelemetry.Instrumentation.AspNetCore;
using OpenTelemetry.Logs;
@ -45,7 +44,7 @@ Action<ResourceBuilder> configureResource = r => r.AddService(
appBuilder.Services.AddSingleton<Instrumentation>();
// Configure OpenTelemetry tracing & metrics with auto-start using the
// StartWithHost extension from OpenTelemetry.Extensions.Hosting.
// AddOpenTelemetry extension from OpenTelemetry.Extensions.Hosting.
appBuilder.Services.AddOpenTelemetry()
.ConfigureResource(configureResource)
.WithTracing(builder =>
@ -127,8 +126,7 @@ appBuilder.Services.AddOpenTelemetry()
builder.AddConsoleExporter();
break;
}
})
.StartWithHost();
});
// Clear default logging providers used by WebApplication host.
appBuilder.Logging.ClearProviders();

View File

@ -14,7 +14,6 @@
// limitations under the License.
// </copyright>
using OpenTelemetry;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
@ -61,8 +60,7 @@ namespace Examples.GrpcService
builder.AddConsoleExporter();
break;
}
})
.StartWithHost();
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

View File

@ -14,7 +14,6 @@
// limitations under the License.
// </copyright>
using OpenTelemetry;
using OpenTelemetry.Trace;
using Utils.Messaging;
@ -43,8 +42,7 @@ namespace WebApi
{
var zipkinHostName = Environment.GetEnvironmentVariable("ZIPKIN_HOSTNAME") ?? "localhost";
b.Endpoint = new Uri($"http://{zipkinHostName}:9411/api/v2/spans");
}))
.StartWithHost();
}));
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

View File

@ -14,7 +14,6 @@
// limitations under the License.
// </copyright>
using OpenTelemetry;
using OpenTelemetry.Trace;
using Utils.Messaging;
@ -42,8 +41,7 @@ namespace WorkerService
{
var zipkinHostName = Environment.GetEnvironmentVariable("ZIPKIN_HOSTNAME") ?? "localhost";
b.Endpoint = new Uri($"http://{zipkinHostName}:9411/api/v2/spans");
}))
.StartWithHost();
}));
});
}
}

View File

@ -98,8 +98,7 @@ services.AddOpenTelemetry()
client.DefaultRequestHeaders.Add("X-MyCustomHeader", "value");
return client;
};
}))
.StartWithHost();
}));
```
For users using

View File

@ -135,8 +135,7 @@ services.AddOpenTelemetry()
client.DefaultRequestHeaders.Add("X-MyCustomHeader", "value");
return client;
};
}))
.StartWithHost();
}));
```
For users using

View File

@ -28,8 +28,7 @@ dotnet add package --prerelease OpenTelemetry.Exporter.Prometheus.AspNetCore
```csharp
services.AddOpenTelemetry()
.WithMetrics(builder => builder
.AddPrometheusExporter())
.StartWithHost();
.AddPrometheusExporter());
```
* Or configure directly:

View File

@ -87,8 +87,7 @@ services.AddOpenTelemetry()
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("X-MyCustomHeader", "value");
return client;
}))
.StartWithHost();
}));
```
For users using

View File

@ -1,13 +1,19 @@
Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions
OpenTelemetry.Metrics.MeterProviderBuilderExtensions
OpenTelemetry.OpenTelemetryBuilderHostingExtensions
OpenTelemetry.OpenTelemetryBuilder
OpenTelemetry.OpenTelemetryBuilder.ConfigureResource(System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.Services.get -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
OpenTelemetry.OpenTelemetryBuilder.WithMetrics() -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithMetrics(System.Action<OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithTracing() -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithTracing(System.Action<OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
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.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.OpenTelemetryBuilderHostingExtensions.StartWithHost(this OpenTelemetry.OpenTelemetryBuilder builder) -> OpenTelemetry.OpenTelemetryBuilder
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 Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions.AddOpenTelemetry(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> OpenTelemetry.OpenTelemetryBuilder!
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.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.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!

View File

@ -2,6 +2,11 @@
## Unreleased
* Added `AddOpenTelemetry` extension from SDK and removed `StartWithHost`.
`AddOpenTelemetry` now registers the `IHostedService` used to start collecting
traces and/or metrics.
([#4174](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4174))
## 1.4.0-rc.3
Released 2023-Feb-01

View File

@ -20,6 +20,10 @@ using Microsoft.Extensions.Hosting;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
// Warning: Do not change the namespace or class name in this file! Azure
// Functions has taken a dependency on the specific details:
// https://github.com/Azure/azure-functions-host/blob/d4655cc4fbb34fc14e6861731991118a9acd02ed/src/WebJobs.Script.WebHost/DependencyInjection/DependencyValidator/DependencyValidator.cs#L57
namespace OpenTelemetry.Extensions.Hosting.Implementation;
internal sealed class TelemetryHostedService : IHostedService

View File

@ -15,6 +15,7 @@
// </copyright>
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry.Internal;
namespace OpenTelemetry.Metrics
{
@ -34,7 +35,12 @@ namespace OpenTelemetry.Metrics
[Obsolete("Configure has been replaced by factory extensions. This method will be removed in a future version.")]
public static MeterProviderBuilder Configure(this MeterProviderBuilder meterProviderBuilder, Action<IServiceProvider, MeterProviderBuilder> configure)
{
return (meterProviderBuilder as IDeferredMeterProviderBuilder)?.Configure(configure);
if (meterProviderBuilder is IDeferredMeterProviderBuilder deferredMeterProviderBuilder)
{
deferredMeterProviderBuilder.Configure(configure);
}
return meterProviderBuilder;
}
/// <summary>
@ -47,8 +53,17 @@ namespace OpenTelemetry.Metrics
[Obsolete("Call ConfigureServices instead this method will be removed in a future version.")]
public static IServiceCollection GetServices(this MeterProviderBuilder meterProviderBuilder)
{
IServiceCollection services = null;
Guard.ThrowIfNull(meterProviderBuilder);
IServiceCollection? services = null;
meterProviderBuilder.ConfigureServices(s => services = s);
if (services == null)
{
throw new NotSupportedException($"GetServices is not supported on the '{meterProviderBuilder.GetType()}' builder type.");
}
return services;
}
}

View File

@ -1,13 +1,11 @@
<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>Contains extensions to start OpenTelemetry in applications using Microsoft.Extensions.Hosting</Description>
<RootNamespace>OpenTelemetry</RootNamespace>
<MinVerTagPrefix>core-</MinVerTagPrefix>
<!-- this is temporary. will remove in future PR. -->
<Nullable>disable</Nullable>
<Nullable>enable</Nullable>
</PropertyGroup>
<!--Do not run ApiCompat for netstandard2.0 as this is newly added. Remove this property once we have released a stable version.-->

View File

@ -14,8 +14,6 @@
// limitations under the License.
// </copyright>
#nullable enable
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry.Internal;
using OpenTelemetry.Metrics;
@ -28,7 +26,7 @@ namespace OpenTelemetry;
/// Contains methods for configuring the OpenTelemetry SDK inside an <see
/// cref="IServiceCollection"/>.
/// </summary>
public class OpenTelemetryBuilder
public sealed class OpenTelemetryBuilder
{
internal OpenTelemetryBuilder(IServiceCollection services)
{
@ -74,18 +72,9 @@ public class OpenTelemetryBuilder
/// Adds metric services into the builder.
/// </summary>
/// <remarks>
/// Notes:
/// <list type="bullet">
/// <item>A <see cref="MeterProvider"/> will not be created automatically
/// using this method. To begin collecting metrics either use the
/// <c>OpenTelemetryBuilder.StartWithHost</c> extension in the
/// <c>OpenTelemetry.Extensions.Hosting</c> package or access the <see
/// cref="MeterProvider"/> through the application <see
/// cref="IServiceProvider"/>.</item>
/// <item>This is safe to be called multiple times and by library authors.
/// Note: This is safe to be called multiple times and by library authors.
/// Only a single <see cref="MeterProvider"/> will be created for a given
/// <see cref="IServiceCollection"/>.</item>
/// </list>
/// <see cref="IServiceCollection"/>.
/// </remarks>
/// <returns>The supplied <see cref="OpenTelemetryBuilder"/> for chaining
/// calls.</returns>
@ -115,18 +104,9 @@ public class OpenTelemetryBuilder
/// Adds tracing services into the builder.
/// </summary>
/// <remarks>
/// Notes:
/// <list type="bullet">
/// <item>A <see cref="TracerProvider"/> will not be created automatically
/// using this method. To begin collecting traces either use the
/// <c>OpenTelemetryBuilder.StartWithHost</c> extension in the
/// <c>OpenTelemetry.Extensions.Hosting</c> package or access the <see
/// cref="TracerProvider"/> through the application <see
/// cref="IServiceProvider"/>.</item>
/// <item>This is safe to be called multiple times and by library authors.
/// 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"/>.</item>
/// </list>
/// <see cref="IServiceCollection"/>.
/// </remarks>
/// <returns>The supplied <see cref="OpenTelemetryBuilder"/> for chaining
/// calls.</returns>

View File

@ -1,54 +0,0 @@
// <copyright file="OpenTelemetryBuilderHostingExtensions.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 Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using OpenTelemetry.Extensions.Hosting.Implementation;
using OpenTelemetry.Internal;
namespace OpenTelemetry;
/// <summary>
/// Contains hosting extension methods for the <see
/// cref="OpenTelemetryBuilder"/> class.
/// </summary>
public static class OpenTelemetryBuilderHostingExtensions
{
/// <summary>
/// Registers an <see cref="IHostedService"/> to automatically start all
/// configured OpenTelemetry services in the supplied <see
/// cref="IServiceCollection" />.
/// </summary>
/// <remarks>
/// Note: This is safe to be called multiple times. Only a single <see
/// cref="IHostedService"/> will be created for a given <see
/// cref="IServiceCollection"/>. This should generally be called by hosting
/// application code and NOT library authors.
/// </remarks>
/// <param name="builder"><see cref="OpenTelemetryBuilder"/>.</param>
/// <returns>The supplied <see cref="OpenTelemetryBuilder"/> for chaining
/// calls.</returns>
public static OpenTelemetryBuilder StartWithHost(this OpenTelemetryBuilder builder)
{
Guard.ThrowIfNull(builder);
builder.Services.TryAddEnumerable(
ServiceDescriptor.Singleton<IHostedService, TelemetryHostedService>());
return builder;
}
}

View File

@ -14,8 +14,11 @@
// limitations under the License.
// </copyright>
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using OpenTelemetry;
using OpenTelemetry.Extensions.Hosting.Implementation;
using OpenTelemetry.Internal;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
@ -27,6 +30,29 @@ namespace Microsoft.Extensions.DependencyInjection;
/// </summary>
public static class OpenTelemetryServicesExtensions
{
/// <summary>
/// Adds OpenTelemetry SDK services into the supplied <see
/// cref="IServiceCollection"/>.
/// </summary>
/// <remarks>
/// Note: This is safe to be called multiple times and by library authors.
/// Only a single <see cref="TracerProvider"/> and/or <see
/// cref="MeterProvider"/> will be created for a given <see
/// cref="IServiceCollection"/>.
/// </remarks>
/// <param name="services"><see cref="IServiceCollection"/>.</param>
/// <returns>The supplied <see cref="OpenTelemetryBuilder"/> for chaining
/// calls.</returns>
public static OpenTelemetryBuilder AddOpenTelemetry(this IServiceCollection services)
{
Guard.ThrowIfNull(services);
services.TryAddEnumerable(
ServiceDescriptor.Singleton<IHostedService, TelemetryHostedService>());
return new(services);
}
/// <summary>
/// Configure OpenTelemetry and register a <see cref="IHostedService"/>
/// to automatically start tracing services in the supplied <see
@ -51,7 +77,7 @@ public static class OpenTelemetryServicesExtensions
/// <param name="services"><see cref="IServiceCollection"/>.</param>
/// <returns>Supplied <see cref="IServiceCollection"/> for chaining
/// calls.</returns>
[Obsolete("Use the AddOpenTelemetry().WithTracing(configure).StartWithHost() pattern instead. This method will be removed in a future version.")]
[Obsolete("Use the AddOpenTelemetry().WithTracing(configure) pattern instead. This method will be removed in a future version.")]
public static IServiceCollection AddOpenTelemetryTracing(this IServiceCollection services)
=> AddOpenTelemetryTracing(services, b => { });
@ -68,10 +94,10 @@ public static class OpenTelemetryServicesExtensions
/// cref="TracerProviderBuilder"/>.</param>
/// <returns>Supplied <see cref="IServiceCollection"/> for chaining
/// calls.</returns>
[Obsolete("Use the AddOpenTelemetry().WithTracing(configure).StartWithHost() pattern instead. This method will be removed in a future version.")]
[Obsolete("Use the AddOpenTelemetry().WithTracing(configure) pattern instead. This method will be removed in a future version.")]
public static IServiceCollection AddOpenTelemetryTracing(this IServiceCollection services, Action<TracerProviderBuilder> configure)
{
services.AddOpenTelemetry().WithTracing(configure).StartWithHost();
services.AddOpenTelemetry().WithTracing(configure);
return services;
}
@ -100,7 +126,7 @@ public static class OpenTelemetryServicesExtensions
/// <param name="services"><see cref="IServiceCollection"/>.</param>
/// <returns>Supplied <see cref="IServiceCollection"/> for chaining
/// calls.</returns>
[Obsolete("Use the AddOpenTelemetry().WithMetrics(configure).StartWithHost() pattern instead. This method will be removed in a future version.")]
[Obsolete("Use the AddOpenTelemetry().WithMetrics(configure) pattern instead. This method will be removed in a future version.")]
public static IServiceCollection AddOpenTelemetryMetrics(this IServiceCollection services)
=> AddOpenTelemetryMetrics(services, b => { });
@ -117,10 +143,10 @@ public static class OpenTelemetryServicesExtensions
/// cref="TracerProviderBuilder"/>.</param>
/// <returns>Supplied <see cref="IServiceCollection"/> for chaining
/// calls.</returns>
[Obsolete("Use the AddOpenTelemetry().WithMetrics(configure).StartWithHost() pattern instead. This method will be removed in a future version.")]
[Obsolete("Use the AddOpenTelemetry().WithMetrics(configure) pattern instead. This method will be removed in a future version.")]
public static IServiceCollection AddOpenTelemetryMetrics(this IServiceCollection services, Action<MeterProviderBuilder> configure)
{
services.AddOpenTelemetry().WithMetrics(configure).StartWithHost();
services.AddOpenTelemetry().WithMetrics(configure);
return services;
}

View File

@ -23,12 +23,41 @@ and metrics (`MeterProvider`) in [ASP.NET
### Current OpenTelemetry SDK v1.4.0 and newer extensions
Targeting `OpenTelemetry.OpenTelemetryBuilder`:
Targeting `Microsoft.Extensions.DependencyInjection.IServiceCollection`:
* `StartWithHost`: Registers an
* `AddOpenTelemetry`: Registers an
[IHostedService](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.ihostedservice)
to automatically start tracing and/or metric services in the supplied
[IServiceCollection](https://learn.microsoft.com/dotnet/api/microsoft.extensions.dependencyinjection.iservicecollection).
[IServiceCollection](https://learn.microsoft.com/dotnet/api/microsoft.extensions.dependencyinjection.iservicecollection)
and then returns an `OpenTelemetryBuilder` class.
> **Note**
> `AddOpenTelemetry` should be called by application host code only. Library
authors see: [Registration extension method guidance for library
authors](../../docs/trace/extending-the-sdk/README.md#registration-extension-method-guidance-for-library-authors).
<!-- This comment is to make sure the two notes above and below are not merged
-->
> **Note**
> Multiple calls to `AddOpenTelemetry` will **NOT** result in multiple
providers. Only a single `TracerProvider` and/or `MeterProvider` will be
created in the target `IServiceCollection`. To establish multiple providers
use the `Sdk.CreateTracerProviderBuilder()` and/or
`Sdk.CreateMeterProviderBuilder()` methods. See [TracerProvider
configuration](../../docs/trace/customizing-the-sdk/README.md#tracerprovider-configuration)
and [Building a
MeterProvider](../../docs/metrics/customizing-the-sdk/README.md#building-a-meterprovider)
for more details.
`OpenTelemetryBuilder` methods:
* `ConfigureResource`: Registers a callback action to configure the
`ResourceBuilder` for tracing and metric providers.
* `WithTracing`: Enables tracing and optionally configures the
`TracerProvider`.
* `WithMetrics`: Enables metrics and optionally configures the
`MeterProvider`.
### Obsolete OpenTelemetry SDK pre-1.4.0 extensions
@ -73,9 +102,9 @@ using OpenTelemetry.Trace;
var appBuilder = WebApplication.CreateBuilder(args);
appBuilder.Services.AddOpenTelemetry()
.ConfigureResource(builder => builder.AddService(serviceName: "MyService"))
.WithTracing(builder => builder.AddConsoleExporter())
.WithMetrics(builder => builder.AddConsoleExporter())
.StartWithHost();
.WithMetrics(builder => builder.AddConsoleExporter());
var app = appBuilder.Build();

View File

@ -15,6 +15,7 @@
// </copyright>
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry.Internal;
namespace OpenTelemetry.Trace
{
@ -34,7 +35,12 @@ namespace OpenTelemetry.Trace
[Obsolete("Configure has been replaced by factory extensions. This method will be removed in a future version.")]
public static TracerProviderBuilder Configure(this TracerProviderBuilder tracerProviderBuilder, Action<IServiceProvider, TracerProviderBuilder> configure)
{
return (tracerProviderBuilder as IDeferredTracerProviderBuilder)?.Configure(configure);
if (tracerProviderBuilder is IDeferredTracerProviderBuilder deferredTracerProviderBuilder)
{
deferredTracerProviderBuilder.Configure(configure);
}
return tracerProviderBuilder;
}
/// <summary>
@ -47,8 +53,17 @@ namespace OpenTelemetry.Trace
[Obsolete("Call ConfigureServices instead this method will be removed in a future version.")]
public static IServiceCollection GetServices(this TracerProviderBuilder tracerProviderBuilder)
{
IServiceCollection services = null;
Guard.ThrowIfNull(tracerProviderBuilder);
IServiceCollection? services = null;
tracerProviderBuilder.ConfigureServices(s => services = s);
if (services == null)
{
throw new NotSupportedException($"GetServices is not supported on the '{tracerProviderBuilder.GetType()}' builder type.");
}
return services;
}
}

View File

@ -58,8 +58,7 @@ public void ConfigureServices(IServiceCollection services)
services.AddOpenTelemetry()
.WithTracing(builder => builder
.AddAspNetCoreInstrumentation()
.AddJaegerExporter())
.StartWithHost();
.AddJaegerExporter());
}
```
@ -88,8 +87,7 @@ services.Configure<AspNetCoreInstrumentationOptions>(options =>
services.AddOpenTelemetry()
.WithTracing(builder => builder
.AddAspNetCoreInstrumentation()
.AddJaegerExporter())
.StartWithHost();
.AddJaegerExporter());
```
### Filter
@ -112,8 +110,7 @@ services.AddOpenTelemetry()
// only collect telemetry about HTTP GET requests
return httpContext.Request.Method.Equals("GET");
})
.AddJaegerExporter())
.StartWithHost();
.AddJaegerExporter());
```
It is important to note that this `Filter` option is specific to this
@ -150,8 +147,7 @@ services.AddOpenTelemetry()
{
activity.SetTag("exceptionType", exception.GetType().ToString());
};
}))
.StartWithHost();
}));
```
[Processor](../../docs/trace/extending-the-sdk/README.md#processor),

View File

@ -120,8 +120,7 @@ services.AddOpenTelemetry()
{
activity.SetTag("responseVersion", httpResponseMessage.Version);
};
})
.StartWithHost();
});
```
[Processor](../../docs/trace/extending-the-sdk/README.md#processor),

View File

@ -12,16 +12,7 @@ OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void
OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool
OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void
OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMinMaxValues(out double min, out double max) -> bool
OpenTelemetry.OpenTelemetryBuilder
OpenTelemetry.OpenTelemetryBuilder.ConfigureResource(System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.Services.get -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
OpenTelemetry.OpenTelemetryBuilder.WithMetrics() -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithMetrics(System.Action<OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithTracing() -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithTracing(System.Action<OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryServiceCollectionExtensions
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Func<System.IServiceProvider!, OpenTelemetry.Metrics.MetricReader!>! implementationFactory) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.OpenTelemetryServiceCollectionExtensions.AddOpenTelemetry(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> OpenTelemetry.OpenTelemetryBuilder!
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader<T>(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder!
OpenTelemetry.Trace.SamplingResult.TraceStateString.get -> string?
OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, string! traceStateString) -> void

View File

@ -12,16 +12,7 @@ OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void
OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool
OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void
OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMinMaxValues(out double min, out double max) -> bool
OpenTelemetry.OpenTelemetryBuilder
OpenTelemetry.OpenTelemetryBuilder.ConfigureResource(System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.Services.get -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
OpenTelemetry.OpenTelemetryBuilder.WithMetrics() -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithMetrics(System.Action<OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithTracing() -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithTracing(System.Action<OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryServiceCollectionExtensions
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Func<System.IServiceProvider!, OpenTelemetry.Metrics.MetricReader!>! implementationFactory) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.OpenTelemetryServiceCollectionExtensions.AddOpenTelemetry(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> OpenTelemetry.OpenTelemetryBuilder!
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader<T>(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder!
OpenTelemetry.Trace.SamplingResult.TraceStateString.get -> string?
OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, string! traceStateString) -> void

View File

@ -12,16 +12,7 @@ OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void
OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool
OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void
OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMinMaxValues(out double min, out double max) -> bool
OpenTelemetry.OpenTelemetryBuilder
OpenTelemetry.OpenTelemetryBuilder.ConfigureResource(System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.Services.get -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
OpenTelemetry.OpenTelemetryBuilder.WithMetrics() -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithMetrics(System.Action<OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithTracing() -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithTracing(System.Action<OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryServiceCollectionExtensions
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Func<System.IServiceProvider!, OpenTelemetry.Metrics.MetricReader!>! implementationFactory) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.OpenTelemetryServiceCollectionExtensions.AddOpenTelemetry(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> OpenTelemetry.OpenTelemetryBuilder!
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader<T>(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder!
OpenTelemetry.Trace.SamplingResult.TraceStateString.get -> string?
OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, string! traceStateString) -> void

View File

@ -12,16 +12,7 @@ OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void
OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool
OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void
OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMinMaxValues(out double min, out double max) -> bool
OpenTelemetry.OpenTelemetryBuilder
OpenTelemetry.OpenTelemetryBuilder.ConfigureResource(System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.Services.get -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
OpenTelemetry.OpenTelemetryBuilder.WithMetrics() -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithMetrics(System.Action<OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithTracing() -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithTracing(System.Action<OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryServiceCollectionExtensions
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Func<System.IServiceProvider!, OpenTelemetry.Metrics.MetricReader!>! implementationFactory) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.OpenTelemetryServiceCollectionExtensions.AddOpenTelemetry(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> OpenTelemetry.OpenTelemetryBuilder!
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader<T>(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder!
OpenTelemetry.Trace.SamplingResult.TraceStateString.get -> string?
OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, string! traceStateString) -> void

View File

@ -21,5 +21,7 @@ using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus.AspNetCore" + AssemblyInfo.PublicKey)]
[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests" + AssemblyInfo.PublicKey)]
[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus.HttpListener.Tests" + AssemblyInfo.PublicKey)]
[assembly: InternalsVisibleTo("OpenTelemetry.Extensions.Hosting" + AssemblyInfo.PublicKey)]
[assembly: InternalsVisibleTo("OpenTelemetry.Extensions.Hosting.Tests" + AssemblyInfo.PublicKey)]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2" + AssemblyInfo.MoqPublicKey)]
[assembly: InternalsVisibleTo("Benchmarks" + AssemblyInfo.PublicKey)]

View File

@ -5,6 +5,11 @@
* Removed the dependency on System.Reflection.Emit.Lightweight
([#4140](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4140))
* Moved the `AddOpenTelemetry` extension into the
`OpenTelemetry.Extensions.Hosting` package so that the `StartWithHost` API
could be removed.
([#4174](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4174))
## 1.4.0-rc.3
Released 2023-Feb-01

View File

@ -1,55 +0,0 @@
// <copyright file="OpenTelemetryServiceCollectionExtensions.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>
#nullable enable
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
namespace OpenTelemetry;
/// <summary>
/// Contains <see cref="IServiceCollection"/> extension methods for registering OpenTelemetry SDK artifacts.
/// </summary>
public static class OpenTelemetryServiceCollectionExtensions
{
/// <summary>
/// Adds OpenTelemetry SDK services into the supplied <see
/// cref="IServiceCollection"/>.
/// </summary>
/// <remarks>
/// Notes:
/// <list type="bullet">
/// <item>A <see cref="TracerProvider"/> and/or <see cref="MeterProvider"/>
/// will not be created automatically using this method. To begin collecting
/// traces and/or metrics either use the
/// <c>OpenTelemetryBuilder.StartWithHost</c> extension in the
/// <c>OpenTelemetry.Extensions.Hosting</c> package or access the <see
/// cref="TracerProvider"/> and/or <see cref="MeterProvider"/> through the
/// application <see cref="IServiceProvider"/>.</item>
/// <item>This is safe to be called multiple times and by library authors.
/// Only a single <see cref="TracerProvider"/> and/or <see
/// cref="MeterProvider"/> will be created for a given <see
/// cref="IServiceCollection"/>.</item>
/// </list>
/// </remarks>
/// <param name="services"><see cref="IServiceCollection"/>.</param>
/// <returns>The supplied <see cref="OpenTelemetryBuilder"/> for chaining
/// calls.</returns>
public static OpenTelemetryBuilder AddOpenTelemetry(this IServiceCollection services)
=> new(services);
}

View File

@ -1,109 +0,0 @@
// <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 Microsoft.Extensions.Configuration;
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 AddOpenTelemetry_StartWithHost_CreationAndDisposal()
{
var callbackRun = false;
var builder = new HostBuilder().ConfigureServices(services =>
{
services.AddOpenTelemetry()
.WithMetrics(builder => builder
.AddInstrumentation(() =>
{
callbackRun = true;
return new object();
}))
.StartWithHost();
});
var host = builder.Build();
Assert.False(callbackRun);
await host.StartAsync().ConfigureAwait(false);
Assert.True(callbackRun);
await host.StopAsync().ConfigureAwait(false);
Assert.True(callbackRun);
host.Dispose();
Assert.True(callbackRun);
}
[Fact]
public async Task AddOpenTelemetry_StartWithHost_HostConfigurationHonoredTest()
{
bool configureBuilderCalled = false;
var builder = new HostBuilder()
.ConfigureAppConfiguration(builder =>
{
builder.AddInMemoryCollection(new Dictionary<string, string>
{
["TEST_KEY"] = "TEST_KEY_VALUE",
});
})
.ConfigureServices(services =>
{
services.AddOpenTelemetry()
.WithMetrics(builder =>
{
if (builder is IDeferredMeterProviderBuilder deferredMeterProviderBuilder)
{
deferredMeterProviderBuilder.Configure((sp, builder) =>
{
configureBuilderCalled = true;
var configuration = sp.GetRequiredService<IConfiguration>();
var testKeyValue = configuration.GetValue<string>("TEST_KEY", null);
Assert.Equal("TEST_KEY_VALUE", testKeyValue);
});
}
})
.StartWithHost();
});
var host = builder.Build();
Assert.False(configureBuilderCalled);
await host.StartAsync().ConfigureAwait(false);
Assert.True(configureBuilderCalled);
await host.StopAsync().ConfigureAwait(false);
host.Dispose();
}
}
}

View File

@ -1,109 +0,0 @@
// <copyright file="HostingTracerExtensionTests.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 Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using OpenTelemetry.Trace;
using Xunit;
namespace OpenTelemetry.Extensions.Hosting.Tests
{
public class HostingTracerExtensionTests
{
[Fact]
public async Task AddOpenTelemetry_StartWithHost_CreationAndDisposal()
{
var callbackRun = false;
var builder = new HostBuilder().ConfigureServices(services =>
{
services.AddOpenTelemetry()
.WithTracing(builder => builder
.AddInstrumentation(() =>
{
callbackRun = true;
return new object();
}))
.StartWithHost();
});
var host = builder.Build();
Assert.False(callbackRun);
await host.StartAsync().ConfigureAwait(false);
Assert.True(callbackRun);
await host.StopAsync().ConfigureAwait(false);
Assert.True(callbackRun);
host.Dispose();
Assert.True(callbackRun);
}
[Fact]
public async Task AddOpenTelemetry_StartWithHost_HostConfigurationHonoredTest()
{
bool configureBuilderCalled = false;
var builder = new HostBuilder()
.ConfigureAppConfiguration(builder =>
{
builder.AddInMemoryCollection(new Dictionary<string, string>
{
["TEST_KEY"] = "TEST_KEY_VALUE",
});
})
.ConfigureServices(services =>
{
services.AddOpenTelemetry()
.WithTracing(builder =>
{
if (builder is IDeferredTracerProviderBuilder deferredTracerProviderBuilder)
{
deferredTracerProviderBuilder.Configure((sp, builder) =>
{
configureBuilderCalled = true;
var configuration = sp.GetRequiredService<IConfiguration>();
var testKeyValue = configuration.GetValue<string>("TEST_KEY", null);
Assert.Equal("TEST_KEY_VALUE", testKeyValue);
});
}
})
.StartWithHost();
});
var host = builder.Build();
Assert.False(configureBuilderCalled);
await host.StartAsync().ConfigureAwait(false);
Assert.True(configureBuilderCalled);
await host.StopAsync().ConfigureAwait(false);
host.Dispose();
}
}
}

View File

@ -89,7 +89,7 @@ namespace OpenTelemetry.Extensions.Hosting.Tests
using var host = await new HostBuilder()
.ConfigureWebHost(webBuilder => webBuilder
.UseTestServer()
.ConfigureServices(services => services.AddOpenTelemetry().WithMetrics(configure).StartWithHost())
.ConfigureServices(services => services.AddOpenTelemetry().WithMetrics(configure))
.Configure(app => app.Run(httpContext =>
{
testAction.Invoke();

View File

@ -12,7 +12,9 @@
<ItemGroup>
<ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Extensions.Hosting\OpenTelemetry.Extensions.Hosting.csproj" />
<ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Exporter.InMemory\OpenTelemetry.Exporter.InMemory.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Include="$(RepoRoot)\test\OpenTelemetry.Tests\Shared\EventSourceTestHelper.cs" Link="Includes\EventSourceTestHelper.cs" />
<Compile Include="$(RepoRoot)\test\OpenTelemetry.Tests\Shared\TestEventListener.cs" Link="Includes\TestEventListener.cs" />
<Compile Include="$(RepoRoot)\test\OpenTelemetry.Tests\Shared\Utils.cs" Link="Includes\Utils.cs" />

View File

@ -0,0 +1,334 @@
// <copyright file="OpenTelemetryServicesExtensionsTests.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 Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
using Xunit;
namespace OpenTelemetry.Extensions.Hosting.Tests;
public class OpenTelemetryServicesExtensionsTests
{
[Fact]
public async Task AddOpenTelemetry_StartWithoutProvidersDoesNotThrow()
{
var builder = new HostBuilder().ConfigureServices(services =>
{
services.AddOpenTelemetry();
});
var host = builder.Build();
await host.StartAsync().ConfigureAwait(false);
await host.StopAsync().ConfigureAwait(false);
}
[Fact]
public async Task AddOpenTelemetry_StartWithExceptionsThrows()
{
bool expectedInnerExceptionThrown = false;
var builder = new HostBuilder().ConfigureServices(services =>
{
services.AddOpenTelemetry()
.WithTracing(builder =>
{
if (builder is IDeferredTracerProviderBuilder deferredTracerProviderBuilder)
{
deferredTracerProviderBuilder.Configure((sp, sdkBuilder) =>
{
try
{
// Note: This throws because services cannot be
// registered after IServiceProvider has been
// created.
sdkBuilder.SetSampler<MySampler>();
}
catch (NotSupportedException)
{
expectedInnerExceptionThrown = true;
throw;
}
});
}
});
});
var host = builder.Build();
await Assert.ThrowsAsync<NotSupportedException>(() => host.StartAsync()).ConfigureAwait(false);
await host.StopAsync().ConfigureAwait(false);
Assert.True(expectedInnerExceptionThrown);
}
[Fact]
public void AddOpenTelemetry_WithTracing_SingleProviderForServiceCollectionTest()
{
var services = new ServiceCollection();
services.AddOpenTelemetry().WithTracing(builder => { });
services.AddOpenTelemetry().WithTracing(builder => { });
using var serviceProvider = services.BuildServiceProvider();
Assert.NotNull(serviceProvider);
var tracerProviders = serviceProvider.GetServices<TracerProvider>();
Assert.Single(tracerProviders);
}
[Fact]
public void AddOpenTelemetry_WithTracing_DisposalTest()
{
var services = new ServiceCollection();
bool testRun = false;
services.AddOpenTelemetry().WithTracing(builder =>
{
testRun = true;
// Note: Build can't be called directly on builder tied to external services
Assert.Throws<NotSupportedException>(() => builder.Build());
});
Assert.True(testRun);
var serviceProvider = services.BuildServiceProvider();
var provider = serviceProvider.GetRequiredService<TracerProvider>() as TracerProviderSdk;
Assert.NotNull(provider);
Assert.Null(provider.OwnedServiceProvider);
Assert.NotNull(serviceProvider);
Assert.NotNull(provider);
Assert.False(provider.Disposed);
serviceProvider.Dispose();
Assert.True(provider.Disposed);
}
[Fact]
public async Task AddOpenTelemetry_WithTracing_HostConfigurationHonoredTest()
{
bool configureBuilderCalled = false;
var builder = new HostBuilder()
.ConfigureAppConfiguration(builder =>
{
builder.AddInMemoryCollection(new Dictionary<string, string>
{
["TEST_KEY"] = "TEST_KEY_VALUE",
});
})
.ConfigureServices(services =>
{
services.AddOpenTelemetry()
.WithTracing(builder =>
{
if (builder is IDeferredTracerProviderBuilder deferredTracerProviderBuilder)
{
deferredTracerProviderBuilder.Configure((sp, builder) =>
{
configureBuilderCalled = true;
var configuration = sp.GetRequiredService<IConfiguration>();
var testKeyValue = configuration.GetValue<string>("TEST_KEY", null);
Assert.Equal("TEST_KEY_VALUE", testKeyValue);
});
}
});
});
var host = builder.Build();
Assert.False(configureBuilderCalled);
await host.StartAsync().ConfigureAwait(false);
Assert.True(configureBuilderCalled);
await host.StopAsync().ConfigureAwait(false);
host.Dispose();
}
[Fact]
public void AddOpenTelemetry_WithTracing_NestedResolutionUsingConfigureTest()
{
bool innerTestExecuted = false;
var services = new ServiceCollection();
services.AddOpenTelemetry().WithTracing(builder =>
{
if (builder is IDeferredTracerProviderBuilder deferredTracerProviderBuilder)
{
deferredTracerProviderBuilder.Configure((sp, builder) =>
{
innerTestExecuted = true;
Assert.Throws<NotSupportedException>(() => sp.GetService<TracerProvider>());
});
}
});
using var serviceProvider = services.BuildServiceProvider();
var resolvedProvider = serviceProvider.GetRequiredService<TracerProvider>();
Assert.True(innerTestExecuted);
}
[Fact]
public void AddOpenTelemetry_WithMetrics_SingleProviderForServiceCollectionTest()
{
var services = new ServiceCollection();
services.AddOpenTelemetry().WithMetrics(builder => { });
services.AddOpenTelemetry().WithMetrics(builder => { });
using var serviceProvider = services.BuildServiceProvider();
Assert.NotNull(serviceProvider);
var meterProviders = serviceProvider.GetServices<MeterProvider>();
Assert.Single(meterProviders);
}
[Fact]
public void AddOpenTelemetry_WithMetrics_DisposalTest()
{
var services = new ServiceCollection();
bool testRun = false;
services.AddOpenTelemetry().WithMetrics(builder =>
{
testRun = true;
// Note: Build can't be called directly on builder tied to external services
Assert.Throws<NotSupportedException>(() => builder.Build());
});
Assert.True(testRun);
var serviceProvider = services.BuildServiceProvider();
var provider = serviceProvider.GetRequiredService<MeterProvider>() as MeterProviderSdk;
Assert.NotNull(provider);
Assert.Null(provider.OwnedServiceProvider);
Assert.NotNull(serviceProvider);
Assert.NotNull(provider);
Assert.False(provider.Disposed);
serviceProvider.Dispose();
Assert.True(provider.Disposed);
}
[Fact]
public async Task AddOpenTelemetry_WithMetrics_HostConfigurationHonoredTest()
{
bool configureBuilderCalled = false;
var builder = new HostBuilder()
.ConfigureAppConfiguration(builder =>
{
builder.AddInMemoryCollection(new Dictionary<string, string>
{
["TEST_KEY"] = "TEST_KEY_VALUE",
});
})
.ConfigureServices(services =>
{
services.AddOpenTelemetry()
.WithMetrics(builder =>
{
if (builder is IDeferredMeterProviderBuilder deferredMeterProviderBuilder)
{
deferredMeterProviderBuilder.Configure((sp, builder) =>
{
configureBuilderCalled = true;
var configuration = sp.GetRequiredService<IConfiguration>();
var testKeyValue = configuration.GetValue<string>("TEST_KEY", null);
Assert.Equal("TEST_KEY_VALUE", testKeyValue);
});
}
});
});
var host = builder.Build();
Assert.False(configureBuilderCalled);
await host.StartAsync().ConfigureAwait(false);
Assert.True(configureBuilderCalled);
await host.StopAsync().ConfigureAwait(false);
host.Dispose();
}
[Fact]
public void AddOpenTelemetry_WithMetrics_NestedResolutionUsingConfigureTest()
{
bool innerTestExecuted = false;
var services = new ServiceCollection();
services.AddOpenTelemetry().WithMetrics(builder =>
{
if (builder is IDeferredMeterProviderBuilder deferredMeterProviderBuilder)
{
deferredMeterProviderBuilder.Configure((sp, builder) =>
{
innerTestExecuted = true;
Assert.Throws<NotSupportedException>(() => sp.GetService<MeterProvider>());
});
}
});
using var serviceProvider = services.BuildServiceProvider();
var resolvedProvider = serviceProvider.GetRequiredService<MeterProvider>();
Assert.True(innerTestExecuted);
}
private sealed class MySampler : Sampler
{
public override SamplingResult ShouldSample(in SamplingParameters samplingParameters)
=> new(SamplingDecision.RecordAndSample);
}
}

View File

@ -1,87 +0,0 @@
// <copyright file="TelemetryHostedServiceTests.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 Microsoft.Extensions.Hosting;
using OpenTelemetry.Trace;
using Xunit;
namespace OpenTelemetry.Extensions.Hosting.Tests;
public class TelemetryHostedServiceTests
{
[Fact]
public async Task StartWithoutProvidersDoesNotThrow()
{
var builder = new HostBuilder().ConfigureServices(services =>
{
services.AddOpenTelemetry()
.StartWithHost();
});
var host = builder.Build();
await host.StartAsync().ConfigureAwait(false);
await host.StopAsync().ConfigureAwait(false);
}
[Fact]
public async Task StartWithExceptionsThrows()
{
bool expectedInnerExceptionThrown = false;
var builder = new HostBuilder().ConfigureServices(services =>
{
services.AddOpenTelemetry()
.WithTracing(builder =>
{
if (builder is IDeferredTracerProviderBuilder deferredTracerProviderBuilder)
{
deferredTracerProviderBuilder.Configure((sp, sdkBuilder) =>
{
try
{
// Note: This throws because services cannot be
// registered after IServiceProvider has been
// created.
sdkBuilder.SetSampler<MySampler>();
}
catch (NotSupportedException)
{
expectedInnerExceptionThrown = true;
throw;
}
});
}
})
.StartWithHost();
});
var host = builder.Build();
await Assert.ThrowsAsync<NotSupportedException>(() => host.StartAsync()).ConfigureAwait(false);
await host.StopAsync().ConfigureAwait(false);
Assert.True(expectedInnerExceptionThrown);
}
private sealed class MySampler : Sampler
{
public override SamplingResult ShouldSample(in SamplingParameters samplingParameters)
=> new SamplingResult(SamplingDecision.RecordAndSample);
}
}

View File

@ -653,8 +653,7 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Tests
.WithTracing(builder => builder
.AddAspNetCoreInstrumentation()
.AddSource(activitySourceName)
.AddInMemoryExporter(exportedItems))
.StartWithHost();
.AddInMemoryExporter(exportedItems));
});
builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders());
})
@ -692,8 +691,7 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Tests
services.AddOpenTelemetry()
.WithTracing(builder => builder
.AddAspNetCoreInstrumentation()
.AddInMemoryExporter(exportedItems))
.StartWithHost();
.AddInMemoryExporter(exportedItems));
// Register ActivitySource here so that it will be used
// by ASP.NET Core to create activities

View File

@ -46,8 +46,7 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Tests
{
services.AddOpenTelemetry()
.WithTracing(builder => builder
.AddAspNetCoreInstrumentation(name, configureAspNetCoreInstrumentationOptions: null))
.StartWithHost();
.AddAspNetCoreInstrumentation(name, configureAspNetCoreInstrumentationOptions: null));
services.Configure<AspNetCoreInstrumentationOptions>(name, options =>
{
@ -78,8 +77,7 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Tests
{
services.AddOpenTelemetry()
.WithMetrics(builder => builder
.AddAspNetCoreInstrumentation(name, configureAspNetCoreInstrumentationOptions: null))
.StartWithHost();
.AddAspNetCoreInstrumentation(name, configureAspNetCoreInstrumentationOptions: null));
services.Configure<AspNetCoreMetricsInstrumentationOptions>(name, options =>
{

View File

@ -63,8 +63,7 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Tests
services.AddOpenTelemetry()
.WithTracing(builder => builder
.AddAspNetCoreInstrumentation(options => options.RecordException = recordException)
.AddInMemoryExporter(exportedItems))
.StartWithHost();
.AddInMemoryExporter(exportedItems));
});
builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders());
})

View File

@ -56,81 +56,6 @@ namespace OpenTelemetry.Metrics.Tests
Assert.True(myInstrumentation.Disposed);
}
[Fact]
public void ServiceLifecycleAvailableToServicesBuilderTest()
{
var services = new ServiceCollection();
bool testRun = false;
ServiceProvider serviceProvider = null;
MeterProviderSdk provider = null;
services.AddOpenTelemetry().WithMetrics(builder =>
{
testRun = true;
RunBuilderServiceLifecycleTest(
builder,
() =>
{
// Note: Build can't be called directly on builder tied to external services
Assert.Throws<NotSupportedException>(() => builder.Build());
serviceProvider = services.BuildServiceProvider();
provider = serviceProvider.GetRequiredService<MeterProvider>() as MeterProviderSdk;
Assert.NotNull(provider);
Assert.Null(provider.OwnedServiceProvider);
return provider;
},
(provider) => { });
});
Assert.True(testRun);
Assert.NotNull(serviceProvider);
Assert.NotNull(provider);
Assert.False(provider.Disposed);
serviceProvider.Dispose();
Assert.True(provider.Disposed);
}
[Fact]
public void SingleProviderForServiceCollectionTest()
{
var services = new ServiceCollection();
services.AddOpenTelemetry().WithMetrics(builder =>
{
builder.AddInstrumentation<MyInstrumentation>(() => new());
});
services.AddOpenTelemetry().WithMetrics(builder =>
{
builder.AddInstrumentation<MyInstrumentation>(() => new());
});
using var serviceProvider = services.BuildServiceProvider();
Assert.NotNull(serviceProvider);
var meterProviders = serviceProvider.GetServices<MeterProvider>();
Assert.Single(meterProviders);
var provider = meterProviders.First() as MeterProviderSdk;
Assert.NotNull(provider);
Assert.Equal(2, provider.Instrumentations.Count);
}
[Fact]
public void AddReaderUsingDependencyInjectionTest()
{
@ -268,7 +193,7 @@ namespace OpenTelemetry.Metrics.Tests
{
if (callNestedConfigure)
{
services.AddOpenTelemetry().WithMetrics(builder => { });
services.ConfigureOpenTelemetryMeterProvider((sp, builder) => { });
}
})
.ConfigureBuilder((sp, builder) =>
@ -283,29 +208,6 @@ namespace OpenTelemetry.Metrics.Tests
Assert.Throws<NotSupportedException>(() => provider.GetServiceProvider()?.GetService<MeterProvider>());
}
[Fact]
public void MeterProviderNestedResolutionUsingConfigureTest()
{
bool innerTestExecuted = false;
var services = new ServiceCollection();
services.AddOpenTelemetry().WithMetrics(builder =>
{
builder.ConfigureBuilder((sp, builder) =>
{
innerTestExecuted = true;
Assert.Throws<NotSupportedException>(() => sp.GetService<MeterProvider>());
});
});
using var serviceProvider = services.BuildServiceProvider();
var resolvedProvider = serviceProvider.GetRequiredService<MeterProvider>();
Assert.True(innerTestExecuted);
}
[Fact]
public void MeterProviderAddReaderFactoryTest()
{

View File

@ -144,81 +144,6 @@ namespace OpenTelemetry.Trace.Tests
Assert.True(myInstrumentation.Disposed);
}
[Fact]
public void ServiceLifecycleAvailableToServicesBuilderTest()
{
var services = new ServiceCollection();
bool testRun = false;
ServiceProvider serviceProvider = null;
TracerProviderSdk provider = null;
services.AddOpenTelemetry().WithTracing(builder =>
{
testRun = true;
RunBuilderServiceLifecycleTest(
builder,
() =>
{
// Note: Build can't be called directly on builder tied to external services
Assert.Throws<NotSupportedException>(() => builder.Build());
serviceProvider = services.BuildServiceProvider();
provider = serviceProvider.GetRequiredService<TracerProvider>() as TracerProviderSdk;
Assert.NotNull(provider);
Assert.Null(provider.OwnedServiceProvider);
return provider;
},
(provider) => { });
});
Assert.True(testRun);
Assert.NotNull(serviceProvider);
Assert.NotNull(provider);
Assert.False(provider.Disposed);
serviceProvider.Dispose();
Assert.True(provider.Disposed);
}
[Fact]
public void SingleProviderForServiceCollectionTest()
{
var services = new ServiceCollection();
services.AddOpenTelemetry().WithTracing(builder =>
{
builder.AddInstrumentation<MyInstrumentation>(() => new());
});
services.AddOpenTelemetry().WithTracing(builder =>
{
builder.AddInstrumentation<MyInstrumentation>(() => new());
});
using var serviceProvider = services.BuildServiceProvider();
Assert.NotNull(serviceProvider);
var tracerProviders = serviceProvider.GetServices<TracerProvider>();
Assert.Single(tracerProviders);
var provider = tracerProviders.First() as TracerProviderSdk;
Assert.NotNull(provider);
Assert.Equal(2, provider.Instrumentations.Count);
}
[Fact]
public void AddProcessorUsingDependencyInjectionTest()
{
@ -356,7 +281,7 @@ namespace OpenTelemetry.Trace.Tests
{
if (callNestedConfigure)
{
services.AddOpenTelemetry().WithTracing(builder => { });
services.ConfigureOpenTelemetryTracerProvider((sp, builder) => { });
}
})
.ConfigureBuilder((sp, builder) =>
@ -371,29 +296,6 @@ namespace OpenTelemetry.Trace.Tests
Assert.Throws<NotSupportedException>(() => provider.GetServiceProvider()?.GetService<TracerProvider>());
}
[Fact]
public void TracerProviderNestedResolutionUsingConfigureTest()
{
bool innerTestExecuted = false;
var services = new ServiceCollection();
services.AddOpenTelemetry().WithTracing(builder =>
{
builder.ConfigureBuilder((sp, builder) =>
{
innerTestExecuted = true;
Assert.Throws<NotSupportedException>(() => sp.GetService<TracerProvider>());
});
});
using var serviceProvider = services.BuildServiceProvider();
var resolvedProvider = serviceProvider.GetRequiredService<TracerProvider>();
Assert.True(innerTestExecuted);
}
[Fact]
public void TracerProviderSetSamplerFactoryTest()
{