diff --git a/examples/AspNetCore/Startup.cs b/examples/AspNetCore/Startup.cs index 7a0e7876643..c2c4a4a817e 100644 --- a/examples/AspNetCore/Startup.cs +++ b/examples/AspNetCore/Startup.cs @@ -23,7 +23,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.OpenApi.Models; -using OpenTelemetry; +using OpenTelemetry.Exporter; using OpenTelemetry.Resources; using OpenTelemetry.Trace; @@ -63,20 +63,17 @@ public void ConfigureServices(IServiceCollection services) .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(this.Configuration.GetValue("Jaeger:ServiceName"))) .AddAspNetCoreInstrumentation() .AddHttpClientInstrumentation() - .AddJaegerExporter(jaegerOptions => - { - jaegerOptions.AgentHost = this.Configuration.GetValue("Jaeger:Host"); - jaegerOptions.AgentPort = this.Configuration.GetValue("Jaeger:Port"); - })); + .AddJaegerExporter()); + + services.Configure(this.Configuration.GetSection("Jaeger")); break; case "zipkin": services.AddOpenTelemetryTracing((builder) => builder .AddAspNetCoreInstrumentation() .AddHttpClientInstrumentation() - .AddZipkinExporter(zipkinOptions => - { - zipkinOptions.Endpoint = new Uri(this.Configuration.GetValue("Zipkin:Endpoint")); - })); + .AddZipkinExporter()); + + services.Configure(this.Configuration.GetSection("Zipkin")); break; case "otlp": // Adding the OtlpExporter creates a GrpcChannel. diff --git a/examples/AspNetCore/appsettings.json b/examples/AspNetCore/appsettings.json index fad736148cb..3279eec3559 100644 --- a/examples/AspNetCore/appsettings.json +++ b/examples/AspNetCore/appsettings.json @@ -10,8 +10,8 @@ "UseExporter": "console", "Jaeger": { "ServiceName": "jaeger-test", - "Host": "localhost", - "Port": 6831 + "AgentHost": "localhost", + "AgentPort": 6831 }, "Zipkin": { "ServiceName": "zipkin-test", diff --git a/src/OpenTelemetry.Api/.publicApi/net452/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Api/.publicApi/net452/PublicAPI.Unshipped.txt index e69de29bb2d..877fcaee8d0 100644 --- a/src/OpenTelemetry.Api/.publicApi/net452/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Api/.publicApi/net452/PublicAPI.Unshipped.txt @@ -0,0 +1 @@ +OpenTelemetry.Trace.TracerProviderBuilder.TracerProviderBuilder() -> void \ No newline at end of file diff --git a/src/OpenTelemetry.Api/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Api/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index e69de29bb2d..877fcaee8d0 100644 --- a/src/OpenTelemetry.Api/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Api/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -0,0 +1 @@ +OpenTelemetry.Trace.TracerProviderBuilder.TracerProviderBuilder() -> void \ No newline at end of file diff --git a/src/OpenTelemetry.Api/Trace/TracerProviderBuilder.cs b/src/OpenTelemetry.Api/Trace/TracerProviderBuilder.cs index 5dfcaa7ca39..dc8e0d57efb 100644 --- a/src/OpenTelemetry.Api/Trace/TracerProviderBuilder.cs +++ b/src/OpenTelemetry.Api/Trace/TracerProviderBuilder.cs @@ -22,12 +22,15 @@ namespace OpenTelemetry.Trace /// public abstract class TracerProviderBuilder { - internal TracerProviderBuilder() + /// + /// Initializes a new instance of the class. + /// + protected TracerProviderBuilder() { } /// - /// Adds an instrumentation to the provider. + /// Adds instrumentation to the provider. /// /// Type of instrumentation class. /// Function that builds instrumentation. diff --git a/src/OpenTelemetry.Exporter.Jaeger/JaegerExporterHelperExtensions.cs b/src/OpenTelemetry.Exporter.Jaeger/JaegerExporterHelperExtensions.cs index bcea406491d..827b35047b7 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/JaegerExporterHelperExtensions.cs +++ b/src/OpenTelemetry.Exporter.Jaeger/JaegerExporterHelperExtensions.cs @@ -38,11 +38,24 @@ public static TracerProviderBuilder AddJaegerExporter(this TracerProviderBuilder throw new ArgumentNullException(nameof(builder)); } - var exporterOptions = new JaegerExporterOptions(); - configure?.Invoke(exporterOptions); - var jaegerExporter = new JaegerExporter(exporterOptions); + if (builder is IDeferredTracerProviderBuilder deferredTracerProviderBuilder) + { + return deferredTracerProviderBuilder.Configure((sp, builder) => + { + AddJaegerExporter(builder, sp.GetOptions(), configure); + }); + } + + return AddJaegerExporter(builder, new JaegerExporterOptions(), configure); + } + + private static TracerProviderBuilder AddJaegerExporter(TracerProviderBuilder builder, JaegerExporterOptions options, Action configure = null) + { + configure?.Invoke(options); + + var jaegerExporter = new JaegerExporter(options); - if (exporterOptions.ExportProcessorType == ExportProcessorType.Simple) + if (options.ExportProcessorType == ExportProcessorType.Simple) { return builder.AddProcessor(new SimpleActivityExportProcessor(jaegerExporter)); } @@ -50,10 +63,10 @@ public static TracerProviderBuilder AddJaegerExporter(this TracerProviderBuilder { return builder.AddProcessor(new BatchActivityExportProcessor( jaegerExporter, - exporterOptions.BatchExportProcessorOptions.MaxQueueSize, - exporterOptions.BatchExportProcessorOptions.ScheduledDelayMilliseconds, - exporterOptions.BatchExportProcessorOptions.ExporterTimeoutMilliseconds, - exporterOptions.BatchExportProcessorOptions.MaxExportBatchSize)); + options.BatchExportProcessorOptions.MaxQueueSize, + options.BatchExportProcessorOptions.ScheduledDelayMilliseconds, + options.BatchExportProcessorOptions.ExporterTimeoutMilliseconds, + options.BatchExportProcessorOptions.MaxExportBatchSize)); } } } diff --git a/src/OpenTelemetry.Exporter.Jaeger/OpenTelemetry.Exporter.Jaeger.csproj b/src/OpenTelemetry.Exporter.Jaeger/OpenTelemetry.Exporter.Jaeger.csproj index 2227d11ce22..3d33742d97a 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/OpenTelemetry.Exporter.Jaeger.csproj +++ b/src/OpenTelemetry.Exporter.Jaeger/OpenTelemetry.Exporter.Jaeger.csproj @@ -22,6 +22,7 @@ + diff --git a/src/OpenTelemetry.Exporter.Zipkin/OpenTelemetry.Exporter.Zipkin.csproj b/src/OpenTelemetry.Exporter.Zipkin/OpenTelemetry.Exporter.Zipkin.csproj index 96f46d41de9..fcd5e005612 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/OpenTelemetry.Exporter.Zipkin.csproj +++ b/src/OpenTelemetry.Exporter.Zipkin/OpenTelemetry.Exporter.Zipkin.csproj @@ -17,6 +17,7 @@ + diff --git a/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterHelperExtensions.cs b/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterHelperExtensions.cs index 4f88aacfefe..78c8ca3adcf 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterHelperExtensions.cs +++ b/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterHelperExtensions.cs @@ -38,11 +38,24 @@ public static TracerProviderBuilder AddZipkinExporter(this TracerProviderBuilder throw new ArgumentNullException(nameof(builder)); } - var exporterOptions = new ZipkinExporterOptions(); - configure?.Invoke(exporterOptions); - var zipkinExporter = new ZipkinExporter(exporterOptions); + if (builder is IDeferredTracerProviderBuilder deferredTracerProviderBuilder) + { + return deferredTracerProviderBuilder.Configure((sp, builder) => + { + AddZipkinExporter(builder, sp.GetOptions(), configure); + }); + } + + return AddZipkinExporter(builder, new ZipkinExporterOptions(), configure); + } + + private static TracerProviderBuilder AddZipkinExporter(TracerProviderBuilder builder, ZipkinExporterOptions options, Action configure = null) + { + configure?.Invoke(options); + + var zipkinExporter = new ZipkinExporter(options); - if (exporterOptions.ExportProcessorType == ExportProcessorType.Simple) + if (options.ExportProcessorType == ExportProcessorType.Simple) { return builder.AddProcessor(new SimpleActivityExportProcessor(zipkinExporter)); } @@ -50,10 +63,10 @@ public static TracerProviderBuilder AddZipkinExporter(this TracerProviderBuilder { return builder.AddProcessor(new BatchActivityExportProcessor( zipkinExporter, - exporterOptions.BatchExportProcessorOptions.MaxQueueSize, - exporterOptions.BatchExportProcessorOptions.ScheduledDelayMilliseconds, - exporterOptions.BatchExportProcessorOptions.ExporterTimeoutMilliseconds, - exporterOptions.BatchExportProcessorOptions.MaxExportBatchSize)); + options.BatchExportProcessorOptions.MaxQueueSize, + options.BatchExportProcessorOptions.ScheduledDelayMilliseconds, + options.BatchExportProcessorOptions.ExporterTimeoutMilliseconds, + options.BatchExportProcessorOptions.MaxExportBatchSize)); } } } diff --git a/src/OpenTelemetry.Extensions.Hosting/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Extensions.Hosting/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index 1d0c89fedbc..364f10146db 100644 --- a/src/OpenTelemetry.Extensions.Hosting/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Extensions.Hosting/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -1,4 +1,9 @@ Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions +OpenTelemetry.Trace.TracerProviderBuilderExtensions 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 configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection -static Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions.AddOpenTelemetryTracing(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection +static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder +static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddProcessor(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 configure) -> OpenTelemetry.Trace.TracerProviderBuilder +static OpenTelemetry.Trace.TracerProviderBuilderExtensions.SetSampler(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder diff --git a/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md b/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md index 01891ca8a08..d9622840be6 100644 --- a/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md +++ b/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md @@ -2,6 +2,11 @@ ## Unreleased +* Added `AddInstrumentation`, `AddProcessor`, `SetSampler`, and + `Configure` extensions to support dependency injection through the + OpenTelemetry.Extensions.Hosting `TracerProviderBuilder`. + ([#1889](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1889)) + ## 1.0.0-rc3 Released 2021-Mar-19 diff --git a/src/OpenTelemetry.Extensions.Hosting/Implementation/TracerProviderBuilderHosting.cs b/src/OpenTelemetry.Extensions.Hosting/Implementation/TracerProviderBuilderHosting.cs new file mode 100644 index 00000000000..08d223b76c7 --- /dev/null +++ b/src/OpenTelemetry.Extensions.Hosting/Implementation/TracerProviderBuilderHosting.cs @@ -0,0 +1,126 @@ +// +// 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. +// + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using Microsoft.Extensions.DependencyInjection; + +namespace OpenTelemetry.Trace +{ + /// + /// A with support for deferred initialization using for dependency injection. + /// + internal class TracerProviderBuilderHosting : TracerProviderBuilderBase, IDeferredTracerProviderBuilder + { + private readonly List instrumentationFactories = new List(); + private readonly List processorTypes = new List(); + private readonly List> configurationActions = new List>(); + private Type samplerType; + + public TracerProviderBuilderHosting(IServiceCollection services) + { + this.Services = services ?? throw new ArgumentNullException(nameof(services)); + } + + public IServiceCollection Services { get; } + + public TracerProviderBuilder AddInstrumentation( + Func instrumentationFactory) + where TInstrumentation : class + { + if (instrumentationFactory == null) + { + throw new ArgumentNullException(nameof(instrumentationFactory)); + } + + this.instrumentationFactories.Add( + new InstrumentationFactory( + typeof(TInstrumentation).Name, + "semver:" + typeof(TInstrumentation).Assembly.GetName().Version, + typeof(TInstrumentation))); + + return this; + } + + public TracerProviderBuilder AddProcessor() + where T : BaseProcessor + { + this.processorTypes.Add(typeof(T)); + return this; + } + + public TracerProviderBuilder SetSampler() + where T : Sampler + { + this.samplerType = typeof(T); + return this; + } + + public TracerProviderBuilder Configure(Action configure) + { + if (configure == null) + { + throw new ArgumentNullException(nameof(configure)); + } + + this.configurationActions.Add(configure); + return this; + } + + public TracerProvider Build(IServiceProvider serviceProvider) + { + foreach (InstrumentationFactory instrumentationFactory in this.instrumentationFactories) + { + this.AddInstrumentation( + instrumentationFactory.Name, + instrumentationFactory.Version, + () => serviceProvider.GetRequiredService(instrumentationFactory.Type)); + } + + foreach (Type processorType in this.processorTypes) + { + this.AddProcessor((BaseProcessor)serviceProvider.GetRequiredService(processorType)); + } + + if (this.samplerType != null) + { + this.SetSampler((Sampler)serviceProvider.GetRequiredService(this.samplerType)); + } + + foreach (Action configureAction in this.configurationActions) + { + configureAction(serviceProvider, this); + } + + return this.Build(); + } + + private readonly struct InstrumentationFactory + { + public readonly string Name; + public readonly string Version; + public readonly Type Type; + + internal InstrumentationFactory(string name, string version, Type type) + { + this.Name = name; + this.Version = version; + this.Type = type; + } + } + } +} diff --git a/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryServicesExtensions.cs b/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryServicesExtensions.cs index d6414cd3d43..982bd013bfb 100644 --- a/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryServicesExtensions.cs +++ b/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryServicesExtensions.cs @@ -17,7 +17,6 @@ using System; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; -using OpenTelemetry; using OpenTelemetry.Extensions.Hosting.Implementation; using OpenTelemetry.Trace; @@ -35,8 +34,7 @@ public static class OpenTelemetryServicesExtensions /// The so that additional calls can be chained. public static IServiceCollection AddOpenTelemetryTracing(this IServiceCollection services) { - services.AddOpenTelemetryTracing(builder => { }); - return services; + return services.AddOpenTelemetryTracing(builder => { }); } /// @@ -52,63 +50,9 @@ public static IServiceCollection AddOpenTelemetryTracing(this IServiceCollection throw new ArgumentNullException(nameof(configure)); } - var builder = Sdk.CreateTracerProviderBuilder(); + var builder = new TracerProviderBuilderHosting(services); configure(builder); - services.AddOpenTelemetryTracing(() => builder.Build()); - return services; - } - - /// - /// Adds OpenTelemetry TracerProvider to the specified . - /// - /// The to add services to. - /// The action to configure TracerProviderBuilder. - /// The so that additional calls can be chained. - public static IServiceCollection AddOpenTelemetryTracing(this IServiceCollection services, Action configure) - { - if (configure is null) - { - throw new ArgumentNullException(nameof(configure)); - } - - var builder = Sdk.CreateTracerProviderBuilder(); - services.AddOpenTelemetryTracing((sp) => - { - configure(sp, builder); - return builder.Build(); - }); - return services; - } - - /// - /// Adds OpenTelemetry TracerProvider to the specified . - /// - /// The to add services to. - /// A delegate that provides the tracer provider to be registered. - /// The so that additional calls can be chained. - private static IServiceCollection AddOpenTelemetryTracing(this IServiceCollection services, Func createTracerProvider) - { - if (services is null) - { - throw new ArgumentNullException(nameof(services)); - } - - if (createTracerProvider is null) - { - throw new ArgumentNullException(nameof(createTracerProvider)); - } - - try - { - services.AddSingleton(s => createTracerProvider()); - AddOpenTelemetryTracingInternal(services); - } - catch (Exception ex) - { - HostingExtensionsEventSource.Log.FailedInitialize(ex); - } - - return services; + return services.AddOpenTelemetryTracing(sp => builder.Build(sp)); } /// @@ -131,8 +75,8 @@ private static IServiceCollection AddOpenTelemetryTracing(this IServiceCollectio try { - services.AddSingleton(s => createTracerProvider(s)); - AddOpenTelemetryTracingInternal(services); + services.TryAddEnumerable(ServiceDescriptor.Singleton()); + return services.AddSingleton(s => createTracerProvider(s)); } catch (Exception ex) { @@ -141,10 +85,5 @@ private static IServiceCollection AddOpenTelemetryTracing(this IServiceCollectio return services; } - - private static void AddOpenTelemetryTracingInternal(IServiceCollection services) - { - services.TryAddEnumerable(ServiceDescriptor.Singleton()); - } } } diff --git a/src/OpenTelemetry.Extensions.Hosting/Trace/TracerProviderBuilderExtensions.cs b/src/OpenTelemetry.Extensions.Hosting/Trace/TracerProviderBuilderExtensions.cs new file mode 100644 index 00000000000..16ecfbb43b9 --- /dev/null +++ b/src/OpenTelemetry.Extensions.Hosting/Trace/TracerProviderBuilderExtensions.cs @@ -0,0 +1,115 @@ +// +// 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. +// + +using System; +using System.Diagnostics; + +namespace OpenTelemetry.Trace +{ + /// + /// Contains extension methods for the class. + /// + public static class TracerProviderBuilderExtensions + { + /// + /// Adds instrumentation to the provider. + /// + /// Instrumentation type. + /// . + /// The supplied for chaining. + public static TracerProviderBuilder AddInstrumentation(this TracerProviderBuilder tracerProviderBuilder) + where T : class + { + if (tracerProviderBuilder is TracerProviderBuilderHosting tracerProviderBuilderHosting) + { + tracerProviderBuilderHosting.AddInstrumentation(); + } + + return tracerProviderBuilder; + } + + /// + /// Adds a processor to the provider. + /// + /// Processor type. + /// . + /// The supplied for chaining. + public static TracerProviderBuilder AddProcessor(this TracerProviderBuilder tracerProviderBuilder) + where T : BaseProcessor + { + if (tracerProviderBuilder is TracerProviderBuilderHosting tracerProviderBuilderHosting) + { + tracerProviderBuilderHosting.AddProcessor(); + } + + return tracerProviderBuilder; + } + + /// + /// Sets the sampler on the provider. + /// + /// Sampler type. + /// . + /// The supplied for chaining. + public static TracerProviderBuilder SetSampler(this TracerProviderBuilder tracerProviderBuilder) + where T : Sampler + { + if (tracerProviderBuilder is TracerProviderBuilderHosting tracerProviderBuilderHosting) + { + tracerProviderBuilderHosting.SetSampler(); + } + + return tracerProviderBuilder; + } + + /// + /// Register a callback action to configure the during initialization. + /// + /// . + /// Configuration callback. + /// The supplied for chaining. + public static TracerProviderBuilder Configure(this TracerProviderBuilder tracerProviderBuilder, Action configure) + { + if (tracerProviderBuilder is IDeferredTracerProviderBuilder deferredTracerProviderBuilder) + { + deferredTracerProviderBuilder.Configure(configure); + } + + return tracerProviderBuilder; + } + + /// + /// Run the configured actions to initialize the . + /// + /// . + /// . + /// . + public static TracerProvider Build(this TracerProviderBuilder tracerProviderBuilder, IServiceProvider serviceProvider) + { + if (tracerProviderBuilder is TracerProviderBuilderHosting tracerProviderBuilderHosting) + { + return tracerProviderBuilderHosting.Build(serviceProvider); + } + + if (tracerProviderBuilder is TracerProviderBuilderBase tracerProviderBuilderBase) + { + return tracerProviderBuilderBase.Build(); + } + + return null; + } + } +} diff --git a/src/OpenTelemetry/.publicApi/net452/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net452/PublicAPI.Unshipped.txt index 8de35a2051f..67d8b08882c 100644 --- a/src/OpenTelemetry/.publicApi/net452/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net452/PublicAPI.Unshipped.txt @@ -1,4 +1,12 @@ +OpenTelemetry.Trace.IDeferredTracerProviderBuilder +OpenTelemetry.Trace.IDeferredTracerProviderBuilder.Configure(System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder OpenTelemetry.Trace.ParentBasedSampler.ParentBasedSampler(OpenTelemetry.Trace.Sampler rootSampler, OpenTelemetry.Trace.Sampler remoteParentSampled = null, OpenTelemetry.Trace.Sampler remoteParentNotSampled = null, OpenTelemetry.Trace.Sampler localParentSampled = null, OpenTelemetry.Trace.Sampler localParentNotSampled = null) -> void +OpenTelemetry.Trace.TracerProviderBuilderBase +OpenTelemetry.Trace.TracerProviderBuilderBase.AddInstrumentation(string instrumentationName, string instrumentationVersion, System.Func instrumentationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder +OpenTelemetry.Trace.TracerProviderBuilderBase.Build() -> OpenTelemetry.Trace.TracerProvider +OpenTelemetry.Trace.TracerProviderBuilderBase.TracerProviderBuilderBase() -> void +override OpenTelemetry.Trace.TracerProviderBuilderBase.AddInstrumentation(System.Func instrumentationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder +override OpenTelemetry.Trace.TracerProviderBuilderBase.AddSource(params string[] names) -> OpenTelemetry.Trace.TracerProviderBuilder static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddLegacySource(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, string operationName) -> OpenTelemetry.Trace.TracerProviderBuilder static OpenTelemetry.Trace.TracerProviderBuilderExtensions.SetErrorStatusOnException(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, bool enabled = true) -> OpenTelemetry.Trace.TracerProviderBuilder static OpenTelemetry.Trace.TracerProviderExtensions.ForceFlush(this OpenTelemetry.Trace.TracerProvider provider, int timeoutMilliseconds = -1) -> bool diff --git a/src/OpenTelemetry/.publicApi/net46/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net46/PublicAPI.Unshipped.txt index 8de35a2051f..67d8b08882c 100644 --- a/src/OpenTelemetry/.publicApi/net46/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net46/PublicAPI.Unshipped.txt @@ -1,4 +1,12 @@ +OpenTelemetry.Trace.IDeferredTracerProviderBuilder +OpenTelemetry.Trace.IDeferredTracerProviderBuilder.Configure(System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder OpenTelemetry.Trace.ParentBasedSampler.ParentBasedSampler(OpenTelemetry.Trace.Sampler rootSampler, OpenTelemetry.Trace.Sampler remoteParentSampled = null, OpenTelemetry.Trace.Sampler remoteParentNotSampled = null, OpenTelemetry.Trace.Sampler localParentSampled = null, OpenTelemetry.Trace.Sampler localParentNotSampled = null) -> void +OpenTelemetry.Trace.TracerProviderBuilderBase +OpenTelemetry.Trace.TracerProviderBuilderBase.AddInstrumentation(string instrumentationName, string instrumentationVersion, System.Func instrumentationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder +OpenTelemetry.Trace.TracerProviderBuilderBase.Build() -> OpenTelemetry.Trace.TracerProvider +OpenTelemetry.Trace.TracerProviderBuilderBase.TracerProviderBuilderBase() -> void +override OpenTelemetry.Trace.TracerProviderBuilderBase.AddInstrumentation(System.Func instrumentationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder +override OpenTelemetry.Trace.TracerProviderBuilderBase.AddSource(params string[] names) -> OpenTelemetry.Trace.TracerProviderBuilder static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddLegacySource(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, string operationName) -> OpenTelemetry.Trace.TracerProviderBuilder static OpenTelemetry.Trace.TracerProviderBuilderExtensions.SetErrorStatusOnException(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, bool enabled = true) -> OpenTelemetry.Trace.TracerProviderBuilder static OpenTelemetry.Trace.TracerProviderExtensions.ForceFlush(this OpenTelemetry.Trace.TracerProvider provider, int timeoutMilliseconds = -1) -> bool diff --git a/src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt index 201f62ad314..aae8523dcf5 100644 --- a/src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt @@ -8,7 +8,16 @@ OpenTelemetry.Logs.OpenTelemetryLoggerOptions.IncludeScopes.set -> void OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ParseStateValues.get -> bool OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ParseStateValues.set -> void OpenTelemetry.Logs.OpenTelemetryLoggerOptions.SetResourceBuilder(OpenTelemetry.Resources.ResourceBuilder resourceBuilder) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions +OpenTelemetry.Trace.IDeferredTracerProviderBuilder +OpenTelemetry.Trace.IDeferredTracerProviderBuilder.Configure(System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder +OpenTelemetry.Trace.IDeferredTracerProviderBuilder.Services.get -> Microsoft.Extensions.DependencyInjection.IServiceCollection OpenTelemetry.Trace.ParentBasedSampler.ParentBasedSampler(OpenTelemetry.Trace.Sampler rootSampler, OpenTelemetry.Trace.Sampler remoteParentSampled = null, OpenTelemetry.Trace.Sampler remoteParentNotSampled = null, OpenTelemetry.Trace.Sampler localParentSampled = null, OpenTelemetry.Trace.Sampler localParentNotSampled = null) -> void +OpenTelemetry.Trace.TracerProviderBuilderBase +OpenTelemetry.Trace.TracerProviderBuilderBase.AddInstrumentation(string instrumentationName, string instrumentationVersion, System.Func instrumentationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder +OpenTelemetry.Trace.TracerProviderBuilderBase.Build() -> OpenTelemetry.Trace.TracerProvider +OpenTelemetry.Trace.TracerProviderBuilderBase.TracerProviderBuilderBase() -> void +override OpenTelemetry.Trace.TracerProviderBuilderBase.AddInstrumentation(System.Func instrumentationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder +override OpenTelemetry.Trace.TracerProviderBuilderBase.AddSource(params string[] names) -> OpenTelemetry.Trace.TracerProviderBuilder override OpenTelemetry.Logs.OpenTelemetryLoggerProvider.Dispose(bool disposing) -> void static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddLegacySource(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, string operationName) -> OpenTelemetry.Trace.TracerProviderBuilder static OpenTelemetry.Trace.TracerProviderBuilderExtensions.SetErrorStatusOnException(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, bool enabled = true) -> OpenTelemetry.Trace.TracerProviderBuilder diff --git a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index 201f62ad314..aae8523dcf5 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -8,7 +8,16 @@ OpenTelemetry.Logs.OpenTelemetryLoggerOptions.IncludeScopes.set -> void OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ParseStateValues.get -> bool OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ParseStateValues.set -> void OpenTelemetry.Logs.OpenTelemetryLoggerOptions.SetResourceBuilder(OpenTelemetry.Resources.ResourceBuilder resourceBuilder) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions +OpenTelemetry.Trace.IDeferredTracerProviderBuilder +OpenTelemetry.Trace.IDeferredTracerProviderBuilder.Configure(System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder +OpenTelemetry.Trace.IDeferredTracerProviderBuilder.Services.get -> Microsoft.Extensions.DependencyInjection.IServiceCollection OpenTelemetry.Trace.ParentBasedSampler.ParentBasedSampler(OpenTelemetry.Trace.Sampler rootSampler, OpenTelemetry.Trace.Sampler remoteParentSampled = null, OpenTelemetry.Trace.Sampler remoteParentNotSampled = null, OpenTelemetry.Trace.Sampler localParentSampled = null, OpenTelemetry.Trace.Sampler localParentNotSampled = null) -> void +OpenTelemetry.Trace.TracerProviderBuilderBase +OpenTelemetry.Trace.TracerProviderBuilderBase.AddInstrumentation(string instrumentationName, string instrumentationVersion, System.Func instrumentationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder +OpenTelemetry.Trace.TracerProviderBuilderBase.Build() -> OpenTelemetry.Trace.TracerProvider +OpenTelemetry.Trace.TracerProviderBuilderBase.TracerProviderBuilderBase() -> void +override OpenTelemetry.Trace.TracerProviderBuilderBase.AddInstrumentation(System.Func instrumentationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder +override OpenTelemetry.Trace.TracerProviderBuilderBase.AddSource(params string[] names) -> OpenTelemetry.Trace.TracerProviderBuilder override OpenTelemetry.Logs.OpenTelemetryLoggerProvider.Dispose(bool disposing) -> void static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddLegacySource(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, string operationName) -> OpenTelemetry.Trace.TracerProviderBuilder static OpenTelemetry.Trace.TracerProviderBuilderExtensions.SetErrorStatusOnException(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, bool enabled = true) -> OpenTelemetry.Trace.TracerProviderBuilder diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index 01d3a8dbddf..6f8472e8756 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -61,6 +61,10 @@ Released 2021-Mar-19 * Added `SetResourceBuilder` support to `OpenTelemetryLoggerOptions`. ([#1913](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1913)) +* Added `IDeferredTracerProviderBuilder` and `TracerProviderBuilderBase` to + support dependency injection through OpenTelemetry.Extensions.Hosting. + ([#1889](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1889)) + ## 1.0.1 Released 2021-Feb-10 diff --git a/src/OpenTelemetry/Internal/ServiceProviderExtensions.cs b/src/OpenTelemetry/Internal/ServiceProviderExtensions.cs new file mode 100644 index 00000000000..d6c53d4ae66 --- /dev/null +++ b/src/OpenTelemetry/Internal/ServiceProviderExtensions.cs @@ -0,0 +1,47 @@ +// +// 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. +// + +#if NET461 || NETSTANDARD2_0 +using Microsoft.Extensions.Options; +#endif + +namespace System +{ + /// + /// Extension methods for OpenTelemetry dependency injection support. + /// + internal static class ServiceProviderExtensions + { + /// + /// Get options from the supplied . + /// + /// Options type. + /// . + /// Options instance. + public static T GetOptions(this IServiceProvider serviceProvider) + where T : class, new() + { +#if NET461 || NETSTANDARD2_0 + IOptions options = (IOptions)serviceProvider.GetService(typeof(IOptions)); + + // Note: options could be null if user never invoked services.AddOptions(). + return options?.Value ?? new T(); +#else + return new T(); +#endif + } + } +} diff --git a/src/OpenTelemetry/Trace/IDeferredTracerProviderBuilder.cs b/src/OpenTelemetry/Trace/IDeferredTracerProviderBuilder.cs new file mode 100644 index 00000000000..633f0a09d3b --- /dev/null +++ b/src/OpenTelemetry/Trace/IDeferredTracerProviderBuilder.cs @@ -0,0 +1,42 @@ +// +// 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. +// + +using System; +#if NET461_OR_GREATER || NETSTANDARD2_0 +using Microsoft.Extensions.DependencyInjection; +#endif + +namespace OpenTelemetry.Trace +{ + /// + /// Describes a tracer provider builder that supports deferred + /// initialization using an to perform + /// dependency injection. + /// + public interface IDeferredTracerProviderBuilder + { +#if NET461_OR_GREATER || NETSTANDARD2_0 + IServiceCollection Services { get; } +#endif + + /// + /// Register a callback action to configure the during initialization. + /// + /// Configuration callback. + /// The supplied for chaining. + TracerProviderBuilder Configure(Action configure); + } +} diff --git a/src/OpenTelemetry/Trace/TracerProviderBuilderBase.cs b/src/OpenTelemetry/Trace/TracerProviderBuilderBase.cs new file mode 100644 index 00000000000..f0e6fc3b50f --- /dev/null +++ b/src/OpenTelemetry/Trace/TracerProviderBuilderBase.cs @@ -0,0 +1,230 @@ +// +// 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. +// + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using OpenTelemetry.Resources; + +namespace OpenTelemetry.Trace +{ + /// + /// Build TracerProvider with Resource, Sampler, Processors and Instrumentation. + /// + public abstract class TracerProviderBuilderBase : TracerProviderBuilder + { + private readonly List instrumentationFactories = new List(); + private readonly List> processors = new List>(); + private readonly List sources = new List(); + private readonly Dictionary legacyActivityOperationNames = new Dictionary(StringComparer.OrdinalIgnoreCase); + private ResourceBuilder resourceBuilder = ResourceBuilder.CreateDefault(); + private Sampler sampler = new ParentBasedSampler(new AlwaysOnSampler()); + + protected TracerProviderBuilderBase() + { + } + + /// + public override TracerProviderBuilder AddInstrumentation( + Func instrumentationFactory) + where TInstrumentation : class + { + if (instrumentationFactory == null) + { + throw new ArgumentNullException(nameof(instrumentationFactory)); + } + + this.instrumentationFactories.Add( + new InstrumentationFactory( + typeof(TInstrumentation).Name, + "semver:" + typeof(TInstrumentation).Assembly.GetName().Version, + instrumentationFactory)); + + return this; + } + + /// + public override TracerProviderBuilder AddSource(params string[] names) + { + if (names == null) + { + throw new ArgumentNullException(nameof(names)); + } + + foreach (var name in names) + { + if (string.IsNullOrWhiteSpace(name)) + { + throw new ArgumentException($"{nameof(names)} contains null or whitespace string."); + } + + // TODO: We need to fix the listening model. + // Today it ignores version. + this.sources.Add(name); + } + + return this; + } + + /// + /// Sets whether the status of + /// should be set to Status.Error when it ended abnormally due to an unhandled exception. + /// + /// Enabled or not. + /// Returns for chaining. + internal TracerProviderBuilder SetErrorStatusOnException(bool enabled) + { + ExceptionProcessor existingExceptionProcessor = null; + + if (this.processors.Count > 0) + { + existingExceptionProcessor = this.processors[0] as ExceptionProcessor; + } + + if (enabled) + { + if (existingExceptionProcessor == null) + { + try + { + this.processors.Insert(0, new ExceptionProcessor()); + } + catch (Exception ex) + { + throw new NotSupportedException("SetErrorStatusOnException is not supported on this platform.", ex); + } + } + } + else + { + if (existingExceptionProcessor != null) + { + this.processors.RemoveAt(0); + existingExceptionProcessor.Dispose(); + } + } + + return this; + } + + /// + /// Sets sampler. + /// + /// Sampler instance. + /// Returns for chaining. + internal TracerProviderBuilder SetSampler(Sampler sampler) + { + this.sampler = sampler ?? throw new ArgumentNullException(nameof(sampler)); + return this; + } + + /// + /// Sets the from which the Resource associated with + /// this provider is built from. Overwrites currently set ResourceBuilder. + /// + /// from which Resource will be built. + /// Returns for chaining. + internal TracerProviderBuilder SetResourceBuilder(ResourceBuilder resourceBuilder) + { + this.resourceBuilder = resourceBuilder ?? throw new ArgumentNullException(nameof(resourceBuilder)); + return this; + } + + /// + /// Adds processor to the provider. + /// + /// Activity processor to add. + /// Returns for chaining. + internal TracerProviderBuilder AddProcessor(BaseProcessor processor) + { + if (processor == null) + { + throw new ArgumentNullException(nameof(processor)); + } + + this.processors.Add(processor); + + return this; + } + + /// + /// Adds a listener for objects created with the given operation name to the . + /// + /// + /// This is provided to capture legacy objects created without using the API. + /// + /// Operation name of the objects to capture. + /// Returns for chaining. + internal TracerProviderBuilder AddLegacySource(string operationName) + { + if (string.IsNullOrWhiteSpace(operationName)) + { + throw new ArgumentException($"{nameof(operationName)} contains null or whitespace string."); + } + + this.legacyActivityOperationNames[operationName] = true; + + return this; + } + + /// + /// Adds instrumentation to the provider. + /// + /// Instrumentation name. + /// Instrumentation version. + /// Function that builds instrumentation. + /// Returns for chaining. + protected TracerProviderBuilder AddInstrumentation( + string instrumentationName, + string instrumentationVersion, + Func instrumentationFactory) + { + this.instrumentationFactories.Add( + new InstrumentationFactory(instrumentationName, instrumentationVersion, instrumentationFactory)); + + return this; + } + + /// + /// Run the configured actions to initialize the . + /// + /// . + protected TracerProvider Build() + { + return new TracerProviderSdk( + this.resourceBuilder.Build(), + this.sources, + this.instrumentationFactories, + this.sampler, + this.processors, + this.legacyActivityOperationNames); + } + + internal readonly struct InstrumentationFactory + { + public readonly string Name; + public readonly string Version; + public readonly Func Factory; + + internal InstrumentationFactory(string name, string version, Func factory) + { + this.Name = name; + this.Version = version; + this.Factory = factory; + } + } + } +} diff --git a/src/OpenTelemetry/Trace/TracerProviderBuilderExtensions.cs b/src/OpenTelemetry/Trace/TracerProviderBuilderExtensions.cs index 17b6ac026ce..9db834cff2e 100644 --- a/src/OpenTelemetry/Trace/TracerProviderBuilderExtensions.cs +++ b/src/OpenTelemetry/Trace/TracerProviderBuilderExtensions.cs @@ -20,6 +20,9 @@ namespace OpenTelemetry.Trace { + /// + /// Contains extension methods for the class. + /// public static class TracerProviderBuilderExtensions { /// @@ -31,9 +34,9 @@ public static class TracerProviderBuilderExtensions /// Returns for chaining. public static TracerProviderBuilder SetErrorStatusOnException(this TracerProviderBuilder tracerProviderBuilder, bool enabled = true) { - if (tracerProviderBuilder is TracerProviderBuilderSdk tracerProviderBuilderSdk) + if (tracerProviderBuilder is TracerProviderBuilderBase tracerProviderBuilderBase) { - tracerProviderBuilderSdk.SetErrorStatusOnException(enabled); + tracerProviderBuilderBase.SetErrorStatusOnException(enabled); } return tracerProviderBuilder; @@ -47,9 +50,9 @@ public static TracerProviderBuilder SetErrorStatusOnException(this TracerProvide /// Returns for chaining. public static TracerProviderBuilder SetSampler(this TracerProviderBuilder tracerProviderBuilder, Sampler sampler) { - if (tracerProviderBuilder is TracerProviderBuilderSdk tracerProviderBuilderSdk) + if (tracerProviderBuilder is TracerProviderBuilderBase tracerProviderBuilderBase) { - tracerProviderBuilderSdk.SetSampler(sampler); + tracerProviderBuilderBase.SetSampler(sampler); } return tracerProviderBuilder; @@ -64,9 +67,9 @@ public static TracerProviderBuilder SetSampler(this TracerProviderBuilder tracer /// Returns for chaining. public static TracerProviderBuilder SetResourceBuilder(this TracerProviderBuilder tracerProviderBuilder, ResourceBuilder resourceBuilder) { - if (tracerProviderBuilder is TracerProviderBuilderSdk tracerProviderBuilderSdk) + if (tracerProviderBuilder is TracerProviderBuilderBase tracerProviderBuilderBase) { - tracerProviderBuilderSdk.SetResourceBuilder(resourceBuilder); + tracerProviderBuilderBase.SetResourceBuilder(resourceBuilder); } return tracerProviderBuilder; @@ -80,9 +83,9 @@ public static TracerProviderBuilder SetResourceBuilder(this TracerProviderBuilde /// Returns for chaining. public static TracerProviderBuilder AddProcessor(this TracerProviderBuilder tracerProviderBuilder, BaseProcessor processor) { - if (tracerProviderBuilder is TracerProviderBuilderSdk tracerProviderBuilderSdk) + if (tracerProviderBuilder is TracerProviderBuilderBase tracerProviderBuilderBase) { - tracerProviderBuilderSdk.AddProcessor(processor); + tracerProviderBuilderBase.AddProcessor(processor); } return tracerProviderBuilder; @@ -99,19 +102,29 @@ public static TracerProviderBuilder AddProcessor(this TracerProviderBuilder trac /// Returns for chaining. public static TracerProviderBuilder AddLegacySource(this TracerProviderBuilder tracerProviderBuilder, string operationName) { - if (tracerProviderBuilder is TracerProviderBuilderSdk tracerProviderBuilderSdk) + if (tracerProviderBuilder is TracerProviderBuilderBase tracerProviderBuilderBase) { - tracerProviderBuilderSdk.AddLegacySource(operationName); + tracerProviderBuilderBase.AddLegacySource(operationName); } return tracerProviderBuilder; } + /// + /// Run the given actions to initialize the . + /// + /// . + /// . public static TracerProvider Build(this TracerProviderBuilder tracerProviderBuilder) { + if (tracerProviderBuilder is IDeferredTracerProviderBuilder) + { + throw new NotSupportedException("DeferredTracerBuilder requires a ServiceProvider to build."); + } + if (tracerProviderBuilder is TracerProviderBuilderSdk tracerProviderBuilderSdk) { - return tracerProviderBuilderSdk.Build(); + return tracerProviderBuilderSdk.BuildSdk(); } return null; diff --git a/src/OpenTelemetry/Trace/TracerProviderBuilderSdk.cs b/src/OpenTelemetry/Trace/TracerProviderBuilderSdk.cs index 3a9c6de9827..18dae6e2ffe 100644 --- a/src/OpenTelemetry/Trace/TracerProviderBuilderSdk.cs +++ b/src/OpenTelemetry/Trace/TracerProviderBuilderSdk.cs @@ -14,204 +14,10 @@ // limitations under the License. // -using System; -using System.Collections.Generic; -using System.Diagnostics; -using OpenTelemetry.Resources; - namespace OpenTelemetry.Trace { - /// - /// Build TracerProvider with Resource, Sampler, Processors and Instrumentation. - /// - internal class TracerProviderBuilderSdk : TracerProviderBuilder + internal class TracerProviderBuilderSdk : TracerProviderBuilderBase { - private readonly List instrumentationFactories = new List(); - private readonly List> processors = new List>(); - private readonly List sources = new List(); - private readonly Dictionary legacyActivityOperationNames = new Dictionary(StringComparer.OrdinalIgnoreCase); - private ResourceBuilder resourceBuilder = ResourceBuilder.CreateDefault(); - private Sampler sampler = new ParentBasedSampler(new AlwaysOnSampler()); - - internal TracerProviderBuilderSdk() - { - } - - /// - /// Adds an instrumentation to the provider. - /// - /// Type of instrumentation class. - /// Function that builds instrumentation. - /// Returns for chaining. - public override TracerProviderBuilder AddInstrumentation( - Func instrumentationFactory) - where TInstrumentation : class - { - if (instrumentationFactory == null) - { - throw new ArgumentNullException(nameof(instrumentationFactory)); - } - - this.instrumentationFactories.Add( - new InstrumentationFactory( - typeof(TInstrumentation).Name, - "semver:" + typeof(TInstrumentation).Assembly.GetName().Version, - instrumentationFactory)); - - return this; - } - - /// - /// Adds given activitysource names to the list of subscribed sources. - /// - /// Activity source names. - /// Returns for chaining. - public override TracerProviderBuilder AddSource(params string[] names) - { - if (names == null) - { - throw new ArgumentNullException(nameof(names)); - } - - foreach (var name in names) - { - if (string.IsNullOrWhiteSpace(name)) - { - throw new ArgumentException($"{nameof(names)} contains null or whitespace string."); - } - - // TODO: We need to fix the listening model. - // Today it ignores version. - this.sources.Add(name); - } - - return this; - } - - /// - /// Sets whether the status of - /// should be set to Status.Error when it ended abnormally due to an unhandled exception. - /// - /// Enabled or not. - /// Returns for chaining. - internal TracerProviderBuilder SetErrorStatusOnException(bool enabled) - { - ExceptionProcessor existingExceptionProcessor = null; - - if (this.processors.Count > 0) - { - existingExceptionProcessor = this.processors[0] as ExceptionProcessor; - } - - if (enabled) - { - if (existingExceptionProcessor == null) - { - try - { - this.processors.Insert(0, new ExceptionProcessor()); - } - catch (Exception ex) - { - throw new NotSupportedException("SetErrorStatusOnException is not supported on this platform.", ex); - } - } - } - else - { - if (existingExceptionProcessor != null) - { - this.processors.RemoveAt(0); - existingExceptionProcessor.Dispose(); - } - } - - return this; - } - - /// - /// Sets sampler. - /// - /// Sampler instance. - /// Returns for chaining. - internal TracerProviderBuilder SetSampler(Sampler sampler) - { - this.sampler = sampler ?? throw new ArgumentNullException(nameof(sampler)); - return this; - } - - /// - /// Sets the from which the Resource associated with - /// this provider is built from. Overwrites currently set ResourceBuilder. - /// - /// from which Resource will be built. - /// Returns for chaining. - internal TracerProviderBuilder SetResourceBuilder(ResourceBuilder resourceBuilder) - { - this.resourceBuilder = resourceBuilder ?? throw new ArgumentNullException(nameof(resourceBuilder)); - return this; - } - - /// - /// Adds processor to the provider. - /// - /// Activity processor to add. - /// Returns for chaining. - internal TracerProviderBuilder AddProcessor(BaseProcessor processor) - { - if (processor == null) - { - throw new ArgumentNullException(nameof(processor)); - } - - this.processors.Add(processor); - - return this; - } - - /// - /// Adds a listener for objects created with the given operation name to the . - /// - /// - /// This is provided to capture legacy objects created without using the API. - /// - /// Operation name of the objects to capture. - /// Returns for chaining. - internal TracerProviderBuilder AddLegacySource(string operationName) - { - if (string.IsNullOrWhiteSpace(operationName)) - { - throw new ArgumentException($"{nameof(operationName)} contains null or whitespace string."); - } - - this.legacyActivityOperationNames[operationName] = true; - - return this; - } - - internal TracerProvider Build() - { - return new TracerProviderSdk( - this.resourceBuilder.Build(), - this.sources, - this.instrumentationFactories, - this.sampler, - this.processors, - this.legacyActivityOperationNames); - } - - internal readonly struct InstrumentationFactory - { - public readonly string Name; - public readonly string Version; - public readonly Func Factory; - - internal InstrumentationFactory(string name, string version, Func factory) - { - this.Name = name; - this.Version = version; - this.Factory = factory; - } - } + internal TracerProvider BuildSdk() => this.Build(); } } diff --git a/src/OpenTelemetry/Trace/TracerProviderSdk.cs b/src/OpenTelemetry/Trace/TracerProviderSdk.cs index 07177f30b3a..82f007d3771 100644 --- a/src/OpenTelemetry/Trace/TracerProviderSdk.cs +++ b/src/OpenTelemetry/Trace/TracerProviderSdk.cs @@ -40,7 +40,7 @@ internal class TracerProviderSdk : TracerProvider internal TracerProviderSdk( Resource resource, IEnumerable sources, - IEnumerable instrumentationFactories, + IEnumerable instrumentationFactories, Sampler sampler, List> processors, Dictionary legacyActivityOperationNames) diff --git a/test/OpenTelemetry.Extensions.Hosting.Tests/HostingExtensionsTests.cs b/test/OpenTelemetry.Extensions.Hosting.Tests/HostingExtensionsTests.cs index 9a8ff39917e..34952c6086d 100644 --- a/test/OpenTelemetry.Extensions.Hosting.Tests/HostingExtensionsTests.cs +++ b/test/OpenTelemetry.Extensions.Hosting.Tests/HostingExtensionsTests.cs @@ -87,9 +87,10 @@ public void AddOpenTelemetryTracerProvider_ServiceProviderArgument_ServicesRegis var services = new ServiceCollection(); services.AddSingleton(testInstrumentation); - services.AddOpenTelemetryTracing((provider, builder) => + services.AddOpenTelemetryTracing(builder => { - builder.AddInstrumentation(() => provider.GetRequiredService()); + builder.Configure( + (sp, b) => b.AddInstrumentation(() => sp.GetRequiredService())); }); var serviceProvider = services.BuildServiceProvider(); @@ -108,12 +109,13 @@ public void AddOpenTelemetryTracerProvider_ServiceProviderArgument_ServicesRegis public void AddOpenTelemetryTracerProvider_BadArgs_NullServiceCollection() { ServiceCollection services = null; - Assert.Throws(() => services.AddOpenTelemetryTracing()); + Assert.Throws(() => services.AddOpenTelemetryTracing(null)); Assert.Throws(() => - services.AddOpenTelemetryTracing((provider, builder) => - { - builder.AddInstrumentation(() => provider.GetRequiredService()); - })); + services.AddOpenTelemetryTracing(builder => + { + builder.Configure( + (sp, b) => b.AddInstrumentation(() => sp.GetRequiredService())); + })); } internal class TestInstrumentation : IDisposable