[hosting] Register OpenTelemetry at the beginning of IServiceCollection (#4883)
Co-authored-by: Mikel Blanchard <mblanchard@macrosssoftware.com>
This commit is contained in:
parent
f63e6e5362
commit
3e885c77f2
|
|
@ -2,6 +2,14 @@
|
|||
|
||||
## Unreleased
|
||||
|
||||
* Changed the behavior of the `OpenTelemetryBuilder.AddOpenTelemetry` extension
|
||||
to INSERT OpenTelemetry services at the beginning of the `IServiceCollection`
|
||||
in an attempt to provide a better experience for end users capturing telemetry
|
||||
in hosted services. Note that this does not guarantee that OpenTelemetry
|
||||
services will be initialized while other hosted services start, so it is
|
||||
possible to miss telemetry until OpenTelemetry services are fully initialized.
|
||||
([#4883](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4883))
|
||||
|
||||
## 1.6.0
|
||||
|
||||
Released 2023-Sep-05
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
// limitations under the License.
|
||||
// </copyright>
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using OpenTelemetry;
|
||||
using OpenTelemetry.Extensions.Hosting.Implementation;
|
||||
|
|
@ -35,10 +34,17 @@ public static class OpenTelemetryServicesExtensions
|
|||
/// cref="IServiceCollection"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Note: This is safe to be called multiple times and by library authors.
|
||||
/// Notes:
|
||||
/// <list type="bullet">
|
||||
/// <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"/>.
|
||||
/// cref="IServiceCollection"/>.</item>
|
||||
/// <item>OpenTelemetry SDK services are inserted at the beginning of the
|
||||
/// <see cref="IServiceCollection"/> and started with the host. For details
|
||||
/// about the ordering of events and capturing telemetry in
|
||||
/// <see cref="IHostedService" />s see: <see href="https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry.Extensions.Hosting/README.md#hosted-service-ordering-and-telemetry-capture" />.</item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
/// <param name="services"><see cref="IServiceCollection"/>.</param>
|
||||
/// <returns>The supplied <see cref="OpenTelemetryBuilder"/> for chaining
|
||||
|
|
@ -47,8 +53,10 @@ public static class OpenTelemetryServicesExtensions
|
|||
{
|
||||
Guard.ThrowIfNull(services);
|
||||
|
||||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Singleton<IHostedService, TelemetryHostedService>());
|
||||
if (!services.Any((ServiceDescriptor d) => d.ServiceType == typeof(IHostedService) && d.ImplementationType == typeof(TelemetryHostedService)))
|
||||
{
|
||||
services.Insert(0, ServiceDescriptor.Singleton<IHostedService, TelemetryHostedService>());
|
||||
}
|
||||
|
||||
return new(services);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,6 +141,10 @@ and
|
|||
[new](https://github.com/open-telemetry/opentelemetry-dotnet/tree/main/examples/AspNetCore)
|
||||
versions of the example application to assist you in your migration.
|
||||
|
||||
## Hosted Service Ordering and Telemetry Capture
|
||||
|
||||
TBD
|
||||
|
||||
## References
|
||||
|
||||
* [OpenTelemetry Project](https://opentelemetry.io/)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
// limitations under the License.
|
||||
// </copyright>
|
||||
|
||||
using System.Diagnostics;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
|
@ -450,9 +451,48 @@ public class OpenTelemetryServicesExtensionsTests
|
|||
Assert.True(innerTestExecuted);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddOpenTelemetry_HostedServiceOrder_DoesNotMatter()
|
||||
{
|
||||
var exportedItems = new List<Activity>();
|
||||
|
||||
var builder = new HostBuilder().ConfigureServices(services =>
|
||||
{
|
||||
services.AddHostedService<TestHostedService>();
|
||||
services.AddOpenTelemetry()
|
||||
.WithTracing(builder =>
|
||||
{
|
||||
builder.SetSampler(new AlwaysOnSampler());
|
||||
builder.AddSource(nameof(TestHostedService));
|
||||
builder.AddInMemoryExporter(exportedItems);
|
||||
});
|
||||
});
|
||||
|
||||
var host = builder.Build();
|
||||
await host.StartAsync().ConfigureAwait(false);
|
||||
await host.StopAsync().ConfigureAwait(false);
|
||||
host.Dispose();
|
||||
|
||||
Assert.Single(exportedItems);
|
||||
}
|
||||
|
||||
private sealed class MySampler : Sampler
|
||||
{
|
||||
public override SamplingResult ShouldSample(in SamplingParameters samplingParameters)
|
||||
=> new(SamplingDecision.RecordAndSample);
|
||||
}
|
||||
|
||||
private sealed class TestHostedService : BackgroundService
|
||||
{
|
||||
private readonly ActivitySource activitySource = new ActivitySource(nameof(TestHostedService));
|
||||
|
||||
protected override Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
using (var activity = this.activitySource.StartActivity("test"))
|
||||
{
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue