diff --git a/OpenTelemetry.sln b/OpenTelemetry.sln index 7b231532653..b0929341fda 100644 --- a/OpenTelemetry.sln +++ b/OpenTelemetry.sln @@ -238,9 +238,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "redaction", "docs\logs\reda EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.OpenTelemetryProtocol.Grpc", "src\OpenTelemetry.Exporter.OpenTelemetryProtocol.Grpc\OpenTelemetry.Exporter.OpenTelemetryProtocol.Grpc.csproj", "{7263001A-49F8-4C3C-AAA8-998F12DAAF64}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenTelemetry.Exporter.Console.Tests", "test\OpenTelemetry.Exporter.Console.Tests\OpenTelemetry.Exporter.Console.Tests.csproj", "{011E70E1-152A-47BB-AF83-12DD12B125ED}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.Console.Tests", "test\OpenTelemetry.Exporter.Console.Tests\OpenTelemetry.Exporter.Console.Tests.csproj", "{011E70E1-152A-47BB-AF83-12DD12B125ED}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "getting-started-jaeger", "docs\trace\getting-started-jaeger\getting-started-jaeger.csproj", "{329AD438-6D15-4432-99BE-B0E85F00B3CB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Extensions.DependencyInjection", "src\OpenTelemetry.Extensions.DependencyInjection\OpenTelemetry.Extensions.DependencyInjection.csproj", "{171A87CB-393C-4296-913F-E704CD8CEAE9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Extensions.DependencyInjection.Tests", "test\OpenTelemetry.Extensions.DependencyInjection.Tests\OpenTelemetry.Extensions.DependencyInjection.Tests.csproj", "{662476AA-5875-4E74-B992-DDF309168EFB}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -500,10 +502,14 @@ Global {011E70E1-152A-47BB-AF83-12DD12B125ED}.Debug|Any CPU.Build.0 = Debug|Any CPU {011E70E1-152A-47BB-AF83-12DD12B125ED}.Release|Any CPU.ActiveCfg = Release|Any CPU {011E70E1-152A-47BB-AF83-12DD12B125ED}.Release|Any CPU.Build.0 = Release|Any CPU - {329AD438-6D15-4432-99BE-B0E85F00B3CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {329AD438-6D15-4432-99BE-B0E85F00B3CB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {329AD438-6D15-4432-99BE-B0E85F00B3CB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {329AD438-6D15-4432-99BE-B0E85F00B3CB}.Release|Any CPU.Build.0 = Release|Any CPU + {171A87CB-393C-4296-913F-E704CD8CEAE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {171A87CB-393C-4296-913F-E704CD8CEAE9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {171A87CB-393C-4296-913F-E704CD8CEAE9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {171A87CB-393C-4296-913F-E704CD8CEAE9}.Release|Any CPU.Build.0 = Release|Any CPU + {662476AA-5875-4E74-B992-DDF309168EFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {662476AA-5875-4E74-B992-DDF309168EFB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {662476AA-5875-4E74-B992-DDF309168EFB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {662476AA-5875-4E74-B992-DDF309168EFB}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -541,7 +547,6 @@ Global {9A07D215-90AC-4BAF-BCDB-73D74FD3A5C5} = {3862190B-E2C5-418E-AFDC-DB281FB5C705} {5FDAF679-DE5A-4C73-A49B-8ABCF2399229} = {77C7929A-2EED-4AA6-8705-B5C443C8AA0F} {A2DF46DE-50D7-4887-8C9D-4BD79CA19FAA} = {3862190B-E2C5-418E-AFDC-DB281FB5C705} - {329AD438-6D15-4432-99BE-B0E85F00B3CB} = {5B7FB835-3FFF-4BC2-99C5-A5B5FAE3C818} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {55639B5C-0770-4A22-AB56-859604650521} diff --git a/build/Common.props b/build/Common.props index e01f6bc1dbe..c3df2c082d3 100644 --- a/build/Common.props +++ b/build/Common.props @@ -35,6 +35,7 @@ [3.3.3] [17.3.0] [3.1.0,) + [3.1.0,) [2.1.0,) [3.1.0,) [3.1.0,) diff --git a/docs/trace/customizing-the-sdk/README.md b/docs/trace/customizing-the-sdk/README.md index ead1fd85986..31857eb5f67 100644 --- a/docs/trace/customizing-the-sdk/README.md +++ b/docs/trace/customizing-the-sdk/README.md @@ -411,21 +411,24 @@ var appBuilder = WebApplication.CreateBuilder(args); appBuilder.Services.AddSingleton(); -appBuilder.Services.AddOpenTelemetryTracing(builder => builder - .AddProcessor(); +appBuilder.Services.AddOpenTelemetry() + .WithTracing(builder => builder + .AddProcessor()) + .StartWithHost(); ``` -When using the `AddOpenTelemetryTracing` method the `TracerProvider` does not -own its `IServiceCollection` and instead registers into an existing collection -(typically the collection used is the one managed by the application host). The -`TracerProviderBuilder` will be able to access all services registered into that -collection. For lifecycle management, an [IHostedService +When using the `AddOpenTelemetry` & `WithTracing` extension methods the +`TracerProvider` does not own its `IServiceCollection` and instead registers +into an existing collection (typically the collection used is the one managed by +the application host). The `TracerProviderBuilder` will be able to access all +services registered into that collection. For lifecycle management, the +`StartWithHost` registers an [IHostedService ](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.ihostedservice) -is used to automatically start the `TracerProvider` when the host starts and the -host will automatically shutdown and dispose the `TracerProvider` when it is -shutdown. +which is used to automatically start the `TracerProvider` when the host starts +and the host will automatically shutdown and dispose the `TracerProvider` when +it is shutdown. -**Note:** Multiple calls to `AddOpenTelemetryTracing` will configure the same +**Note:** Multiple calls to `WithTracing` will configure the same `TracerProvider`. Only a single `TraceProvider` may exist in an `IServiceCollection` \ `IServiceProvider`. @@ -451,15 +454,17 @@ shutdown. ```csharp var appBuilder = WebApplication.CreateBuilder(args); - appBuilder.Services.AddOpenTelemetryTracing(builder => builder - .ConfigureBuilder((sp, builder) => - { - builder.AddProcessor( - new MyCustomProcessor( - // Note: This example uses the final IServiceProvider once it is available. - sp.GetRequiredService(), - sp.GetRequiredService>().Value)); - })); + appBuilder.Services.AddOpenTelemetry() + .WithTracing(builder => builder + .ConfigureBuilder((sp, builder) => + { + builder.AddProcessor( + new MyCustomProcessor( + // Note: This example uses the final IServiceProvider once it is available. + sp.GetRequiredService(), + sp.GetRequiredService>().Value)); + })) + .StartWithHost(); ``` **Note:** `ConfigureBuilder` is an advanced API and is expected to be used @@ -612,8 +617,9 @@ var appBuilder = WebApplication.CreateBuilder(args); appBuilder.Services.Configure( appBuilder.Configuration.GetSection("OpenTelemetry:Jaeger")); -appBuilder.Services.AddOpenTelemetryTracing( - builder => builder.AddJaegerExporter()); +appBuilder.Services.AddOpenTelemetry() + .WithTracing(builder => builder.AddJaegerExporter()) + .StartWithHost(); ``` The OpenTelemetry .NET SDK supports running multiple `TracerProvider`s inside @@ -654,7 +660,9 @@ appBuilder.Services.Configure( "JaegerSecondary", appBuilder.Configuration.GetSection("OpenTelemetry:JaegerSecondary")); -appBuilder.Services.AddOpenTelemetryTracing(builder => builder - .AddJaegerExporter(name: "JaegerPrimary", configure: null) - .AddJaegerExporter(name: "JaegerSecondary", configure: null)); +appBuilder.Services.AddOpenTelemetry() + .WithTracing(builder => builder + .AddJaegerExporter(name: "JaegerPrimary", configure: null) + .AddJaegerExporter(name: "JaegerSecondary", configure: null)) + .StartWithHost(); ``` diff --git a/docs/trace/extending-the-sdk/README.md b/docs/trace/extending-the-sdk/README.md index 8d62577cb1b..ec34104adfe 100644 --- a/docs/trace/extending-the-sdk/README.md +++ b/docs/trace/extending-the-sdk/README.md @@ -530,7 +530,7 @@ the target type for registration extension methods. The following example shows how a library might enable tracing and metric support using an `IServiceCollection` extension by calling -`ConfigureOpenTelemetryTracing`. +`ConfigureOpenTelemetryTracerProvider`. ```csharp using Microsoft.Extensions.DependencyInjection.Extensions; @@ -563,7 +563,7 @@ namespace Microsoft.Extensions.DependencyInjection } // Configure OpenTelemetry tracing. - services.ConfigureOpenTelemetryTracing(builder => builder.ConfigureBuilder((sp, builder) => + services.ConfigureOpenTelemetryTracerProvider((sp, builder) => { var options = sp.GetRequiredService>().Get(name); if (options.EnableTracing) @@ -573,7 +573,7 @@ namespace Microsoft.Extensions.DependencyInjection })); // Configure OpenTelemetry metrics. - services.ConfigureOpenTelemetryMetrics(builder => builder.ConfigureBuilder((sp, builder) => + services.ConfigureOpenTelemetryMeterProvider((sp, builder) => { var options = sp.GetRequiredService>().Get(name); if (options.EnableMetrics) @@ -614,13 +614,12 @@ single `AddMyLibrary` extension to configure the library itself and optionally turn on OpenTelemetry integration for multiple signals (tracing & metrics in this case). -**Note:** `ConfigureOpenTelemetryTracing` does not automatically start -OpenTelemetry. The host is responsible for either calling -`AddOpenTelemetryTracing` in the +**Note:** `ConfigureOpenTelemetryTracerProvider` does not automatically start +OpenTelemetry. The host is responsible for either calling `StartWithHost` in the [OpenTelemetry.Extensions.Hosting](../../../src/OpenTelemetry.Extensions.Hosting/README.md) package, calling `Build` when using the `Sdk.CreateTracerProviderBuilder` method, or by accessing the `TracerProvider` from the `IServiceCollection` where -`ConfigureOpenTelemetryTracing` was performed. +`ConfigureOpenTelemetryTracerProvider` was performed. When providing `IServiceCollection` registration extensions: diff --git a/examples/AspNetCore/Program.cs b/examples/AspNetCore/Program.cs index e070011daa7..f051b05f903 100644 --- a/examples/AspNetCore/Program.cs +++ b/examples/AspNetCore/Program.cs @@ -15,6 +15,7 @@ // using System.Reflection; +using OpenTelemetry; using OpenTelemetry.Exporter; using OpenTelemetry.Instrumentation.AspNetCore; using OpenTelemetry.Logs; @@ -22,118 +23,122 @@ using OpenTelemetry.Resources; using OpenTelemetry.Trace; -var builder = WebApplication.CreateBuilder(args); +var appBuilder = WebApplication.CreateBuilder(args); -// OpenTelemetry -var assemblyVersion = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "unknown"; +// Note: Switch between Zipkin/Jaeger/OTLP/Console by setting UseTracingExporter in appsettings.json. +var tracingExporter = appBuilder.Configuration.GetValue("UseTracingExporter").ToLowerInvariant(); -// Switch between Zipkin/Jaeger/OTLP/Console by setting UseTracingExporter in appsettings.json. -var tracingExporter = builder.Configuration.GetValue("UseTracingExporter").ToLowerInvariant(); +// Note: Switch between Prometheus/OTLP/Console by setting UseMetricsExporter in appsettings.json. +var metricsExporter = appBuilder.Configuration.GetValue("UseMetricsExporter").ToLowerInvariant(); -var serviceName = tracingExporter switch -{ - "jaeger" => builder.Configuration.GetValue("Jaeger:ServiceName"), - "zipkin" => builder.Configuration.GetValue("Zipkin:ServiceName"), - "otlp" => builder.Configuration.GetValue("Otlp:ServiceName"), - _ => "AspNetCoreExampleService", -}; +// Note: Switch between Console/OTLP by setting UseLogExporter in appsettings.json. +var logExporter = appBuilder.Configuration.GetValue("UseLogExporter").ToLowerInvariant(); +// Build a resource configuration action to set service information. Action configureResource = r => r.AddService( - serviceName, serviceVersion: assemblyVersion, serviceInstanceId: Environment.MachineName); - -// Traces -builder.Services.AddOpenTelemetryTracing(options => -{ - options - .ConfigureResource(configureResource) - .SetSampler(new AlwaysOnSampler()) - .AddHttpClientInstrumentation() - .AddAspNetCoreInstrumentation(); - - switch (tracingExporter) + serviceName: appBuilder.Configuration.GetValue("ServiceName"), + serviceVersion: Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "unknown", + serviceInstanceId: Environment.MachineName); + +// Configure OpenTelemetry tracing & metrics with auto-start using the +// StartWithHost extension from OpenTelemetry.Extensions.Hosting. +appBuilder.Services.AddOpenTelemetry() + .ConfigureResource(configureResource) + .WithTracing(builder => { - case "jaeger": - options.AddJaegerExporter(); - - builder.Services.Configure(builder.Configuration.GetSection("Jaeger")); + // Tracing - // Customize the HttpClient that will be used when JaegerExporter is configured for HTTP transport. - builder.Services.AddHttpClient("JaegerExporter", configureClient: (client) => client.DefaultRequestHeaders.Add("X-MyCustomHeader", "value")); - break; + builder + .SetSampler(new AlwaysOnSampler()) + .AddHttpClientInstrumentation() + .AddAspNetCoreInstrumentation(); - case "zipkin": - options.AddZipkinExporter(); + // Use IConfiguration binding for AspNetCore instrumentation options. + appBuilder.Services.Configure(appBuilder.Configuration.GetSection("AspNetCoreInstrumentation")); - builder.Services.Configure(builder.Configuration.GetSection("Zipkin")); - break; + switch (tracingExporter) + { + case "jaeger": + builder.AddJaegerExporter(); - case "otlp": - options.AddOtlpExporter(otlpOptions => + builder.ConfigureServices(services => { - otlpOptions.Endpoint = new Uri(builder.Configuration.GetValue("Otlp:Endpoint")); - }); - break; + // Use IConfiguration binding for Jaeger exporter options. + services.Configure(appBuilder.Configuration.GetSection("Jaeger")); - default: - options.AddConsoleExporter(); - - break; - } -}); - -// For options which can be bound from IConfiguration. -builder.Services.Configure(builder.Configuration.GetSection("AspNetCoreInstrumentation")); + // Customize the HttpClient that will be used when JaegerExporter is configured for HTTP transport. + services.AddHttpClient("JaegerExporter", configureClient: (client) => client.DefaultRequestHeaders.Add("X-MyCustomHeader", "value")); + }); + break; -// Logging -builder.Logging.ClearProviders(); + case "zipkin": + builder.AddZipkinExporter(); -builder.Logging.AddOpenTelemetry(options => -{ - options.ConfigureResource(configureResource); + builder.ConfigureServices(services => + { + // Use IConfiguration binding for Zipkin exporter options. + services.Configure(appBuilder.Configuration.GetSection("Zipkin")); + }); + break; - // Switch between Console/OTLP by setting UseLogExporter in appsettings.json. - var logExporter = builder.Configuration.GetValue("UseLogExporter").ToLowerInvariant(); - switch (logExporter) + case "otlp": + builder.AddOtlpExporter(otlpOptions => + { + // Use IConfiguration directly for Otlp exporter endpoint option. + otlpOptions.Endpoint = new Uri(appBuilder.Configuration.GetValue("Otlp:Endpoint")); + }); + break; + + default: + builder.AddConsoleExporter(); + break; + } + }) + .WithMetrics(builder => { - case "otlp": - options.AddOtlpExporter(otlpOptions => - { - otlpOptions.Endpoint = new Uri(builder.Configuration.GetValue("Otlp:Endpoint")); - }); - break; - default: - options.AddConsoleExporter(); - break; - } -}); - -builder.Services.Configure(opt => + // Metrics + + builder + .AddRuntimeInstrumentation() + .AddHttpClientInstrumentation() + .AddAspNetCoreInstrumentation(); + + switch (metricsExporter) + { + case "prometheus": + builder.AddPrometheusExporter(); + break; + case "otlp": + builder.AddOtlpExporter(otlpOptions => + { + // Use IConfiguration directly for Otlp exporter endpoint option. + otlpOptions.Endpoint = new Uri(appBuilder.Configuration.GetValue("Otlp:Endpoint")); + }); + break; + default: + builder.AddConsoleExporter(); + break; + } + }) + .StartWithHost(); + +// Clear default logging providers used by WebApplication host. +appBuilder.Logging.ClearProviders(); + +// Configure OpenTelemetry Logging. +appBuilder.Logging.AddOpenTelemetry(options => { - opt.IncludeScopes = true; - opt.ParseStateValues = true; - opt.IncludeFormattedMessage = true; -}); + // Note: See appsettings.json Logging:OpenTelemetry section for configuration. -// Metrics -// Switch between Prometheus/OTLP/Console by setting UseMetricsExporter in appsettings.json. -var metricsExporter = builder.Configuration.GetValue("UseMetricsExporter").ToLowerInvariant(); - -builder.Services.AddOpenTelemetryMetrics(options => -{ - options.ConfigureResource(configureResource) - .AddRuntimeInstrumentation() - .AddHttpClientInstrumentation() - .AddAspNetCoreInstrumentation(); + options.ConfigureResource(configureResource); - switch (metricsExporter) + switch (logExporter) { - case "prometheus": - options.AddPrometheusExporter(); - break; case "otlp": options.AddOtlpExporter(otlpOptions => { - otlpOptions.Endpoint = new Uri(builder.Configuration.GetValue("Otlp:Endpoint")); + // Use IConfiguration directly for Otlp exporter endpoint option. + otlpOptions.Endpoint = new Uri(appBuilder.Configuration.GetValue("Otlp:Endpoint")); }); break; default: @@ -142,17 +147,14 @@ } }); -// Add services to the container. -builder.Services.AddControllers(); +appBuilder.Services.AddControllers(); -// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle -builder.Services.AddEndpointsApiExplorer(); +appBuilder.Services.AddEndpointsApiExplorer(); -builder.Services.AddSwaggerGen(); +appBuilder.Services.AddSwaggerGen(); -var app = builder.Build(); +var app = appBuilder.Build(); -// Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); @@ -165,6 +167,7 @@ app.MapControllers(); +// Configure OpenTelemetry Prometheus AspNetCore middleware scrape endpoint if enabled. if (metricsExporter.Equals("prometheus", StringComparison.OrdinalIgnoreCase)) { app.UseOpenTelemetryPrometheusScrapingEndpoint(); diff --git a/examples/AspNetCore/appsettings.json b/examples/AspNetCore/appsettings.json index 10f9feba43f..b6756e818df 100644 --- a/examples/AspNetCore/appsettings.json +++ b/examples/AspNetCore/appsettings.json @@ -1,27 +1,29 @@ { "Logging": { "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" + "Default": "Information" + }, + "OpenTelemetry": { + "IncludeFormattedMessage": true, + "IncludeScopes": true, + "ParseStateValues": true } }, + "ServiceName": "otel-test", "AllowedHosts": "*", "UseTracingExporter": "console", "UseMetricsExporter": "console", "UseLogExporter": "console", "Jaeger": { - "ServiceName": "jaeger-test", "AgentHost": "localhost", "AgentPort": 6831, "Endpoint": "http://localhost:14268", "Protocol": "UdpCompactThrift" }, "Zipkin": { - "ServiceName": "zipkin-test", "Endpoint": "http://localhost:9411/api/v2/spans" }, "Otlp": { - "ServiceName": "otlp-test", "Endpoint": "http://localhost:4317" }, "AspNetCoreInstrumentation": { diff --git a/examples/GrpcService/Startup.cs b/examples/GrpcService/Startup.cs index c7034011b02..98f563800e1 100644 --- a/examples/GrpcService/Startup.cs +++ b/examples/GrpcService/Startup.cs @@ -21,6 +21,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using OpenTelemetry; using OpenTelemetry.Resources; using OpenTelemetry.Trace; @@ -39,34 +40,36 @@ public void ConfigureServices(IServiceCollection services) { services.AddGrpc(); - // Switch between Jaeger/Zipkin by setting UseExporter in appsettings.json. - var exporter = this.Configuration.GetValue("UseExporter").ToLowerInvariant(); - switch (exporter) - { - case "jaeger": - services.AddOpenTelemetryTracing((builder) => builder - .ConfigureResource(r => r.AddService(this.Configuration.GetValue("Jaeger:ServiceName"))) - .AddAspNetCoreInstrumentation() - .AddJaegerExporter(jaegerOptions => - { - jaegerOptions.AgentHost = this.Configuration.GetValue("Jaeger:Host"); - jaegerOptions.AgentPort = this.Configuration.GetValue("Jaeger:Port"); - })); - break; - case "zipkin": - services.AddOpenTelemetryTracing((builder) => builder - .AddAspNetCoreInstrumentation() - .AddZipkinExporter(zipkinOptions => - { - zipkinOptions.Endpoint = new Uri(this.Configuration.GetValue("Zipkin:Endpoint")); - })); - break; - default: - services.AddOpenTelemetryTracing((builder) => builder - .AddAspNetCoreInstrumentation() - .AddConsoleExporter()); - break; - } + services.AddOpenTelemetry() + .WithTracing(builder => + { + builder + .ConfigureResource(r => r.AddService(this.Configuration.GetValue("ServiceName"))) + .AddAspNetCoreInstrumentation(); + + // Switch between Jaeger/Zipkin/Console by setting UseExporter in appsettings.json. + var exporter = this.Configuration.GetValue("UseExporter").ToLowerInvariant(); + switch (exporter) + { + case "jaeger": + builder.AddJaegerExporter(jaegerOptions => + { + jaegerOptions.AgentHost = this.Configuration.GetValue("Jaeger:Host"); + jaegerOptions.AgentPort = this.Configuration.GetValue("Jaeger:Port"); + }); + break; + case "zipkin": + builder.AddZipkinExporter(zipkinOptions => + { + zipkinOptions.Endpoint = new Uri(this.Configuration.GetValue("Zipkin:Endpoint")); + }); + break; + default: + builder.AddConsoleExporter(); + break; + } + }) + .StartWithHost(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) diff --git a/examples/GrpcService/appsettings.json b/examples/GrpcService/appsettings.json index eb311b0d6fa..675b9d1c8e6 100644 --- a/examples/GrpcService/appsettings.json +++ b/examples/GrpcService/appsettings.json @@ -12,14 +12,13 @@ "Protocols": "Http2" } }, + "ServiceName": "otel-test", "UseExporter": "console", "Jaeger": { - "ServiceName": "jaeger-test", "Host": "localhost", "Port": 6831 }, "Zipkin": { - "ServiceName": "zipkin-test", "Endpoint": "http://localhost:9411/api/v2/spans" } } diff --git a/examples/MicroserviceExample/WebApi/Startup.cs b/examples/MicroserviceExample/WebApi/Startup.cs index a7664f00ccf..8a3fb88d04e 100644 --- a/examples/MicroserviceExample/WebApi/Startup.cs +++ b/examples/MicroserviceExample/WebApi/Startup.cs @@ -20,6 +20,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using OpenTelemetry; using OpenTelemetry.Trace; using Utils.Messaging; @@ -40,14 +41,16 @@ public void ConfigureServices(IServiceCollection services) services.AddSingleton(); - services.AddOpenTelemetryTracing((builder) => builder - .AddAspNetCoreInstrumentation() - .AddSource(nameof(MessageSender)) - .AddZipkinExporter(b => - { - var zipkinHostName = Environment.GetEnvironmentVariable("ZIPKIN_HOSTNAME") ?? "localhost"; - b.Endpoint = new Uri($"http://{zipkinHostName}:9411/api/v2/spans"); - })); + services.AddOpenTelemetry() + .WithTracing(builder => builder + .AddAspNetCoreInstrumentation() + .AddSource(nameof(MessageSender)) + .AddZipkinExporter(b => + { + 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) diff --git a/examples/MicroserviceExample/WorkerService/Program.cs b/examples/MicroserviceExample/WorkerService/Program.cs index 88a8cfd8dcf..10add6ae111 100644 --- a/examples/MicroserviceExample/WorkerService/Program.cs +++ b/examples/MicroserviceExample/WorkerService/Program.cs @@ -17,6 +17,7 @@ using System; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using OpenTelemetry; using OpenTelemetry.Trace; using Utils.Messaging; @@ -37,16 +38,15 @@ public static IHostBuilder CreateHostBuilder(string[] args) => services.AddSingleton(); - services.AddOpenTelemetryTracing(builder => - { - builder + services.AddOpenTelemetry() + .WithTracing(builder => builder .AddSource(nameof(MessageReceiver)) .AddZipkinExporter(b => { var zipkinHostName = Environment.GetEnvironmentVariable("ZIPKIN_HOSTNAME") ?? "localhost"; b.Endpoint = new Uri($"http://{zipkinHostName}:9411/api/v2/spans"); - }); - }); + })) + .StartWithHost(); }); } } diff --git a/src/OpenTelemetry.Exporter.Jaeger/README.md b/src/OpenTelemetry.Exporter.Jaeger/README.md index 2a67fb66d42..22fd4a382e4 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/README.md +++ b/src/OpenTelemetry.Exporter.Jaeger/README.md @@ -90,17 +90,19 @@ who want to configure the `HttpClient` used by the `JaegerExporter` when implementation if you want to customize the generated `HttpClient`: ```csharp -services.AddOpenTelemetryTracing((builder) => builder - .AddJaegerExporter(o => - { - o.Protocol = JaegerExportProtocol.HttpBinaryThrift; - o.HttpClientFactory = () => +services.AddOpenTelemetry() + .WithTracing(builder => builder + .AddJaegerExporter(o => { - HttpClient client = new HttpClient(); - client.DefaultRequestHeaders.Add("X-MyCustomHeader", "value"); - return client; - }; - })); + o.Protocol = JaegerExportProtocol.HttpBinaryThrift; + o.HttpClientFactory = () => + { + HttpClient client = new HttpClient(); + client.DefaultRequestHeaders.Add("X-MyCustomHeader", "value"); + return client; + }; + })) + .StartWithHost(); ``` For users using diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md index 8005b5246f3..4386b891217 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md @@ -127,17 +127,19 @@ function with your own implementation if you want to customize the generated `HttpClient`: ```csharp -services.AddOpenTelemetryTracing((builder) => builder - .AddOtlpExporter(o => - { - o.Protocol = OtlpExportProtocol.HttpProtobuf; - o.HttpClientFactory = () => +services.AddOpenTelemetry() + .WithTracing(builder => builder + .AddOtlpExporter(o => { - HttpClient client = new HttpClient(); - client.DefaultRequestHeaders.Add("X-MyCustomHeader", "value"); - return client; - }; - })); + o.Protocol = OtlpExportProtocol.HttpProtobuf; + o.HttpClientFactory = () => + { + HttpClient client = new HttpClient(); + client.DefaultRequestHeaders.Add("X-MyCustomHeader", "value"); + return client; + }; + })) + .StartWithHost(); ``` For users using diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md index 1387fb09736..6bcd236b5bb 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md @@ -26,10 +26,10 @@ dotnet add package --prerelease OpenTelemetry.Exporter.Prometheus.AspNetCore package on .NET 6.0+: ```csharp - services.AddOpenTelemetryMetrics(builder => - { - builder.AddPrometheusExporter(); - }); + services.AddOpenTelemetry() + .WithMetrics(builder => builder + .AddPrometheusExporter()) + .StartWithHost(); ``` * Or configure directly: diff --git a/src/OpenTelemetry.Exporter.Zipkin/README.md b/src/OpenTelemetry.Exporter.Zipkin/README.md index 7cfd6d2ca11..9b4b7c185ef 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/README.md +++ b/src/OpenTelemetry.Exporter.Zipkin/README.md @@ -83,13 +83,15 @@ replace the function with your own implementation if you want to customize the generated `HttpClient`: ```csharp -services.AddOpenTelemetryTracing((builder) => builder - .AddZipkinExporter(o => o.HttpClientFactory = () => - { - HttpClient client = new HttpClient(); - client.DefaultRequestHeaders.Add("X-MyCustomHeader", "value"); - return client; - })); +services.AddOpenTelemetry() + .WithTracing(builder => builder + .AddZipkinExporter(o => o.HttpClientFactory = () => + { + HttpClient client = new HttpClient(); + client.DefaultRequestHeaders.Add("X-MyCustomHeader", "value"); + return client; + })) + .StartWithHost(); ``` For users using diff --git a/src/OpenTelemetry.Extensions.DependencyInjection/.publicApi/net462/PublicAPI.Shipped.txt b/src/OpenTelemetry.Extensions.DependencyInjection/.publicApi/net462/PublicAPI.Shipped.txt new file mode 100644 index 00000000000..7dc5c58110b --- /dev/null +++ b/src/OpenTelemetry.Extensions.DependencyInjection/.publicApi/net462/PublicAPI.Shipped.txt @@ -0,0 +1 @@ +#nullable enable diff --git a/src/OpenTelemetry.Extensions.DependencyInjection/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Extensions.DependencyInjection/.publicApi/net462/PublicAPI.Unshipped.txt new file mode 100644 index 00000000000..61fd6da1fd8 --- /dev/null +++ b/src/OpenTelemetry.Extensions.DependencyInjection/.publicApi/net462/PublicAPI.Unshipped.txt @@ -0,0 +1,30 @@ +OpenTelemetry.Metrics.IConfigureMeterProviderBuilder +OpenTelemetry.Metrics.IConfigureMeterProviderBuilder.ConfigureBuilder(System.IServiceProvider! serviceProvider, OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> void +OpenTelemetry.Metrics.IMeterProviderBuilder +OpenTelemetry.Metrics.IMeterProviderBuilder.ConfigureBuilder(System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! +OpenTelemetry.Metrics.IMeterProviderBuilder.ConfigureServices(System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! +OpenTelemetry.Metrics.IMeterProviderBuilder.Provider.get -> OpenTelemetry.Metrics.MeterProvider? +OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions +OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMetricsServiceCollectionExtensions +OpenTelemetry.Trace.IConfigureTracerProviderBuilder +OpenTelemetry.Trace.IConfigureTracerProviderBuilder.ConfigureBuilder(System.IServiceProvider! serviceProvider, OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> void +OpenTelemetry.Trace.ITracerProviderBuilder +OpenTelemetry.Trace.ITracerProviderBuilder.ConfigureBuilder(System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! +OpenTelemetry.Trace.ITracerProviderBuilder.ConfigureServices(System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! +OpenTelemetry.Trace.ITracerProviderBuilder.Provider.get -> OpenTelemetry.Trace.TracerProvider? +OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions +OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracingServiceCollectionExtensions +static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! +static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Func! instrumentationFactory) -> OpenTelemetry.Metrics.MeterProviderBuilder! +static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Func! instrumentationFactory) -> OpenTelemetry.Metrics.MeterProviderBuilder! +static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, T! instrumentation) -> OpenTelemetry.Metrics.MeterProviderBuilder! +static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! +static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! +static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMetricsServiceCollectionExtensions.ConfigureOpenTelemetryMeterProvider(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! +static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Func! instrumentationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Func! instrumentationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, T! instrumentation) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracingServiceCollectionExtensions.ConfigureOpenTelemetryTracerProvider(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! diff --git a/src/OpenTelemetry.Extensions.DependencyInjection/.publicApi/netstandard2.0/PublicAPI.Shipped.txt b/src/OpenTelemetry.Extensions.DependencyInjection/.publicApi/netstandard2.0/PublicAPI.Shipped.txt new file mode 100644 index 00000000000..7dc5c58110b --- /dev/null +++ b/src/OpenTelemetry.Extensions.DependencyInjection/.publicApi/netstandard2.0/PublicAPI.Shipped.txt @@ -0,0 +1 @@ +#nullable enable diff --git a/src/OpenTelemetry.Extensions.DependencyInjection/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Extensions.DependencyInjection/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt new file mode 100644 index 00000000000..61fd6da1fd8 --- /dev/null +++ b/src/OpenTelemetry.Extensions.DependencyInjection/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -0,0 +1,30 @@ +OpenTelemetry.Metrics.IConfigureMeterProviderBuilder +OpenTelemetry.Metrics.IConfigureMeterProviderBuilder.ConfigureBuilder(System.IServiceProvider! serviceProvider, OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> void +OpenTelemetry.Metrics.IMeterProviderBuilder +OpenTelemetry.Metrics.IMeterProviderBuilder.ConfigureBuilder(System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! +OpenTelemetry.Metrics.IMeterProviderBuilder.ConfigureServices(System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! +OpenTelemetry.Metrics.IMeterProviderBuilder.Provider.get -> OpenTelemetry.Metrics.MeterProvider? +OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions +OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMetricsServiceCollectionExtensions +OpenTelemetry.Trace.IConfigureTracerProviderBuilder +OpenTelemetry.Trace.IConfigureTracerProviderBuilder.ConfigureBuilder(System.IServiceProvider! serviceProvider, OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> void +OpenTelemetry.Trace.ITracerProviderBuilder +OpenTelemetry.Trace.ITracerProviderBuilder.ConfigureBuilder(System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! +OpenTelemetry.Trace.ITracerProviderBuilder.ConfigureServices(System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! +OpenTelemetry.Trace.ITracerProviderBuilder.Provider.get -> OpenTelemetry.Trace.TracerProvider? +OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions +OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracingServiceCollectionExtensions +static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! +static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Func! instrumentationFactory) -> OpenTelemetry.Metrics.MeterProviderBuilder! +static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Func! instrumentationFactory) -> OpenTelemetry.Metrics.MeterProviderBuilder! +static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, T! instrumentation) -> OpenTelemetry.Metrics.MeterProviderBuilder! +static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! +static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! +static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMetricsServiceCollectionExtensions.ConfigureOpenTelemetryMeterProvider(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! +static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Func! instrumentationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Func! instrumentationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, T! instrumentation) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracingServiceCollectionExtensions.ConfigureOpenTelemetryTracerProvider(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! diff --git a/src/OpenTelemetry.Extensions.DependencyInjection/AssemblyInfo.cs b/src/OpenTelemetry.Extensions.DependencyInjection/AssemblyInfo.cs new file mode 100644 index 00000000000..f07bd3cd4ba --- /dev/null +++ b/src/OpenTelemetry.Extensions.DependencyInjection/AssemblyInfo.cs @@ -0,0 +1,33 @@ +// +// 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.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("OpenTelemetry.Extensions.DependencyInjection.Tests" + AssemblyInfo.PublicKey)] + +#if SIGNED +internal static class AssemblyInfo +{ + public const string PublicKey = ", PublicKey=002400000480000094000000060200000024000052534131000400000100010051C1562A090FB0C9F391012A32198B5E5D9A60E9B80FA2D7B434C9E5CCB7259BD606E66F9660676AFC6692B8CDC6793D190904551D2103B7B22FA636DCBB8208839785BA402EA08FC00C8F1500CCEF28BBF599AA64FFB1E1D5DC1BF3420A3777BADFE697856E9D52070A50C3EA5821C80BEF17CA3ACFFA28F89DD413F096F898"; + public const string MoqPublicKey = ", PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7"; +} +#else +internal static class AssemblyInfo +{ + public const string PublicKey = ""; + public const string MoqPublicKey = ""; +} +#endif diff --git a/src/OpenTelemetry.Extensions.DependencyInjection/CHANGELOG.md b/src/OpenTelemetry.Extensions.DependencyInjection/CHANGELOG.md new file mode 100644 index 00000000000..63bfc986bdc --- /dev/null +++ b/src/OpenTelemetry.Extensions.DependencyInjection/CHANGELOG.md @@ -0,0 +1,5 @@ +# Changelog + +## Unreleased + +Initial release. diff --git a/src/OpenTelemetry.Extensions.DependencyInjection/Metrics/IConfigureMeterProviderBuilder.cs b/src/OpenTelemetry.Extensions.DependencyInjection/Metrics/IConfigureMeterProviderBuilder.cs new file mode 100644 index 00000000000..0176e2be7c7 --- /dev/null +++ b/src/OpenTelemetry.Extensions.DependencyInjection/Metrics/IConfigureMeterProviderBuilder.cs @@ -0,0 +1,30 @@ +// +// 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. +// + +namespace OpenTelemetry.Metrics; + +/// +/// Represents something that configures the type. +/// +public interface IConfigureMeterProviderBuilder +{ + /// + /// Invoked to configure a instance. + /// + /// . + /// . + void ConfigureBuilder(IServiceProvider serviceProvider, MeterProviderBuilder meterProviderBuilder); +} diff --git a/src/OpenTelemetry.Extensions.DependencyInjection/Metrics/IMeterProviderBuilder.cs b/src/OpenTelemetry.Extensions.DependencyInjection/Metrics/IMeterProviderBuilder.cs new file mode 100644 index 00000000000..8b0766bf9cf --- /dev/null +++ b/src/OpenTelemetry.Extensions.DependencyInjection/Metrics/IMeterProviderBuilder.cs @@ -0,0 +1,58 @@ +// +// 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 Microsoft.Extensions.DependencyInjection; + +namespace OpenTelemetry.Metrics; + +/// +/// Describes a backed by an . +/// +public interface IMeterProviderBuilder : IDeferredMeterProviderBuilder +{ + /// + /// Gets the being constructed by the builder. + /// + /// + /// Note: should return until + /// construction has started and the has + /// closed. + /// + MeterProvider? Provider { get; } + + /// + /// Register a callback action to configure the where metric services are configured. + /// + /// + /// Note: Metric services are only available during the application + /// configuration phase. This method should throw a if services are configured after the + /// application has been created. + /// + /// Configuration callback. + /// The supplied for chaining. + MeterProviderBuilder ConfigureServices(Action configure); + + /// + /// Register a callback action to configure the once the application is available. + /// + /// Configuration callback. + /// The supplied for chaining. + MeterProviderBuilder ConfigureBuilder(Action configure); +} diff --git a/src/OpenTelemetry.Extensions.DependencyInjection/Metrics/OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Extensions.DependencyInjection/Metrics/OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.cs new file mode 100644 index 00000000000..3621124668f --- /dev/null +++ b/src/OpenTelemetry.Extensions.DependencyInjection/Metrics/OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.cs @@ -0,0 +1,161 @@ +// +// 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 Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using OpenTelemetry.Internal; + +namespace OpenTelemetry.Metrics; + +/// +/// Contains extension methods for the class. +/// +public static class OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions +{ + /// + /// Adds instrumentation to the provider. + /// + /// + /// Note: The type specified by will be + /// registered as a singleton service into application services. + /// + /// Instrumentation type. + /// . + /// The supplied for chaining. + public static MeterProviderBuilder AddInstrumentation(this MeterProviderBuilder meterProviderBuilder) + where T : class + { + meterProviderBuilder.ConfigureServices(services => services.TryAddSingleton()); + + meterProviderBuilder.ConfigureBuilder((sp, builder) => + { + builder.AddInstrumentation(() => sp.GetRequiredService()); + }); + + return meterProviderBuilder; + } + + /// + /// Adds instrumentation to the provider. + /// + /// Instrumentation type. + /// . + /// Instrumentation instance. + /// The supplied for chaining. + public static MeterProviderBuilder AddInstrumentation(this MeterProviderBuilder meterProviderBuilder, T instrumentation) + where T : class + { + Guard.ThrowIfNull(instrumentation); + + meterProviderBuilder.ConfigureBuilder((sp, builder) => + { + builder.AddInstrumentation(() => instrumentation); + }); + + return meterProviderBuilder; + } + + /// + /// Adds instrumentation to the provider. + /// + /// Instrumentation type. + /// . + /// Instrumentation factory. + /// The supplied for chaining. + public static MeterProviderBuilder AddInstrumentation( + this MeterProviderBuilder meterProviderBuilder, + Func instrumentationFactory) + where T : class + { + Guard.ThrowIfNull(instrumentationFactory); + + meterProviderBuilder.ConfigureBuilder((sp, builder) => + { + builder.AddInstrumentation(() => instrumentationFactory(sp)); + }); + + return meterProviderBuilder; + } + + /// + /// Adds instrumentation to the provider. + /// + /// Instrumentation type. + /// . + /// Instrumentation factory. + /// The supplied for chaining. + public static MeterProviderBuilder AddInstrumentation( + this MeterProviderBuilder meterProviderBuilder, + Func instrumentationFactory) + where T : class + { + Guard.ThrowIfNull(instrumentationFactory); + + meterProviderBuilder.ConfigureBuilder((sp, builder) => + { + if (builder is IMeterProviderBuilder iMeterProviderBuilder + && iMeterProviderBuilder.Provider != null) + { + builder.AddInstrumentation(() => instrumentationFactory(sp, iMeterProviderBuilder.Provider)); + } + }); + + return meterProviderBuilder; + } + + /// + /// Register a callback action to configure the where tracing services are configured. + /// + /// + /// Note: Tracing services are only available during the application + /// configuration phase. + /// + /// . + /// Configuration callback. + /// The supplied for chaining. + public static MeterProviderBuilder ConfigureServices( + this MeterProviderBuilder meterProviderBuilder, + Action configure) + { + if (meterProviderBuilder is IMeterProviderBuilder iMeterProviderBuilder) + { + iMeterProviderBuilder.ConfigureServices(configure); + } + + return meterProviderBuilder; + } + + /// + /// Register a callback action to configure the once the application is available. + /// + /// . + /// Configuration callback. + /// The supplied for chaining. + public static MeterProviderBuilder ConfigureBuilder( + this MeterProviderBuilder meterProviderBuilder, + Action configure) + { + if (meterProviderBuilder is IDeferredMeterProviderBuilder deferredMeterProviderBuilder) + { + deferredMeterProviderBuilder.Configure(configure); + } + + return meterProviderBuilder; + } +} diff --git a/src/OpenTelemetry.Extensions.DependencyInjection/Metrics/OpenTelemetryDependencyInjectionMetricsServiceCollectionExtensions.cs b/src/OpenTelemetry.Extensions.DependencyInjection/Metrics/OpenTelemetryDependencyInjectionMetricsServiceCollectionExtensions.cs new file mode 100644 index 00000000000..e87d2fd8a5c --- /dev/null +++ b/src/OpenTelemetry.Extensions.DependencyInjection/Metrics/OpenTelemetryDependencyInjectionMetricsServiceCollectionExtensions.cs @@ -0,0 +1,85 @@ +// +// 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 Microsoft.Extensions.DependencyInjection; +using OpenTelemetry.Internal; + +namespace OpenTelemetry.Metrics; + +/// +/// Extension methods for setting up OpenTelemetry Metrics services in an . +/// +public static class OpenTelemetryDependencyInjectionMetricsServiceCollectionExtensions +{ + /// + /// Registers an action used to configure the OpenTelemetry used to create the for the being + /// configured. + /// + /// + /// Notes: + /// + /// This is safe to be called multiple times and by library authors. + /// Each registered configuration action will be applied + /// sequentially. + /// A will not be created automatically + /// using this method. To begin collecting metrics use the + /// IServiceCollection.AddOpenTelemetry extension in the + /// OpenTelemetry package. + /// + /// + /// The to add + /// services to. + /// Callback action to configure the . + /// The so that additional calls + /// can be chained. + public static IServiceCollection ConfigureOpenTelemetryMeterProvider( + this IServiceCollection services, + Action configure) + { + RegisterBuildAction(services, configure); + + return services; + } + + private static void RegisterBuildAction(IServiceCollection services, Action configure) + { + Guard.ThrowIfNull(services); + Guard.ThrowIfNull(configure); + + services.AddSingleton( + new ConfigureMeterProviderBuilderCallbackWrapper(configure)); + } + + private sealed class ConfigureMeterProviderBuilderCallbackWrapper : IConfigureMeterProviderBuilder + { + private readonly Action configure; + + public ConfigureMeterProviderBuilderCallbackWrapper(Action configure) + { + Guard.ThrowIfNull(configure); + + this.configure = configure; + } + + public void ConfigureBuilder(IServiceProvider serviceProvider, MeterProviderBuilder meterProviderBuilder) + { + this.configure(serviceProvider, meterProviderBuilder); + } + } +} diff --git a/src/OpenTelemetry.Extensions.DependencyInjection/OpenTelemetry.Extensions.DependencyInjection.csproj b/src/OpenTelemetry.Extensions.DependencyInjection/OpenTelemetry.Extensions.DependencyInjection.csproj new file mode 100644 index 00000000000..4655980ddf5 --- /dev/null +++ b/src/OpenTelemetry.Extensions.DependencyInjection/OpenTelemetry.Extensions.DependencyInjection.csproj @@ -0,0 +1,28 @@ + + + + + netstandard2.0;net462 + Contains extensions to register OpenTelemetry in applications using Microsoft.Extensions.DependencyInjection + OpenTelemetry + core- + + + + + false + + + + + + + + + + + + + + + diff --git a/src/OpenTelemetry.Extensions.DependencyInjection/README.md b/src/OpenTelemetry.Extensions.DependencyInjection/README.md new file mode 100644 index 00000000000..3e783d502ee --- /dev/null +++ b/src/OpenTelemetry.Extensions.DependencyInjection/README.md @@ -0,0 +1,25 @@ +# OpenTelemetry.Extensions.DependencyInjection + +[![NuGet](https://img.shields.io/nuget/v/OpenTelemetry.Extensions.DependencyInjection.svg)](https://www.nuget.org/packages/OpenTelemetry.Extensions.DependencyInjection) +[![NuGet](https://img.shields.io/nuget/dt/OpenTelemetry.Extensions.DependencyInjection.svg)](https://www.nuget.org/packages/OpenTelemetry.Extensions.DependencyInjection) + +## Installation + +```shell +dotnet add package --prerelease OpenTelemetry.Extensions.DependencyInjection +``` + +## Overview + +The OpenTelemetry.Extensions.DependencyInjection package provides extension +methods and helpers for building `TracerProvider`s and `MeterProvider`s using +the Microsoft.Extensions.DependencyInjection API. + +The Microsoft.Extensions.DependencyInjection package is primarily intended for +library authors who need to integrate with the OpenTelemetry SDK. For more +details see: [Registration extension method guidance for library +authors](../../docs/trace/extending-the-sdk/README.md#registration-extension-method-guidance-for-library-authors). + +## References + +* [OpenTelemetry Project](https://opentelemetry.io/) diff --git a/src/OpenTelemetry.Extensions.DependencyInjection/Trace/IConfigureTracerProviderBuilder.cs b/src/OpenTelemetry.Extensions.DependencyInjection/Trace/IConfigureTracerProviderBuilder.cs new file mode 100644 index 00000000000..f09bcc05a91 --- /dev/null +++ b/src/OpenTelemetry.Extensions.DependencyInjection/Trace/IConfigureTracerProviderBuilder.cs @@ -0,0 +1,30 @@ +// +// 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. +// + +namespace OpenTelemetry.Trace; + +/// +/// Represents something that configures the type. +/// +public interface IConfigureTracerProviderBuilder +{ + /// + /// Invoked to configure a instance. + /// + /// . + /// . + void ConfigureBuilder(IServiceProvider serviceProvider, TracerProviderBuilder tracerProviderBuilder); +} diff --git a/src/OpenTelemetry.Extensions.DependencyInjection/Trace/ITracerProviderBuilder.cs b/src/OpenTelemetry.Extensions.DependencyInjection/Trace/ITracerProviderBuilder.cs new file mode 100644 index 00000000000..bfb3e499cd7 --- /dev/null +++ b/src/OpenTelemetry.Extensions.DependencyInjection/Trace/ITracerProviderBuilder.cs @@ -0,0 +1,58 @@ +// +// 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 Microsoft.Extensions.DependencyInjection; + +namespace OpenTelemetry.Trace; + +/// +/// Describes a backed by an . +/// +public interface ITracerProviderBuilder : IDeferredTracerProviderBuilder +{ + /// + /// Gets the being constructed by the builder. + /// + /// + /// Note: should return until + /// construction has started and the has + /// closed. + /// + TracerProvider? Provider { get; } + + /// + /// Register a callback action to configure the where tracing services are configured. + /// + /// + /// Note: Tracing services are only available during the application + /// configuration phase. This method should throw a if services are configured after the + /// application has been created. + /// + /// Configuration callback. + /// The supplied for chaining. + TracerProviderBuilder ConfigureServices(Action configure); + + /// + /// Register a callback action to configure the once the application is available. + /// + /// Configuration callback. + /// The supplied for chaining. + TracerProviderBuilder ConfigureBuilder(Action configure); +} diff --git a/src/OpenTelemetry.Extensions.DependencyInjection/Trace/OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.cs b/src/OpenTelemetry.Extensions.DependencyInjection/Trace/OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.cs new file mode 100644 index 00000000000..f92c5456469 --- /dev/null +++ b/src/OpenTelemetry.Extensions.DependencyInjection/Trace/OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.cs @@ -0,0 +1,161 @@ +// +// 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 Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using OpenTelemetry.Internal; + +namespace OpenTelemetry.Trace; + +/// +/// Contains extension methods for the class. +/// +public static class OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions +{ + /// + /// Adds instrumentation to the provider. + /// + /// + /// Note: The type specified by will be + /// registered as a singleton service into application services. + /// + /// Instrumentation type. + /// . + /// The supplied for chaining. + public static TracerProviderBuilder AddInstrumentation(this TracerProviderBuilder tracerProviderBuilder) + where T : class + { + tracerProviderBuilder.ConfigureServices(services => services.TryAddSingleton()); + + tracerProviderBuilder.ConfigureBuilder((sp, builder) => + { + builder.AddInstrumentation(() => sp.GetRequiredService()); + }); + + return tracerProviderBuilder; + } + + /// + /// Adds instrumentation to the provider. + /// + /// Instrumentation type. + /// . + /// Instrumentation instance. + /// The supplied for chaining. + public static TracerProviderBuilder AddInstrumentation(this TracerProviderBuilder tracerProviderBuilder, T instrumentation) + where T : class + { + Guard.ThrowIfNull(instrumentation); + + tracerProviderBuilder.ConfigureBuilder((sp, builder) => + { + builder.AddInstrumentation(() => instrumentation); + }); + + return tracerProviderBuilder; + } + + /// + /// Adds instrumentation to the provider. + /// + /// Instrumentation type. + /// . + /// Instrumentation factory. + /// The supplied for chaining. + public static TracerProviderBuilder AddInstrumentation( + this TracerProviderBuilder tracerProviderBuilder, + Func instrumentationFactory) + where T : class + { + Guard.ThrowIfNull(instrumentationFactory); + + tracerProviderBuilder.ConfigureBuilder((sp, builder) => + { + builder.AddInstrumentation(() => instrumentationFactory(sp)); + }); + + return tracerProviderBuilder; + } + + /// + /// Adds instrumentation to the provider. + /// + /// Instrumentation type. + /// . + /// Instrumentation factory. + /// The supplied for chaining. + public static TracerProviderBuilder AddInstrumentation( + this TracerProviderBuilder tracerProviderBuilder, + Func instrumentationFactory) + where T : class + { + Guard.ThrowIfNull(instrumentationFactory); + + tracerProviderBuilder.ConfigureBuilder((sp, builder) => + { + if (tracerProviderBuilder is ITracerProviderBuilder iTracerProviderBuilder + && iTracerProviderBuilder.Provider != null) + { + builder.AddInstrumentation(() => instrumentationFactory(sp, iTracerProviderBuilder.Provider)); + } + }); + + return tracerProviderBuilder; + } + + /// + /// Register a callback action to configure the where tracing services are configured. + /// + /// + /// Note: Tracing services are only available during the application + /// configuration phase. + /// + /// . + /// Configuration callback. + /// The supplied for chaining. + public static TracerProviderBuilder ConfigureServices( + this TracerProviderBuilder tracerProviderBuilder, + Action configure) + { + if (tracerProviderBuilder is ITracerProviderBuilder iTracerProviderBuilder) + { + iTracerProviderBuilder.ConfigureServices(configure); + } + + return tracerProviderBuilder; + } + + /// + /// Register a callback action to configure the once the application is available. + /// + /// . + /// Configuration callback. + /// The supplied for chaining. + public static TracerProviderBuilder ConfigureBuilder( + this TracerProviderBuilder tracerProviderBuilder, + Action configure) + { + if (tracerProviderBuilder is IDeferredTracerProviderBuilder deferredTracerProviderBuilder) + { + deferredTracerProviderBuilder.Configure(configure); + } + + return tracerProviderBuilder; + } +} diff --git a/src/OpenTelemetry.Extensions.DependencyInjection/Trace/OpenTelemetryDependencyInjectionTracingServiceCollectionExtensions.cs b/src/OpenTelemetry.Extensions.DependencyInjection/Trace/OpenTelemetryDependencyInjectionTracingServiceCollectionExtensions.cs new file mode 100644 index 00000000000..f7ff9c2a831 --- /dev/null +++ b/src/OpenTelemetry.Extensions.DependencyInjection/Trace/OpenTelemetryDependencyInjectionTracingServiceCollectionExtensions.cs @@ -0,0 +1,85 @@ +// +// 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 Microsoft.Extensions.DependencyInjection; +using OpenTelemetry.Internal; + +namespace OpenTelemetry.Trace; + +/// +/// Extension methods for setting up OpenTelemetry tracing services in an . +/// +public static class OpenTelemetryDependencyInjectionTracingServiceCollectionExtensions +{ + /// + /// Registers an action used to configure the OpenTelemetry used to create the for the being + /// configured. + /// + /// + /// Notes: + /// + /// This is safe to be called multiple times and by library authors. + /// Each registered configuration action will be applied + /// sequentially. + /// A will not be created automatically + /// using this method. To begin collecting metrics use the + /// IServiceCollection.AddOpenTelemetry extension in the + /// OpenTelemetry package. + /// + /// + /// The to add + /// services to. + /// Callback action to configure the . + /// The so that additional calls + /// can be chained. + public static IServiceCollection ConfigureOpenTelemetryTracerProvider( + this IServiceCollection services, + Action configure) + { + RegisterBuildAction(services, configure); + + return services; + } + + private static void RegisterBuildAction(IServiceCollection services, Action configure) + { + Guard.ThrowIfNull(services); + Guard.ThrowIfNull(configure); + + services.AddSingleton( + new ConfigureTracerProviderBuilderCallbackWrapper(configure)); + } + + private sealed class ConfigureTracerProviderBuilderCallbackWrapper : IConfigureTracerProviderBuilder + { + private readonly Action configure; + + public ConfigureTracerProviderBuilderCallbackWrapper(Action configure) + { + Guard.ThrowIfNull(configure); + + this.configure = configure; + } + + public void ConfigureBuilder(IServiceProvider serviceProvider, TracerProviderBuilder tracerProviderBuilder) + { + this.configure(serviceProvider, tracerProviderBuilder); + } + } +} 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 63141a61d05..dbee0f5b37d 100644 --- a/src/OpenTelemetry.Extensions.Hosting/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Extensions.Hosting/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -1,5 +1,6 @@ Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions OpenTelemetry.Metrics.MeterProviderBuilderExtensions +OpenTelemetry.OpenTelemetryBuilderHostingExtensions 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 configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection @@ -7,5 +8,6 @@ static Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions. static Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions.AddOpenTelemetryTracing(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.Configure(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, System.Action 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 configure) -> OpenTelemetry.Trace.TracerProviderBuilder static OpenTelemetry.Trace.TracerProviderBuilderExtensions.GetServices(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder) -> Microsoft.Extensions.DependencyInjection.IServiceCollection diff --git a/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md b/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md index 8d31ce75b4e..b4a2978d33c 100644 --- a/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md +++ b/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +* Added the `OpenTelemetryBuilder.StartWithHost` extension. + ([#3923](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3923)) + ## 1.0.0-rc9.9 Released 2022-Nov-07 diff --git a/src/OpenTelemetry.Extensions.Hosting/OpenTelemetry.Extensions.Hosting.csproj b/src/OpenTelemetry.Extensions.Hosting/OpenTelemetry.Extensions.Hosting.csproj index abefb22d1f1..e636ed6c65d 100644 --- a/src/OpenTelemetry.Extensions.Hosting/OpenTelemetry.Extensions.Hosting.csproj +++ b/src/OpenTelemetry.Extensions.Hosting/OpenTelemetry.Extensions.Hosting.csproj @@ -2,7 +2,7 @@ netstandard2.0 - Contains extensions to register and start OpenTelemetry in applications using Microsoft.Extensions.Hosting + Contains extensions to start OpenTelemetry in applications using Microsoft.Extensions.Hosting OpenTelemetry diff --git a/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryBuilderHostingExtensions.cs b/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryBuilderHostingExtensions.cs new file mode 100644 index 00000000000..646ca614f44 --- /dev/null +++ b/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryBuilderHostingExtensions.cs @@ -0,0 +1,54 @@ +// +// 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 Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; +using OpenTelemetry.Extensions.Hosting.Implementation; +using OpenTelemetry.Internal; + +namespace OpenTelemetry; + +/// +/// Contains hosting extension methods for the class. +/// +public static class OpenTelemetryBuilderHostingExtensions +{ + /// + /// Registers an to automatically start all + /// configured OpenTelemetry services in the supplied . + /// + /// + /// Note: This is safe to be called multiple times. Only a single will be created for a given . This should generally be called by hosting + /// application code and NOT library authors. + /// + /// . + /// The supplied for chaining + /// calls. + public static OpenTelemetryBuilder StartWithHost(this OpenTelemetryBuilder builder) + { + Guard.ThrowIfNull(builder); + + builder.Services.TryAddEnumerable( + ServiceDescriptor.Singleton()); + + return builder; + } +} diff --git a/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryServicesExtensions.cs b/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryServicesExtensions.cs index 84f8560fd47..64e837fbf16 100644 --- a/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryServicesExtensions.cs +++ b/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryServicesExtensions.cs @@ -14,121 +14,114 @@ // limitations under the License. // -using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; -using OpenTelemetry.Extensions.Hosting.Implementation; -using OpenTelemetry.Internal; +using OpenTelemetry; using OpenTelemetry.Metrics; using OpenTelemetry.Trace; -namespace Microsoft.Extensions.DependencyInjection +namespace Microsoft.Extensions.DependencyInjection; + +/// +/// Extension methods for setting up OpenTelemetry services in an . +/// +public static class OpenTelemetryServicesExtensions { /// - /// Extension methods for setting up OpenTelemetry services in an + /// to automatically start tracing services in the supplied . /// - public static class OpenTelemetryServicesExtensions - { - /// - /// Configure OpenTelemetry and register a - /// to automatically start tracing services in the supplied . - /// - /// - /// Notes: - /// - /// - /// This is safe to be called multiple times. Only a single will be created for a given . - /// - /// - /// This method should be called by application host code. Library - /// authors should call - /// instead. - /// - /// - /// - /// . - /// Supplied for chaining - /// calls. - public static IServiceCollection AddOpenTelemetryTracing(this IServiceCollection services) - => AddOpenTelemetryTracing(services, b => { }); - - /// - /// Configure OpenTelemetry and register a - /// to automatically start tracing services in the supplied . - /// - /// - /// . - /// Callback action to configure the . - /// Supplied for chaining - /// calls. - public static IServiceCollection AddOpenTelemetryTracing(this IServiceCollection services, Action configure) - { - Guard.ThrowIfNull(services); - - services.ConfigureOpenTelemetryTracing(configure); - - services.TryAddEnumerable(ServiceDescriptor.Singleton()); + /// + /// Notes: + /// + /// + /// This is safe to be called multiple times. Only a single will be created for a given . + /// + /// + /// This method should be called by application host code. Library + /// authors should call + /// instead. + /// + /// + /// + /// . + /// Supplied for chaining + /// calls. + [Obsolete("Use the AddOpenTelemetry().WithTracing(configure).StartWithHost() pattern instead. This method will be removed in a future version.")] + public static IServiceCollection AddOpenTelemetryTracing(this IServiceCollection services) + => AddOpenTelemetryTracing(services, b => { }); - return services; - } - - /// - /// Configure OpenTelemetry and register a - /// to automatically start metric services in the supplied . - /// - /// - /// Notes: - /// - /// - /// This is safe to be called multiple times. Only a single will be created for a given . - /// - /// - /// This method should be called by application host code. Library - /// authors should call - /// instead. - /// - /// - /// - /// . - /// Supplied for chaining - /// calls. - public static IServiceCollection AddOpenTelemetryMetrics(this IServiceCollection services) - => AddOpenTelemetryMetrics(services, b => { }); + /// + /// Configure OpenTelemetry and register a + /// to automatically start tracing services in the supplied . + /// + /// + /// . + /// Callback action to configure the . + /// Supplied for chaining + /// calls. + [Obsolete("Use the AddOpenTelemetry().WithTracing(configure).StartWithHost() pattern instead. This method will be removed in a future version.")] + public static IServiceCollection AddOpenTelemetryTracing(this IServiceCollection services, Action configure) + { + services.AddOpenTelemetry().WithTracing(configure).StartWithHost(); - /// - /// Configure OpenTelemetry and register a - /// to automatically start metric services in the supplied . - /// - /// - /// . - /// Callback action to configure the . - /// Supplied for chaining - /// calls. - public static IServiceCollection AddOpenTelemetryMetrics(this IServiceCollection services, Action configure) - { - Guard.ThrowIfNull(services); + return services; + } - services.ConfigureOpenTelemetryMetrics(configure); + /// + /// Configure OpenTelemetry and register a + /// to automatically start metric services in the supplied . + /// + /// + /// Notes: + /// + /// + /// This is safe to be called multiple times. Only a single will be created for a given . + /// + /// + /// This method should be called by application host code. Library + /// authors should call + /// instead. + /// + /// + /// + /// . + /// Supplied for chaining + /// calls. + [Obsolete("Use the AddOpenTelemetry().WithMetrics(configure).StartWithHost() pattern instead. This method will be removed in a future version.")] + public static IServiceCollection AddOpenTelemetryMetrics(this IServiceCollection services) + => AddOpenTelemetryMetrics(services, b => { }); - services.TryAddEnumerable(ServiceDescriptor.Singleton()); + /// + /// Configure OpenTelemetry and register a + /// to automatically start metric services in the supplied . + /// + /// + /// . + /// Callback action to configure the . + /// Supplied for chaining + /// calls. + [Obsolete("Use the AddOpenTelemetry().WithMetrics(configure).StartWithHost() pattern instead. This method will be removed in a future version.")] + public static IServiceCollection AddOpenTelemetryMetrics(this IServiceCollection services, Action configure) + { + services.AddOpenTelemetry().WithMetrics(configure).StartWithHost(); - return services; - } + return services; } } diff --git a/src/OpenTelemetry.Extensions.Hosting/README.md b/src/OpenTelemetry.Extensions.Hosting/README.md index e8e35c03383..b76f082bb5b 100644 --- a/src/OpenTelemetry.Extensions.Hosting/README.md +++ b/src/OpenTelemetry.Extensions.Hosting/README.md @@ -21,8 +21,16 @@ and metrics (`MeterProvider`) in [ASP.NET ## Extension method reference -**Note:** The below extension methods target -`Microsoft.Extensions.DependencyInjection.IServiceCollection`. +### Current OpenTelemetry SDK v1.4.0 and newer extensions + +Targeting `OpenTelemetry.OpenTelemetryBuilder`: + +* `StartWithHost`: 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). + +### Obsolete OpenTelemetry SDK pre-1.4.0 extensions **Note:** The below extension methods should be called by application host code only. Library authors see: [Registration extension method guidance for library @@ -37,6 +45,8 @@ and [Building a MeterProvider](../../docs/metrics/customizing-the-sdk/README.md#building-a-meterprovider) for more details. +Targeting `Microsoft.Extensions.DependencyInjection.IServiceCollection`: + * `AddOpenTelemetryTracing`: Configure OpenTelemetry and register an [IHostedService](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.ihostedservice) to automatically start tracing services in the supplied @@ -60,11 +70,10 @@ using OpenTelemetry.Trace; var appBuilder = WebApplication.CreateBuilder(args); -appBuilder.Services.AddOpenTelemetryTracing( - builder => builder.AddConsoleExporter()); - -appBuilder.Services.AddOpenTelemetryMetrics( - builder => builder.AddConsoleExporter()); +appBuilder.Services.AddOpenTelemetry() + .WithTracing(builder => builder.AddConsoleExporter()) + .WithMetrics(builder => builder.AddConsoleExporter()) + .StartWithHost(); var app = appBuilder.Build(); diff --git a/src/OpenTelemetry.Instrumentation.AspNetCore/README.md b/src/OpenTelemetry.Instrumentation.AspNetCore/README.md index a5801839648..59e489b8676 100644 --- a/src/OpenTelemetry.Instrumentation.AspNetCore/README.md +++ b/src/OpenTelemetry.Instrumentation.AspNetCore/README.md @@ -55,10 +55,11 @@ using OpenTelemetry.Trace; public void ConfigureServices(IServiceCollection services) { - services.AddOpenTelemetryTracing((builder) => builder - .AddAspNetCoreInstrumentation() - .AddJaegerExporter() - ); + services.AddOpenTelemetry() + .WithTracing(builder => builder + .AddAspNetCoreInstrumentation() + .AddJaegerExporter()) + .StartWithHost(); } ``` @@ -84,10 +85,11 @@ services.Configure(options => }; }); -services.AddOpenTelemetryTracing((builder) => builder - .AddAspNetCoreInstrumentation() - .AddJaegerExporter() -); +services.AddOpenTelemetry() + .WithTracing(builder => builder + .AddAspNetCoreInstrumentation() + .AddJaegerExporter()) + .StartWithHost(); ``` ### Filter @@ -103,14 +105,15 @@ The following code snippet shows how to use `Filter` to only allow GET requests. ```csharp -services.AddOpenTelemetryTracing((builder) => builder - .AddAspNetCoreInstrumentation((options) => options.Filter = httpContext => - { - // only collect telemetry about HTTP GET requests - return httpContext.Request.Method.Equals("GET"); - }) - .AddJaegerExporter() -); +services.AddOpenTelemetry() + .WithTracing(builder => builder + .AddAspNetCoreInstrumentation((options) => options.Filter = httpContext => + { + // only collect telemetry about HTTP GET requests + return httpContext.Request.Method.Equals("GET"); + }) + .AddJaegerExporter()) + .StartWithHost(); ``` It is important to note that this `Filter` option is specific to this @@ -131,24 +134,24 @@ The following code snippet shows how to enrich the activity using all 3 different options. ```csharp -services.AddOpenTelemetryTracing((builder) => -{ - builder.AddAspNetCoreInstrumentation(o => - { - o.EnrichWithHttpRequest = (activity, httpRequest) => - { - activity.SetTag("requestProtocol", httpRequest.Protocol); - }; - o.EnrichWithHttpResponse = (activity, httpResponse) => +services.AddOpenTelemetry() + .WithTracing(builder => builder + .AddAspNetCoreInstrumentation(o => { - activity.SetTag("responseLength", httpResponse.ContentLength); - }; - o.EnrichWithException = (activity, exception) => - { - activity.SetTag("exceptionType", exception.GetType().ToString()); - }; - }) -}); + o.EnrichWithHttpRequest = (activity, httpRequest) => + { + activity.SetTag("requestProtocol", httpRequest.Protocol); + }; + o.EnrichWithHttpResponse = (activity, httpResponse) => + { + activity.SetTag("responseLength", httpResponse.ContentLength); + }; + o.EnrichWithException = (activity, exception) => + { + activity.SetTag("exceptionType", exception.GetType().ToString()); + }; + })) + .StartWithHost(); ``` [Processor](../../docs/trace/extending-the-sdk/README.md#processor), diff --git a/src/OpenTelemetry.Instrumentation.GrpcNetClient/README.md b/src/OpenTelemetry.Instrumentation.GrpcNetClient/README.md index 9f39c155ada..62bb0853aea 100644 --- a/src/OpenTelemetry.Instrumentation.GrpcNetClient/README.md +++ b/src/OpenTelemetry.Instrumentation.GrpcNetClient/README.md @@ -108,20 +108,20 @@ can be enriched), the name of the event, and the actual raw object. The following code snippet shows how to add additional tags using these options. ```csharp -services.AddOpenTelemetryTracing((builder) => -{ - builder - .AddGrpcClientInstrumentation((options) => - { - options.EnrichWithHttpRequestMessage = (activity, httpRequestMessage) => - { - activity.SetTag("requestVersion", httpRequestMessage.Version); - }; - options.EnrichWithHttpResponseMessage = (activity, httpResponseMessage) => +services.AddOpenTelemetry() + .WithTracing(builder => builder + .AddGrpcClientInstrumentation(options => { - activity.SetTag("responseVersion", httpResponseMessage.Version); - }; - }) + options.EnrichWithHttpRequestMessage = (activity, httpRequestMessage) => + { + activity.SetTag("requestVersion", httpRequestMessage.Version); + }; + options.EnrichWithHttpResponseMessage = (activity, httpResponseMessage) => + { + activity.SetTag("responseVersion", httpResponseMessage.Version); + }; + }) + .StartWithHost(); ``` [Processor](../../docs/trace/extending-the-sdk/README.md#processor), diff --git a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt index a5968754802..65a0375525d 100644 --- a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt @@ -1,5 +1,3 @@ -Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions -Microsoft.Extensions.DependencyInjection.TracerProviderBuilderServiceCollectionExtensions OpenTelemetry.Logs.LogRecord.CategoryName.set -> void OpenTelemetry.Logs.LogRecord.EventId.set -> void OpenTelemetry.Logs.LogRecord.Exception.set -> void @@ -14,27 +12,30 @@ OpenTelemetry.Metrics.HistogramConfiguration OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void +OpenTelemetry.Metrics.MeterProviderBuilderBase.ConfigureBuilder(System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! +OpenTelemetry.Metrics.MeterProviderBuilderBase.ConfigureServices(System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMinMaxValues(out double min, out double max) -> bool +OpenTelemetry.OpenTelemetryBuilder +OpenTelemetry.OpenTelemetryBuilder.ConfigureResource(System.Action! configure) -> OpenTelemetry.OpenTelemetryBuilder! +OpenTelemetry.OpenTelemetryBuilder.Services.get -> Microsoft.Extensions.DependencyInjection.IServiceCollection! +OpenTelemetry.OpenTelemetryBuilder.WithMetrics() -> OpenTelemetry.OpenTelemetryBuilder! +OpenTelemetry.OpenTelemetryBuilder.WithMetrics(System.Action! configure) -> OpenTelemetry.OpenTelemetryBuilder! +OpenTelemetry.OpenTelemetryBuilder.WithTracing() -> OpenTelemetry.OpenTelemetryBuilder! +OpenTelemetry.OpenTelemetryBuilder.WithTracing(System.Action! configure) -> OpenTelemetry.OpenTelemetryBuilder! OpenTelemetry.Resources.ResourceBuilder.AddDetector(System.Func! resourceDetectorFactory) -> OpenTelemetry.Resources.ResourceBuilder! -static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! -static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! -static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! +OpenTelemetry.Trace.TracerProviderBuilderBase.ConfigureBuilder(System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! +OpenTelemetry.Trace.TracerProviderBuilderBase.ConfigureServices(System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! +OpenTelemetry.OpenTelemetryServiceCollectionExtensions +static OpenTelemetry.OpenTelemetryServiceCollectionExtensions.AddOpenTelemetry(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> OpenTelemetry.OpenTelemetryBuilder! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! -static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! -static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! OpenTelemetry.Trace.SamplingResult.TraceStateString.get -> string? OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, string! traceStateString) -> void OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, System.Collections.Generic.IEnumerable>? attributes, string? traceStateString) -> void *REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure = null) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure) -> Microsoft.Extensions.Logging.ILoggingBuilder! -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.ConfigureBuilder(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.SetSampler(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder! -static Microsoft.Extensions.DependencyInjection.TracerProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryTracing(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! -static Microsoft.Extensions.DependencyInjection.TracerProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryTracing(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! OpenTelemetry.Metrics.MetricType.LongSumNonMonotonic = 138 -> OpenTelemetry.Metrics.MetricType diff --git a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt index a5968754802..65a0375525d 100644 --- a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt @@ -1,5 +1,3 @@ -Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions -Microsoft.Extensions.DependencyInjection.TracerProviderBuilderServiceCollectionExtensions OpenTelemetry.Logs.LogRecord.CategoryName.set -> void OpenTelemetry.Logs.LogRecord.EventId.set -> void OpenTelemetry.Logs.LogRecord.Exception.set -> void @@ -14,27 +12,30 @@ OpenTelemetry.Metrics.HistogramConfiguration OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void +OpenTelemetry.Metrics.MeterProviderBuilderBase.ConfigureBuilder(System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! +OpenTelemetry.Metrics.MeterProviderBuilderBase.ConfigureServices(System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMinMaxValues(out double min, out double max) -> bool +OpenTelemetry.OpenTelemetryBuilder +OpenTelemetry.OpenTelemetryBuilder.ConfigureResource(System.Action! configure) -> OpenTelemetry.OpenTelemetryBuilder! +OpenTelemetry.OpenTelemetryBuilder.Services.get -> Microsoft.Extensions.DependencyInjection.IServiceCollection! +OpenTelemetry.OpenTelemetryBuilder.WithMetrics() -> OpenTelemetry.OpenTelemetryBuilder! +OpenTelemetry.OpenTelemetryBuilder.WithMetrics(System.Action! configure) -> OpenTelemetry.OpenTelemetryBuilder! +OpenTelemetry.OpenTelemetryBuilder.WithTracing() -> OpenTelemetry.OpenTelemetryBuilder! +OpenTelemetry.OpenTelemetryBuilder.WithTracing(System.Action! configure) -> OpenTelemetry.OpenTelemetryBuilder! OpenTelemetry.Resources.ResourceBuilder.AddDetector(System.Func! resourceDetectorFactory) -> OpenTelemetry.Resources.ResourceBuilder! -static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! -static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! -static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! +OpenTelemetry.Trace.TracerProviderBuilderBase.ConfigureBuilder(System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! +OpenTelemetry.Trace.TracerProviderBuilderBase.ConfigureServices(System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! +OpenTelemetry.OpenTelemetryServiceCollectionExtensions +static OpenTelemetry.OpenTelemetryServiceCollectionExtensions.AddOpenTelemetry(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> OpenTelemetry.OpenTelemetryBuilder! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! -static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! -static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! OpenTelemetry.Trace.SamplingResult.TraceStateString.get -> string? OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, string! traceStateString) -> void OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, System.Collections.Generic.IEnumerable>? attributes, string? traceStateString) -> void *REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure = null) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure) -> Microsoft.Extensions.Logging.ILoggingBuilder! -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.ConfigureBuilder(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.SetSampler(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder! -static Microsoft.Extensions.DependencyInjection.TracerProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryTracing(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! -static Microsoft.Extensions.DependencyInjection.TracerProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryTracing(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! OpenTelemetry.Metrics.MetricType.LongSumNonMonotonic = 138 -> OpenTelemetry.Metrics.MetricType diff --git a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index a5968754802..65a0375525d 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -1,5 +1,3 @@ -Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions -Microsoft.Extensions.DependencyInjection.TracerProviderBuilderServiceCollectionExtensions OpenTelemetry.Logs.LogRecord.CategoryName.set -> void OpenTelemetry.Logs.LogRecord.EventId.set -> void OpenTelemetry.Logs.LogRecord.Exception.set -> void @@ -14,27 +12,30 @@ OpenTelemetry.Metrics.HistogramConfiguration OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void +OpenTelemetry.Metrics.MeterProviderBuilderBase.ConfigureBuilder(System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! +OpenTelemetry.Metrics.MeterProviderBuilderBase.ConfigureServices(System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMinMaxValues(out double min, out double max) -> bool +OpenTelemetry.OpenTelemetryBuilder +OpenTelemetry.OpenTelemetryBuilder.ConfigureResource(System.Action! configure) -> OpenTelemetry.OpenTelemetryBuilder! +OpenTelemetry.OpenTelemetryBuilder.Services.get -> Microsoft.Extensions.DependencyInjection.IServiceCollection! +OpenTelemetry.OpenTelemetryBuilder.WithMetrics() -> OpenTelemetry.OpenTelemetryBuilder! +OpenTelemetry.OpenTelemetryBuilder.WithMetrics(System.Action! configure) -> OpenTelemetry.OpenTelemetryBuilder! +OpenTelemetry.OpenTelemetryBuilder.WithTracing() -> OpenTelemetry.OpenTelemetryBuilder! +OpenTelemetry.OpenTelemetryBuilder.WithTracing(System.Action! configure) -> OpenTelemetry.OpenTelemetryBuilder! OpenTelemetry.Resources.ResourceBuilder.AddDetector(System.Func! resourceDetectorFactory) -> OpenTelemetry.Resources.ResourceBuilder! -static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! -static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! -static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! +OpenTelemetry.Trace.TracerProviderBuilderBase.ConfigureBuilder(System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! +OpenTelemetry.Trace.TracerProviderBuilderBase.ConfigureServices(System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! +OpenTelemetry.OpenTelemetryServiceCollectionExtensions +static OpenTelemetry.OpenTelemetryServiceCollectionExtensions.AddOpenTelemetry(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> OpenTelemetry.OpenTelemetryBuilder! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! -static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! -static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! OpenTelemetry.Trace.SamplingResult.TraceStateString.get -> string? OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, string! traceStateString) -> void OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, System.Collections.Generic.IEnumerable>? attributes, string? traceStateString) -> void *REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure = null) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure) -> Microsoft.Extensions.Logging.ILoggingBuilder! -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.ConfigureBuilder(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.SetSampler(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder! -static Microsoft.Extensions.DependencyInjection.TracerProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryTracing(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! -static Microsoft.Extensions.DependencyInjection.TracerProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryTracing(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! OpenTelemetry.Metrics.MetricType.LongSumNonMonotonic = 138 -> OpenTelemetry.Metrics.MetricType diff --git a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt index a5968754802..65a0375525d 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt @@ -1,5 +1,3 @@ -Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions -Microsoft.Extensions.DependencyInjection.TracerProviderBuilderServiceCollectionExtensions OpenTelemetry.Logs.LogRecord.CategoryName.set -> void OpenTelemetry.Logs.LogRecord.EventId.set -> void OpenTelemetry.Logs.LogRecord.Exception.set -> void @@ -14,27 +12,30 @@ OpenTelemetry.Metrics.HistogramConfiguration OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void +OpenTelemetry.Metrics.MeterProviderBuilderBase.ConfigureBuilder(System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! +OpenTelemetry.Metrics.MeterProviderBuilderBase.ConfigureServices(System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMinMaxValues(out double min, out double max) -> bool +OpenTelemetry.OpenTelemetryBuilder +OpenTelemetry.OpenTelemetryBuilder.ConfigureResource(System.Action! configure) -> OpenTelemetry.OpenTelemetryBuilder! +OpenTelemetry.OpenTelemetryBuilder.Services.get -> Microsoft.Extensions.DependencyInjection.IServiceCollection! +OpenTelemetry.OpenTelemetryBuilder.WithMetrics() -> OpenTelemetry.OpenTelemetryBuilder! +OpenTelemetry.OpenTelemetryBuilder.WithMetrics(System.Action! configure) -> OpenTelemetry.OpenTelemetryBuilder! +OpenTelemetry.OpenTelemetryBuilder.WithTracing() -> OpenTelemetry.OpenTelemetryBuilder! +OpenTelemetry.OpenTelemetryBuilder.WithTracing(System.Action! configure) -> OpenTelemetry.OpenTelemetryBuilder! OpenTelemetry.Resources.ResourceBuilder.AddDetector(System.Func! resourceDetectorFactory) -> OpenTelemetry.Resources.ResourceBuilder! -static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! -static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! -static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! +OpenTelemetry.Trace.TracerProviderBuilderBase.ConfigureBuilder(System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! +OpenTelemetry.Trace.TracerProviderBuilderBase.ConfigureServices(System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! +OpenTelemetry.OpenTelemetryServiceCollectionExtensions +static OpenTelemetry.OpenTelemetryServiceCollectionExtensions.AddOpenTelemetry(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> OpenTelemetry.OpenTelemetryBuilder! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! -static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! -static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! OpenTelemetry.Trace.SamplingResult.TraceStateString.get -> string? OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, string! traceStateString) -> void OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, System.Collections.Generic.IEnumerable>? attributes, string? traceStateString) -> void *REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure = null) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure) -> Microsoft.Extensions.Logging.ILoggingBuilder! -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.ConfigureBuilder(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.SetSampler(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder! -static Microsoft.Extensions.DependencyInjection.TracerProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryTracing(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! -static Microsoft.Extensions.DependencyInjection.TracerProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryTracing(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! OpenTelemetry.Metrics.MetricType.LongSumNonMonotonic = 138 -> OpenTelemetry.Metrics.MetricType diff --git a/src/OpenTelemetry/AssemblyInfo.cs b/src/OpenTelemetry/AssemblyInfo.cs index c5d345fb6ae..38bc9f164dd 100644 --- a/src/OpenTelemetry/AssemblyInfo.cs +++ b/src/OpenTelemetry/AssemblyInfo.cs @@ -21,6 +21,5 @@ [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.Tests" + AssemblyInfo.PublicKey)] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2" + AssemblyInfo.MoqPublicKey)] [assembly: InternalsVisibleTo("Benchmarks" + AssemblyInfo.PublicKey)] diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index f9a7f3013e4..1a3e32517c8 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -7,6 +7,11 @@ `AddEnvironmentVariableDetector` extension (Logs) ([#3889](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3889)) +* Refactored `AddInstrumentation`, `ConfigureServices` and `ConfigureBuilder` + APIs into the OpenTelemetry.Extensions.DependencyInjection package and added + the `IServiceCollection.AddOpenTelemetry` API + ([#3923](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3923)) + ## 1.4.0-beta.3 Released 2022-Nov-07 diff --git a/src/OpenTelemetry/Internal/Builder/ProviderBuilderServiceCollectionCallbackHelper.cs b/src/OpenTelemetry/Internal/Builder/ProviderBuilderServiceCollectionCallbackHelper.cs deleted file mode 100644 index 0c6c088c50a..00000000000 --- a/src/OpenTelemetry/Internal/Builder/ProviderBuilderServiceCollectionCallbackHelper.cs +++ /dev/null @@ -1,82 +0,0 @@ -// -// 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. -// - -#nullable enable - -using System.Diagnostics; -using Microsoft.Extensions.DependencyInjection; - -namespace OpenTelemetry; - -internal static class ProviderBuilderServiceCollectionCallbackHelper - where TState : ProviderBuilderState -{ - public static IServiceCollection RegisterConfigureBuilderCallback( - IServiceCollection services, - Action configure) - { - Debug.Assert(configure != null, "configure was null"); - - return RegisterConfigureStateCallback( - services, - (sp, state) => configure!(sp, state.Builder)); - } - - public static IServiceCollection RegisterConfigureStateCallback( - IServiceCollection services, - Action configure) - { - Debug.Assert(services != null, "services was null"); - Debug.Assert(configure != null, "configure was null"); - - return services!.AddSingleton( - new ConfigureProviderBuilderStateCallbackRegistration(configure!)); - } - - public static void InvokeRegisteredConfigureStateCallbacks( - IServiceProvider serviceProvider, - TState state) - { - Debug.Assert(serviceProvider != null, "serviceProvider was null"); - Debug.Assert(state != null, "state was null"); - - var callbackRegistrations = serviceProvider!.GetServices(); - - foreach (var callbackRegistration in callbackRegistrations) - { - callbackRegistration.Configure(serviceProvider!, state!); - } - } - - private sealed class ConfigureProviderBuilderStateCallbackRegistration - { - private readonly Action configure; - - public ConfigureProviderBuilderStateCallbackRegistration( - Action configure) - { - this.configure = configure; - } - - public void Configure(IServiceProvider serviceProvider, TState state) - { - Debug.Assert(serviceProvider != null, "serviceProvider was null"); - Debug.Assert(state != null, "state was null"); - - this.configure(serviceProvider!, state!); - } - } -} diff --git a/src/OpenTelemetry/Internal/Builder/ProviderBuilderServiceCollectionExtensions.cs b/src/OpenTelemetry/Internal/Builder/ProviderBuilderServiceCollectionExtensions.cs index fb2a3c06301..13db86eff8f 100644 --- a/src/OpenTelemetry/Internal/Builder/ProviderBuilderServiceCollectionExtensions.cs +++ b/src/OpenTelemetry/Internal/Builder/ProviderBuilderServiceCollectionExtensions.cs @@ -19,6 +19,7 @@ using System.Diagnostics; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection.Extensions; +using OpenTelemetry; using OpenTelemetry.Internal; using OpenTelemetry.Metrics; using OpenTelemetry.Trace; @@ -29,28 +30,32 @@ internal static class ProviderBuilderServiceCollectionExtensions { public static IServiceCollection AddOpenTelemetryMeterProviderBuilderServices(this IServiceCollection services) { - services.AddOpenTelemetryProviderBuilderServices(); + Debug.Assert(services != null, "services was null"); - services.TryAddSingleton(); - services.RegisterOptionsFactory(configuration => new MetricReaderOptions(configuration)); + services!.TryAddSingleton(); + services!.RegisterOptionsFactory(configuration => new MetricReaderOptions(configuration)); - return services; + return services!; } public static IServiceCollection AddOpenTelemetryTracerProviderBuilderServices(this IServiceCollection services) { - services.AddOpenTelemetryProviderBuilderServices(); + Debug.Assert(services != null, "services was null"); - services.TryAddSingleton(); - services.RegisterOptionsFactory(configuration => new BatchExportActivityProcessorOptions(configuration)); + services!.TryAddSingleton(); + services!.RegisterOptionsFactory(configuration => new BatchExportActivityProcessorOptions(configuration)); - return services; + return services!; } - private static IServiceCollection AddOpenTelemetryProviderBuilderServices(this IServiceCollection services) + public static IServiceCollection AddOpenTelemetrySharedProviderBuilderServices(this IServiceCollection services) { Debug.Assert(services != null, "services was null"); + // Accessing Sdk class is just to trigger its static ctor, + // which sets default Propagators and default Activity Id format + _ = Sdk.SuppressInstrumentation; + services.AddOptions(); // Note: When using a host builder IConfiguration is automatically @@ -58,7 +63,8 @@ private static IServiceCollection AddOpenTelemetryProviderBuilderServices(this I // Sdk.Create* style or when manually creating a ServiceCollection. The // point of this registration is to make IConfiguration available in // those cases. - services!.TryAddSingleton(sp => new ConfigurationBuilder().AddEnvironmentVariables().Build()); + services!.TryAddSingleton( + sp => new ConfigurationBuilder().AddEnvironmentVariables().Build()); return services!; } diff --git a/src/OpenTelemetry/Internal/Builder/ProviderBuilderState.cs b/src/OpenTelemetry/Internal/Builder/ProviderBuilderState.cs deleted file mode 100644 index 3ff92761e95..00000000000 --- a/src/OpenTelemetry/Internal/Builder/ProviderBuilderState.cs +++ /dev/null @@ -1,105 +0,0 @@ -// -// 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. -// - -#nullable enable - -using System.Diagnostics; -using OpenTelemetry.Resources; - -namespace OpenTelemetry; - -internal abstract class ProviderBuilderState -{ - private TProvider? provider; - - protected ProviderBuilderState(IServiceProvider serviceProvider) - { - Debug.Assert(serviceProvider != null, "serviceProvider was null"); - - this.ServiceProvider = serviceProvider!; - } - - public IServiceProvider ServiceProvider { get; } - - public abstract TBuilder Builder { get; } - - public TProvider Provider - { - get => this.provider ?? throw new InvalidOperationException("Provider has not been set on state."); - } - - public List Instrumentation { get; } = new(); - - public ResourceBuilder? ResourceBuilder { get; protected set; } - - public void RegisterProvider(string providerTypeName, TProvider provider) - { - Debug.Assert(provider != null, "provider was null"); - - if (this.provider != null) - { - throw new NotSupportedException($"{providerTypeName} cannot be accessed while build is executing."); - } - - this.provider = provider; - } - - public void AddInstrumentation( - string instrumentationName, - string instrumentationVersion, - object instrumentation) - { - Debug.Assert(!string.IsNullOrWhiteSpace(instrumentationName), "instrumentationName was null or whitespace"); - Debug.Assert(!string.IsNullOrWhiteSpace(instrumentationVersion), "instrumentationVersion was null or whitespace"); - Debug.Assert(instrumentation != null, "instrumentation was null"); - - this.Instrumentation.Add( - new InstrumentationRegistration( - instrumentationName, - instrumentationVersion, - instrumentation!)); - } - - public void ConfigureResource(Action configure) - { - Debug.Assert(configure != null, "configure was null"); - - var resourceBuilder = this.ResourceBuilder ??= ResourceBuilder.CreateDefault(); - - configure!(resourceBuilder); - } - - public void SetResourceBuilder(ResourceBuilder resourceBuilder) - { - Debug.Assert(resourceBuilder != null, "resourceBuilder was null"); - - this.ResourceBuilder = resourceBuilder; - } - - internal readonly struct InstrumentationRegistration - { - public readonly string Name; - public readonly string Version; - public readonly object Instance; - - internal InstrumentationRegistration(string name, string version, object instance) - { - this.Name = name; - this.Version = version; - this.Instance = instance; - } - } -} diff --git a/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderBase.cs b/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderBase.cs index f63284a74e4..4b75d85acff 100644 --- a/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderBase.cs +++ b/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderBase.cs @@ -16,299 +16,147 @@ #nullable enable -using System.Diagnostics; -using System.Diagnostics.Metrics; -using System.Text.RegularExpressions; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using OpenTelemetry.Internal; -using OpenTelemetry.Resources; -using CallbackHelper = OpenTelemetry.ProviderBuilderServiceCollectionCallbackHelper< - OpenTelemetry.Metrics.MeterProviderBuilderSdk, - OpenTelemetry.Metrics.MeterProviderSdk, - OpenTelemetry.Metrics.MeterProviderBuilderState>; +namespace OpenTelemetry.Metrics; -namespace OpenTelemetry.Metrics +/// +/// Contains methods for building instances. +/// +public class MeterProviderBuilderBase : MeterProviderBuilder, IMeterProviderBuilder { - /// - /// Contains methods for building instances. - /// - public abstract class MeterProviderBuilderBase : MeterProviderBuilder, IDeferredMeterProviderBuilder - { - internal readonly MeterProviderBuilderState? State; - private const string DefaultInstrumentationVersion = "1.0.0.0"; + private readonly bool allowBuild; + private IServiceCollection? services; - private readonly bool ownsServices; - private IServiceCollection? services; - - // This ctor is for a builder created from MeterProviderBuilderState which - // happens after the service provider has been created. - internal MeterProviderBuilderBase(MeterProviderBuilderState state) - { - Debug.Assert(state != null, "state was null"); + public MeterProviderBuilderBase() + { + var services = new ServiceCollection(); - this.State = state; - } + services + .AddOpenTelemetrySharedProviderBuilderServices() + .AddOpenTelemetryMeterProviderBuilderServices() + .TryAddSingleton( + sp => throw new NotSupportedException("Self-contained MeterProvider cannot be accessed using the application IServiceProvider call Build instead.")); - // This ctor is for ConfigureOpenTelemetryMetrics + - // AddOpenTelemetryMetrics scenarios where the builder is bound to an - // external service collection. - internal MeterProviderBuilderBase(IServiceCollection services) - { - Guard.ThrowIfNull(services); + services.ConfigureOpenTelemetryMeterProvider((sp, builder) => this.services = null); - services.AddOpenTelemetryMeterProviderBuilderServices(); - services.TryAddSingleton(sp => new MeterProviderSdk(sp, ownsServiceProvider: false)); + this.services = services; - this.services = services; - this.ownsServices = false; - } + this.allowBuild = true; + } - // This ctor is for Sdk.CreateMeterProviderBuilder where the builder - // owns its services and service provider. - protected MeterProviderBuilderBase() - { - var services = new ServiceCollection(); + internal MeterProviderBuilderBase(IServiceCollection services) + { + Guard.ThrowIfNull(services); - services.AddOpenTelemetryMeterProviderBuilderServices(); - services.AddSingleton( - sp => throw new NotSupportedException("External MeterProvider created through Sdk.CreateMeterProviderBuilder cannot be accessed using service provider.")); + services + .AddOpenTelemetryMeterProviderBuilderServices() + .TryAddSingleton(sp => new MeterProviderSdk(sp, ownsServiceProvider: false)); - this.services = services; - this.ownsServices = true; - } + services.ConfigureOpenTelemetryMeterProvider((sp, builder) => this.services = null); - /// - public override MeterProviderBuilder AddInstrumentation(Func instrumentationFactory) - { - Guard.ThrowIfNull(instrumentationFactory); + this.services = services; - return this.AddInstrumentation((sp) => instrumentationFactory()); - } + this.allowBuild = false; + } - /// - public override MeterProviderBuilder AddMeter(params string[] names) - { - Guard.ThrowIfNull(names); + /// + MeterProvider? IMeterProviderBuilder.Provider => null; - return this.ConfigureState((sp, state) => state.AddMeter(names)); - } + /// + public override MeterProviderBuilder AddInstrumentation(Func instrumentationFactory) + { + Guard.ThrowIfNull(instrumentationFactory); - /// - MeterProviderBuilder IDeferredMeterProviderBuilder.Configure( - Action configure) + this.ConfigureBuilder((sp, builder) => { - Guard.ThrowIfNull(configure); - - if (this.State != null) - { - configure(this.State.ServiceProvider, this); - } - else - { - this.ConfigureServices(services - => CallbackHelper.RegisterConfigureBuilderCallback(services, configure)); - } - - return this; - } + builder.AddInstrumentation(instrumentationFactory); + }); - internal MeterProviderBuilder AddInstrumentation() - where T : class - { - this.TryAddSingleton(); - this.AddInstrumentation((sp) => sp.GetRequiredService()); + return this; + } - return this; - } + /// + public override MeterProviderBuilder AddMeter(params string[] names) + { + Guard.ThrowIfNull(names); - internal MeterProviderBuilder AddReader() - where T : MetricReader + this.ConfigureBuilder((sp, builder) => { - this.TryAddSingleton(); - this.ConfigureState((sp, state) => state.AddReader(sp.GetRequiredService())); - - return this; - } + builder.AddMeter(names); + }); - internal MeterProviderBuilder AddReader(MetricReader reader) - { - Guard.ThrowIfNull(reader); + return this; + } - return this.ConfigureState((sp, state) => state.AddReader(reader)); - } + /// + public MeterProviderBuilder ConfigureBuilder(Action configure) + { + var services = this.services; - internal MeterProviderBuilder AddView(string instrumentName, string name) + if (services == null) { - if (!MeterProviderBuilderSdk.IsValidInstrumentName(name)) - { - throw new ArgumentException($"Custom view name {name} is invalid.", nameof(name)); - } - - if (instrumentName.IndexOf('*') != -1) - { - throw new ArgumentException( - $"Instrument selection criteria is invalid. Instrument name '{instrumentName}' " + - $"contains a wildcard character. This is not allowed when using a view to " + - $"rename a metric stream as it would lead to conflicting metric stream names.", - nameof(instrumentName)); - } - - return this.AddView( - instrumentName, - new MetricStreamConfiguration - { - Name = name, - }); + throw new NotSupportedException("Builder cannot be configured during MeterProvider construction."); } - internal MeterProviderBuilder AddView(string instrumentName, MetricStreamConfiguration metricStreamConfiguration) - { - Guard.ThrowIfNullOrWhitespace(instrumentName); - Guard.ThrowIfNull(metricStreamConfiguration); - - if (metricStreamConfiguration.Name != null && instrumentName.IndexOf('*') != -1) - { - throw new ArgumentException( - $"Instrument selection criteria is invalid. Instrument name '{instrumentName}' " + - $"contains a wildcard character. This is not allowed when using a view to " + - $"rename a metric stream as it would lead to conflicting metric stream names.", - nameof(instrumentName)); - } - - if (instrumentName.IndexOf('*') != -1) - { - var pattern = '^' + Regex.Escape(instrumentName).Replace("\\*", ".*"); - var regex = new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase); - return this.AddView(instrument => regex.IsMatch(instrument.Name) ? metricStreamConfiguration : null); - } - else - { - return this.AddView(instrument => instrument.Name.Equals(instrumentName, StringComparison.OrdinalIgnoreCase) ? metricStreamConfiguration : null); - } - } + services.ConfigureOpenTelemetryMeterProvider(configure); - internal MeterProviderBuilder AddView(Func viewConfig) - { - Guard.ThrowIfNull(viewConfig); + return this; + } - this.ConfigureState((sp, state) => state.AddView(viewConfig)); + /// + public MeterProviderBuilder ConfigureServices(Action configure) + { + Guard.ThrowIfNull(configure); - return this; - } + var services = this.services; - internal MeterProviderBuilder ConfigureResource(Action configure) + if (services == null) { - Guard.ThrowIfNull(configure); - - return this.ConfigureState((sp, state) => state.ConfigureResource(configure)); + throw new NotSupportedException("Services cannot be configured during MeterProvider construction."); } - internal MeterProviderBuilder ConfigureServices(Action configure) - { - Guard.ThrowIfNull(configure); + configure(services); - var services = this.services; - - if (services == null) - { - throw new NotSupportedException("Services cannot be configured after ServiceProvider has been created."); - } - - configure(services); + return this; + } - return this; - } + /// + MeterProviderBuilder IDeferredMeterProviderBuilder.Configure(Action configure) + => this.ConfigureBuilder(configure); - internal MeterProvider InvokeBuild() - => this.Build(); + internal MeterProvider InvokeBuild() + => this.Build(); - internal MeterProviderBuilder SetMaxMetricStreams(int maxMetricStreams) + /// + /// Run the configured actions to initialize the . + /// + /// . + protected MeterProvider Build() + { + if (!this.allowBuild) { - Guard.ThrowIfOutOfRange(maxMetricStreams, min: 1); - - return this.ConfigureState((sp, state) => state.MaxMetricStreams = maxMetricStreams); + throw new NotSupportedException("A MeterProviderBuilder bound to external service cannot be built directly. Access the MeterProvider using the application IServiceProvider instead."); } - internal MeterProviderBuilder SetMaxMetricPointsPerMetricStream(int maxMetricPointsPerMetricStream) - { - Guard.ThrowIfOutOfRange(maxMetricPointsPerMetricStream, min: 1); - - return this.ConfigureState((sp, state) => state.MaxMetricPointsPerMetricStream = maxMetricPointsPerMetricStream); - } + var services = this.services; - internal MeterProviderBuilder SetResourceBuilder(ResourceBuilder resourceBuilder) + if (services == null) { - Guard.ThrowIfNull(resourceBuilder); - - return this.ConfigureState((sp, state) => state.SetResourceBuilder(resourceBuilder)); + throw new NotSupportedException("MeterProviderBuilder build method cannot be called multiple times."); } - /// - /// Run the configured actions to initialize the . - /// - /// . - protected MeterProvider Build() - { - if (!this.ownsServices || this.State != null) - { - throw new NotSupportedException("Build cannot be called directly on MeterProviderBuilder tied to external services."); - } - - var services = this.services; - - if (services == null) - { - throw new NotSupportedException("MeterProviderBuilder build method cannot be called multiple times."); - } - - this.services = null; + this.services = null; #if DEBUG - bool validateScopes = true; + bool validateScopes = true; #else - bool validateScopes = false; + bool validateScopes = false; #endif - var serviceProvider = services.BuildServiceProvider(validateScopes); - - return new MeterProviderSdk(serviceProvider, ownsServiceProvider: true); - } - - private MeterProviderBuilder AddInstrumentation(Func instrumentationFactory) - where T : class - { - this.ConfigureState((sp, state) - => state.AddInstrumentation( - typeof(T).Name, - typeof(T).Assembly.GetName().Version?.ToString() ?? DefaultInstrumentationVersion, - instrumentationFactory(sp))); + var serviceProvider = services.BuildServiceProvider(validateScopes); - return this; - } - - private MeterProviderBuilder ConfigureState(Action configure) - { - Debug.Assert(configure != null, "configure was null"); - - if (this.State != null) - { - configure!(this.State.ServiceProvider, this.State); - } - else - { - this.ConfigureServices(services => CallbackHelper.RegisterConfigureStateCallback(services, configure!)); - } - - return this; - } - - private void TryAddSingleton() - where T : class - { - var services = this.services; - - services?.TryAddSingleton(); - } + return new MeterProviderSdk(serviceProvider, ownsServiceProvider: true); } } diff --git a/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderExtensions.cs b/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderExtensions.cs index a1f2e4408e2..1d1344480b5 100644 --- a/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderExtensions.cs +++ b/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderExtensions.cs @@ -17,7 +17,10 @@ #nullable enable using System.Diagnostics.Metrics; +using System.Text.RegularExpressions; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using OpenTelemetry.Internal; using OpenTelemetry.Resources; namespace OpenTelemetry.Metrics @@ -27,27 +30,6 @@ namespace OpenTelemetry.Metrics /// public static class MeterProviderBuilderExtensions { - /// - /// Adds instrumentation to the provider. - /// - /// - /// Note: The type specified by will be - /// registered as a singleton service into application services. - /// - /// Instrumentation type. - /// . - /// The supplied for chaining. - public static MeterProviderBuilder AddInstrumentation(this MeterProviderBuilder meterProviderBuilder) - where T : class - { - if (meterProviderBuilder is MeterProviderBuilderBase meterProviderBuilderBase) - { - meterProviderBuilderBase.AddInstrumentation(); - } - - return meterProviderBuilder; - } - /// /// Adds a reader to the provider. /// @@ -56,10 +38,15 @@ public static MeterProviderBuilder AddInstrumentation(this MeterProviderBuild /// The supplied for chaining. public static MeterProviderBuilder AddReader(this MeterProviderBuilder meterProviderBuilder, MetricReader reader) { - if (meterProviderBuilder is MeterProviderBuilderBase meterProviderBuilderBase) + Guard.ThrowIfNull(reader); + + meterProviderBuilder.ConfigureBuilder((sp, builder) => { - meterProviderBuilderBase.AddReader(reader); - } + if (builder is MeterProviderBuilderSdk meterProviderBuilderSdk) + { + meterProviderBuilderSdk.AddReader(reader); + } + }); return meterProviderBuilder; } @@ -77,10 +64,15 @@ public static MeterProviderBuilder AddReader(this MeterProviderBuilder meterProv public static MeterProviderBuilder AddReader(this MeterProviderBuilder meterProviderBuilder) where T : MetricReader { - if (meterProviderBuilder is MeterProviderBuilderBase meterProviderBuilderBase) + meterProviderBuilder.ConfigureServices(services => services.TryAddSingleton()); + + meterProviderBuilder.ConfigureBuilder((sp, builder) => { - meterProviderBuilderBase.AddReader(); - } + if (builder is MeterProviderBuilderSdk meterProviderBuilderSdk) + { + meterProviderBuilderSdk.AddReader(sp.GetRequiredService()); + } + }); return meterProviderBuilder; } @@ -96,11 +88,22 @@ public static MeterProviderBuilder AddReader(this MeterProviderBuilder meterP /// The supplied for chaining. public static MeterProviderBuilder AddView(this MeterProviderBuilder meterProviderBuilder, string instrumentName, string name) { - if (meterProviderBuilder is MeterProviderBuilderBase meterProviderBuilderBase) + if (!MeterProviderBuilderSdk.IsValidInstrumentName(name)) { - meterProviderBuilderBase.AddView(instrumentName, name); + throw new ArgumentException($"Custom view name {name} is invalid.", nameof(name)); } + if (instrumentName.IndexOf('*') != -1) + { + throw new ArgumentException( + $"Instrument selection criteria is invalid. Instrument name '{instrumentName}' " + + $"contains a wildcard character. This is not allowed when using a view to " + + $"rename a metric stream as it would lead to conflicting metric stream names.", + nameof(instrumentName)); + } + + meterProviderBuilder.AddView(instrumentName, new MetricStreamConfiguration { Name = name }); + return meterProviderBuilder; } @@ -115,11 +118,35 @@ public static MeterProviderBuilder AddView(this MeterProviderBuilder meterProvid /// The supplied for chaining. public static MeterProviderBuilder AddView(this MeterProviderBuilder meterProviderBuilder, string instrumentName, MetricStreamConfiguration metricStreamConfiguration) { - if (meterProviderBuilder is MeterProviderBuilderBase meterProviderBuilderBase) + Guard.ThrowIfNullOrWhitespace(instrumentName); + Guard.ThrowIfNull(metricStreamConfiguration); + + if (metricStreamConfiguration.Name != null && instrumentName.IndexOf('*') != -1) { - meterProviderBuilderBase.AddView(instrumentName, metricStreamConfiguration); + throw new ArgumentException( + $"Instrument selection criteria is invalid. Instrument name '{instrumentName}' " + + $"contains a wildcard character. This is not allowed when using a view to " + + $"rename a metric stream as it would lead to conflicting metric stream names.", + nameof(instrumentName)); } + meterProviderBuilder.ConfigureBuilder((sp, builder) => + { + if (builder is MeterProviderBuilderSdk meterProviderBuilderSdk) + { + if (instrumentName.IndexOf('*') != -1) + { + var pattern = '^' + Regex.Escape(instrumentName).Replace("\\*", ".*"); + var regex = new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase); + meterProviderBuilderSdk.AddView(instrument => regex.IsMatch(instrument.Name) ? metricStreamConfiguration : null); + } + else + { + meterProviderBuilderSdk.AddView(instrument => instrument.Name.Equals(instrumentName, StringComparison.OrdinalIgnoreCase) ? metricStreamConfiguration : null); + } + } + }); + return meterProviderBuilder; } @@ -141,10 +168,15 @@ public static MeterProviderBuilder AddView(this MeterProviderBuilder meterProvid /// The supplied for chaining. public static MeterProviderBuilder AddView(this MeterProviderBuilder meterProviderBuilder, Func viewConfig) { - if (meterProviderBuilder is MeterProviderBuilderBase meterProviderBuilderBase) + Guard.ThrowIfNull(viewConfig); + + meterProviderBuilder.ConfigureBuilder((sp, builder) => { - meterProviderBuilderBase.AddView(viewConfig); - } + if (builder is MeterProviderBuilderSdk meterProviderBuilderSdk) + { + meterProviderBuilderSdk.AddView(viewConfig); + } + }); return meterProviderBuilder; } @@ -165,10 +197,15 @@ public static MeterProviderBuilder AddView(this MeterProviderBuilder meterProvid /// The supplied for chaining. public static MeterProviderBuilder SetMaxMetricStreams(this MeterProviderBuilder meterProviderBuilder, int maxMetricStreams) { - if (meterProviderBuilder is MeterProviderBuilderBase meterProviderBuilderBase) + Guard.ThrowIfOutOfRange(maxMetricStreams, min: 1); + + meterProviderBuilder.ConfigureBuilder((sp, builder) => { - meterProviderBuilderBase.SetMaxMetricStreams(maxMetricStreams); - } + if (builder is MeterProviderBuilderSdk meterProviderBuilderSdk) + { + meterProviderBuilderSdk.SetMaxMetricStreams(maxMetricStreams); + } + }); return meterProviderBuilder; } @@ -188,10 +225,15 @@ public static MeterProviderBuilder SetMaxMetricStreams(this MeterProviderBuilder /// The supplied for chaining. public static MeterProviderBuilder SetMaxMetricPointsPerMetricStream(this MeterProviderBuilder meterProviderBuilder, int maxMetricPointsPerMetricStream) { - if (meterProviderBuilder is MeterProviderBuilderBase meterProviderBuilderBase) + Guard.ThrowIfOutOfRange(maxMetricPointsPerMetricStream, min: 1); + + meterProviderBuilder.ConfigureBuilder((sp, builder) => { - meterProviderBuilderBase.SetMaxMetricPointsPerMetricStream(maxMetricPointsPerMetricStream); - } + if (builder is MeterProviderBuilderSdk meterProviderBuilderSdk) + { + meterProviderBuilderSdk.SetMaxMetricPointsPerMetricStream(maxMetricPointsPerMetricStream); + } + }); return meterProviderBuilder; } @@ -207,10 +249,13 @@ public static MeterProviderBuilder SetMaxMetricPointsPerMetricStream(this MeterP /// The supplied for chaining. public static MeterProviderBuilder SetResourceBuilder(this MeterProviderBuilder meterProviderBuilder, ResourceBuilder resourceBuilder) { - if (meterProviderBuilder is MeterProviderBuilderBase meterProviderBuilderBase) + meterProviderBuilder.ConfigureBuilder((sp, builder) => { - meterProviderBuilderBase.SetResourceBuilder(resourceBuilder); - } + if (builder is MeterProviderBuilderSdk meterProviderBuilderSdk) + { + meterProviderBuilderSdk.SetResourceBuilder(resourceBuilder); + } + }); return meterProviderBuilder; } @@ -224,53 +269,13 @@ public static MeterProviderBuilder SetResourceBuilder(this MeterProviderBuilder /// The supplied for chaining. public static MeterProviderBuilder ConfigureResource(this MeterProviderBuilder meterProviderBuilder, Action configure) { - if (meterProviderBuilder is MeterProviderBuilderBase meterProviderBuilderBase) - { - meterProviderBuilderBase.ConfigureResource(configure); - } - - return meterProviderBuilder; - } - - /// - /// Register a callback action to configure the where metric services are configured. - /// - /// - /// Note: Metric services are only available during the application - /// configuration phase. - /// - /// . - /// Configuration callback. - /// The supplied for chaining. - public static MeterProviderBuilder ConfigureServices( - this MeterProviderBuilder meterProviderBuilder, - Action configure) - { - if (meterProviderBuilder is MeterProviderBuilderBase meterProviderBuilderBase) + meterProviderBuilder.ConfigureBuilder((sp, builder) => { - meterProviderBuilderBase.ConfigureServices(configure); - } - - return meterProviderBuilder; - } - - /// - /// Register a callback action to configure the once the application is available. - /// - /// . - /// Configuration callback. - /// The supplied for chaining. - public static MeterProviderBuilder ConfigureBuilder( - this MeterProviderBuilder meterProviderBuilder, - Action configure) - { - if (meterProviderBuilder is IDeferredMeterProviderBuilder deferredMeterProviderBuilder) - { - deferredMeterProviderBuilder.Configure(configure); - } + if (builder is MeterProviderBuilderSdk meterProviderBuilderSdk) + { + meterProviderBuilderSdk.ConfigureResource(configure); + } + }); return meterProviderBuilder; } diff --git a/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderSdk.cs b/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderSdk.cs index b8db1029f74..bf703f5b38d 100644 --- a/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderSdk.cs +++ b/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderSdk.cs @@ -16,29 +16,50 @@ #nullable enable +using System.Diagnostics; +using System.Diagnostics.Metrics; using System.Text.RegularExpressions; using Microsoft.Extensions.DependencyInjection; +using OpenTelemetry.Internal; +using OpenTelemetry.Resources; namespace OpenTelemetry.Metrics { - internal sealed class MeterProviderBuilderSdk : MeterProviderBuilderBase + /// + /// Stores state used to build a . + /// + internal sealed class MeterProviderBuilderSdk : MeterProviderBuilder, IMeterProviderBuilder { + public const int MaxMetricsDefault = 1000; + public const int MaxMetricPointsPerMetricDefault = 2000; + private const string DefaultInstrumentationVersion = "1.0.0.0"; + private static readonly Regex InstrumentNameRegex = new( @"^[a-z][a-z0-9-._]{0,62}$", RegexOptions.IgnoreCase | RegexOptions.Compiled); - public MeterProviderBuilderSdk() - { - } + private readonly IServiceProvider serviceProvider; + private MeterProviderSdk? meterProvider; - public MeterProviderBuilderSdk(IServiceCollection services) - : base(services) + public MeterProviderBuilderSdk(IServiceProvider serviceProvider) { + this.serviceProvider = serviceProvider; } - public MeterProviderBuilderSdk(MeterProviderBuilderState state) - : base(state) - { - } + public List Instrumentation { get; } = new(); + + public ResourceBuilder? ResourceBuilder { get; private set; } + + public MeterProvider? Provider => this.meterProvider; + + public List Readers { get; } = new(); + + public List MeterSources { get; } = new(); + + public List> ViewConfigs { get; } = new(); + + public int MaxMetricStreams { get; private set; } = MaxMetricsDefault; + + public int MaxMetricPointsPerMetricStream { get; private set; } = MaxMetricPointsPerMetricDefault; /// /// Returns whether the given instrument name is valid according to the specification. @@ -72,5 +93,143 @@ public static bool IsValidViewName(string customViewName) return InstrumentNameRegex.IsMatch(customViewName); } + + public void RegisterProvider(MeterProviderSdk meterProvider) + { + Debug.Assert(meterProvider != null, "meterProvider was null"); + + if (this.meterProvider != null) + { + throw new NotSupportedException("MeterProvider cannot be accessed while build is executing."); + } + + this.meterProvider = meterProvider; + } + + public override MeterProviderBuilder AddInstrumentation( + Func instrumentationFactory) + { + Debug.Assert(instrumentationFactory != null, "instrumentationFactory was null"); + + return this.AddInstrumentation( + typeof(TInstrumentation).Name, + typeof(TInstrumentation).Assembly.GetName().Version?.ToString() ?? DefaultInstrumentationVersion, + instrumentationFactory!()); + } + + public MeterProviderBuilder AddInstrumentation( + string instrumentationName, + string instrumentationVersion, + object instrumentation) + { + Debug.Assert(!string.IsNullOrWhiteSpace(instrumentationName), "instrumentationName was null or whitespace"); + Debug.Assert(!string.IsNullOrWhiteSpace(instrumentationVersion), "instrumentationVersion was null or whitespace"); + Debug.Assert(instrumentation != null, "instrumentation was null"); + + this.Instrumentation.Add( + new InstrumentationRegistration( + instrumentationName, + instrumentationVersion, + instrumentation!)); + + return this; + } + + public MeterProviderBuilder ConfigureResource(Action configure) + { + Debug.Assert(configure != null, "configure was null"); + + var resourceBuilder = this.ResourceBuilder ??= ResourceBuilder.CreateDefault(); + + configure!(resourceBuilder); + + return this; + } + + public MeterProviderBuilder SetResourceBuilder(ResourceBuilder resourceBuilder) + { + Debug.Assert(resourceBuilder != null, "resourceBuilder was null"); + + this.ResourceBuilder = resourceBuilder; + + return this; + } + + public override MeterProviderBuilder AddMeter(params string[] names) + { + Debug.Assert(names != null, "names was null"); + + foreach (var name in names!) + { + Guard.ThrowIfNullOrWhitespace(name); + + this.MeterSources.Add(name); + } + + return this; + } + + public MeterProviderBuilder AddReader(MetricReader reader) + { + Debug.Assert(reader != null, "reader was null"); + + this.Readers.Add(reader!); + + return this; + } + + public MeterProviderBuilder AddView(Func viewConfig) + { + Debug.Assert(viewConfig != null, "viewConfig was null"); + + this.ViewConfigs.Add(viewConfig!); + + return this; + } + + public MeterProviderBuilder SetMaxMetricStreams(int maxMetricStreams) + { + this.MaxMetricStreams = maxMetricStreams; + + return this; + } + + public MeterProviderBuilder SetMaxMetricPointsPerMetricStream(int maxMetricPointsPerMetricStream) + { + this.MaxMetricPointsPerMetricStream = maxMetricPointsPerMetricStream; + + return this; + } + + public MeterProviderBuilder ConfigureBuilder(Action configure) + { + Debug.Assert(configure != null, "configure was null"); + + configure!(this.serviceProvider, this); + + return this; + } + + public MeterProviderBuilder ConfigureServices(Action configure) + { + throw new NotSupportedException("Services cannot be configured after ServiceProvider has been created."); + } + + MeterProviderBuilder IDeferredMeterProviderBuilder.Configure(Action configure) + => this.ConfigureBuilder(configure); + + internal readonly struct InstrumentationRegistration + { + public readonly string Name; + public readonly string Version; + public readonly object Instance; + + internal InstrumentationRegistration(string name, string version, object instance) + { + this.Name = name; + this.Version = version; + this.Instance = instance; + } + } } } diff --git a/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderServiceCollectionExtensions.cs b/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderServiceCollectionExtensions.cs deleted file mode 100644 index 631c7bb1c0b..00000000000 --- a/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderServiceCollectionExtensions.cs +++ /dev/null @@ -1,76 +0,0 @@ -// -// 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. -// - -#nullable enable - -using OpenTelemetry; -using OpenTelemetry.Internal; -using OpenTelemetry.Metrics; - -namespace Microsoft.Extensions.DependencyInjection; - -/// -/// Extension methods for setting up OpenTelemetry Metrics services in an . -/// -public static class MeterProviderBuilderServiceCollectionExtensions -{ - /// - /// Configures OpenTelemetry Metrics services in the supplied . - /// - /// - /// Notes: - /// - /// A will not be created automatically - /// using this method. Either use the - /// IServiceCollection.AddOpenTelemetryMetrics extension in the - /// OpenTelemetry.Extensions.Hosting package or access the through the application to begin collecting traces. - /// This is safe to be called multiple times and by library authors. - /// Only a single will be created for a given - /// . - /// - /// - /// The to add services to. - /// The so that additional calls can be chained. - public static IServiceCollection ConfigureOpenTelemetryMetrics(this IServiceCollection services) - => ConfigureOpenTelemetryMetrics(services, (b) => { }); - - /// - /// Configures OpenTelemetry Metrics services in the supplied . - /// - /// - /// The to add services to. - /// Callback action to configure the . - /// The so that additional calls can be chained. - public static IServiceCollection ConfigureOpenTelemetryMetrics(this IServiceCollection services, Action configure) - { - Guard.ThrowIfNull(services); - Guard.ThrowIfNull(configure); - - // Accessing Sdk class is just to trigger its static ctor, - // which sets default Propagators and default Activity Id format - _ = Sdk.SuppressInstrumentation; - - // Note: We need to create a builder even if there is no configure - // because the builder will register services - var builder = new MeterProviderBuilderSdk(services); - - configure(builder); - - return services; - } -} diff --git a/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderState.cs b/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderState.cs deleted file mode 100644 index a71d046cdd0..00000000000 --- a/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderState.cs +++ /dev/null @@ -1,79 +0,0 @@ -// -// 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. -// - -#nullable enable - -using System.Diagnostics; -using System.Diagnostics.Metrics; -using OpenTelemetry.Internal; - -namespace OpenTelemetry.Metrics -{ - /// - /// Stores state used to build a . - /// - internal sealed class MeterProviderBuilderState : ProviderBuilderState - { - public const int MaxMetricsDefault = 1000; - public const int MaxMetricPointsPerMetricDefault = 2000; - - private MeterProviderBuilderSdk? builder; - - public MeterProviderBuilderState(IServiceProvider serviceProvider) - : base(serviceProvider) - { - } - - public override MeterProviderBuilderSdk Builder - => this.builder ??= new MeterProviderBuilderSdk(this); - - public List Readers { get; } = new(); - - public List MeterSources { get; } = new(); - - public List> ViewConfigs { get; } = new(); - - public int MaxMetricStreams { get; set; } = MaxMetricsDefault; - - public int MaxMetricPointsPerMetricStream { get; set; } = MaxMetricPointsPerMetricDefault; - - public void AddMeter(params string[] names) - { - Debug.Assert(names != null, "names was null"); - - foreach (var name in names!) - { - Guard.ThrowIfNullOrWhitespace(name); - - this.MeterSources.Add(name); - } - } - - public void AddReader(MetricReader reader) - { - Debug.Assert(reader != null, "reader was null"); - - this.Readers.Add(reader!); - } - - public void AddView(Func viewConfig) - { - Debug.Assert(viewConfig != null, "viewConfig was null"); - - this.ViewConfigs.Add(viewConfig!); - } - } -} diff --git a/src/OpenTelemetry/Metrics/MeterProviderSdk.cs b/src/OpenTelemetry/Metrics/MeterProviderSdk.cs index 906d582279c..d02c34865af 100644 --- a/src/OpenTelemetry/Metrics/MeterProviderSdk.cs +++ b/src/OpenTelemetry/Metrics/MeterProviderSdk.cs @@ -23,11 +23,6 @@ using OpenTelemetry.Internal; using OpenTelemetry.Resources; -using CallbackHelper = OpenTelemetry.ProviderBuilderServiceCollectionCallbackHelper< - OpenTelemetry.Metrics.MeterProviderBuilderSdk, - OpenTelemetry.Metrics.MeterProviderSdk, - OpenTelemetry.Metrics.MeterProviderBuilderState>; - namespace OpenTelemetry.Metrics { internal sealed class MeterProviderSdk : MeterProvider @@ -50,8 +45,8 @@ internal MeterProviderSdk( { Debug.Assert(serviceProvider != null, "serviceProvider was null"); - var state = serviceProvider!.GetRequiredService(); - state.RegisterProvider(nameof(MeterProvider), this); + var state = serviceProvider!.GetRequiredService(); + state.RegisterProvider(this); this.ServiceProvider = serviceProvider!; @@ -63,9 +58,11 @@ internal MeterProviderSdk( OpenTelemetrySdkEventSource.Log.MeterProviderSdkEvent("Building MeterProvider."); - CallbackHelper.InvokeRegisteredConfigureStateCallbacks( - serviceProvider!, - state); + var configureProviderBuilders = serviceProvider!.GetServices(); + foreach (var configureProviderBuilder in configureProviderBuilders) + { + configureProviderBuilder.ConfigureBuilder(serviceProvider!, state); + } StringBuilder exportersAdded = new StringBuilder(); StringBuilder instrumentationFactoriesAdded = new StringBuilder(); diff --git a/src/OpenTelemetry/OpenTelemetry.csproj b/src/OpenTelemetry/OpenTelemetry.csproj index 5d5d8a4a32c..05afbcc9235 100644 --- a/src/OpenTelemetry/OpenTelemetry.csproj +++ b/src/OpenTelemetry/OpenTelemetry.csproj @@ -27,7 +27,7 @@ - + diff --git a/src/OpenTelemetry/OpenTelemetryBuilder.cs b/src/OpenTelemetry/OpenTelemetryBuilder.cs new file mode 100644 index 00000000000..f817e0bfe68 --- /dev/null +++ b/src/OpenTelemetry/OpenTelemetryBuilder.cs @@ -0,0 +1,154 @@ +// +// 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. +// + +#nullable enable + +using Microsoft.Extensions.DependencyInjection; +using OpenTelemetry.Internal; +using OpenTelemetry.Metrics; +using OpenTelemetry.Resources; +using OpenTelemetry.Trace; + +namespace OpenTelemetry; + +/// +/// Contains methods for configuring the OpenTelemetry SDK inside an . +/// +public class OpenTelemetryBuilder +{ + internal OpenTelemetryBuilder(IServiceCollection services) + { + Guard.ThrowIfNull(services); + + services.AddOpenTelemetrySharedProviderBuilderServices(); + + this.Services = services; + } + + /// + /// Gets the behind the builder. + /// + public IServiceCollection Services { get; } + + /// + /// Registers an action to configure the s used + /// by tracing and metrics. + /// + /// + /// Note: This is safe to be called multiple times and by library authors. + /// Each registered configuration action will be applied sequentially. + /// + /// configuration + /// action. + /// The supplied for chaining + /// calls. + public OpenTelemetryBuilder ConfigureResource( + Action configure) + { + Guard.ThrowIfNull(configure); + + this.Services.ConfigureOpenTelemetryMeterProvider( + (sp, builder) => builder.ConfigureResource(configure)); + + this.Services.ConfigureOpenTelemetryTracerProvider( + (sp, builder) => builder.ConfigureResource(configure)); + + return this; + } + + /// + /// Adds metric services into the builder. + /// + /// + /// Notes: + /// + /// A will not be created automatically + /// using this method. To begin collecting metrics either use the + /// OpenTelemetryBuilder.StartWithHost extension in the + /// OpenTelemetry.Extensions.Hosting package or access the through the application . + /// This is safe to be called multiple times and by library authors. + /// Only a single will be created for a given + /// . + /// + /// + /// The supplied for chaining + /// calls. + public OpenTelemetryBuilder WithMetrics() + => this.WithMetrics(b => { }); + + /// + /// Adds metric services into the builder. + /// + /// + /// + /// configuration callback. + /// The supplied for chaining + /// calls. + public OpenTelemetryBuilder WithMetrics(Action configure) + { + Guard.ThrowIfNull(configure); + + var builder = new MeterProviderBuilderBase(this.Services); + + configure(builder); + + return this; + } + + /// + /// Adds tracing services into the builder. + /// + /// + /// Notes: + /// + /// A will not be created automatically + /// using this method. To begin collecting traces either use the + /// OpenTelemetryBuilder.StartWithHost extension in the + /// OpenTelemetry.Extensions.Hosting package or access the through the application . + /// This is safe to be called multiple times and by library authors. + /// Only a single will be created for a given + /// . + /// + /// + /// The supplied for chaining + /// calls. + public OpenTelemetryBuilder WithTracing() + => this.WithTracing(b => { }); + + /// + /// Adds tracing services into the builder. + /// + /// + /// + /// configuration callback. + /// The supplied for chaining + /// calls. + public OpenTelemetryBuilder WithTracing(Action configure) + { + Guard.ThrowIfNull(configure); + + var builder = new TracerProviderBuilderBase(this.Services); + + configure(builder); + + return this; + } +} diff --git a/src/OpenTelemetry/OpenTelemetryServiceCollectionExtensions.cs b/src/OpenTelemetry/OpenTelemetryServiceCollectionExtensions.cs new file mode 100644 index 00000000000..2541a85f7bb --- /dev/null +++ b/src/OpenTelemetry/OpenTelemetryServiceCollectionExtensions.cs @@ -0,0 +1,55 @@ +// +// 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. +// + +#nullable enable + +using Microsoft.Extensions.DependencyInjection; +using OpenTelemetry.Metrics; +using OpenTelemetry.Trace; + +namespace OpenTelemetry; + +/// +/// Contains extension methods for registering OpenTelemetry SDK artifacts. +/// +public static class OpenTelemetryServiceCollectionExtensions +{ + /// + /// Adds OpenTelemetry SDK services into the supplied . + /// + /// + /// Notes: + /// + /// A and/or + /// will not be created automatically using this method. To begin collecting + /// traces and/or metrics either use the + /// OpenTelemetryBuilder.StartWithHost extension in the + /// OpenTelemetry.Extensions.Hosting package or access the and/or through the + /// application . + /// This is safe to be called multiple times and by library authors. + /// Only a single and/or will be created for a given . + /// + /// + /// . + /// The supplied for chaining + /// calls. + public static OpenTelemetryBuilder AddOpenTelemetry(this IServiceCollection services) + => new(services); +} diff --git a/src/OpenTelemetry/Sdk.cs b/src/OpenTelemetry/Sdk.cs index 62fb0da26d1..f903510b40c 100644 --- a/src/OpenTelemetry/Sdk.cs +++ b/src/OpenTelemetry/Sdk.cs @@ -68,7 +68,7 @@ public static void SetDefaultTextMapPropagator(TextMapPropagator textMapPropagat /// instance, which is used to build a . public static MeterProviderBuilder CreateMeterProviderBuilder() { - return new MeterProviderBuilderSdk(); + return new MeterProviderBuilderBase(); } /// @@ -81,7 +81,7 @@ public static MeterProviderBuilder CreateMeterProviderBuilder() /// instance, which is used to build a . public static TracerProviderBuilder CreateTracerProviderBuilder() { - return new TracerProviderBuilderSdk(); + return new TracerProviderBuilderBase(); } } } diff --git a/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderBase.cs b/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderBase.cs index 0ce4d3b2c28..ad9e1b9560f 100644 --- a/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderBase.cs +++ b/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderBase.cs @@ -16,279 +16,191 @@ #nullable enable -using System.Diagnostics; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using OpenTelemetry.Internal; -using OpenTelemetry.Resources; -using CallbackHelper = OpenTelemetry.ProviderBuilderServiceCollectionCallbackHelper< - OpenTelemetry.Trace.TracerProviderBuilderSdk, - OpenTelemetry.Trace.TracerProviderSdk, - OpenTelemetry.Trace.TracerProviderBuilderState>; +namespace OpenTelemetry.Trace; -namespace OpenTelemetry.Trace +/// +/// Contains methods for building instances. +/// +public class TracerProviderBuilderBase : TracerProviderBuilder, ITracerProviderBuilder { + private readonly bool allowBuild; + private IServiceCollection? services; + /// - /// Contains methods for building instances. + /// Initializes a new instance of the class. /// - public abstract class TracerProviderBuilderBase : TracerProviderBuilder, IDeferredTracerProviderBuilder + public TracerProviderBuilderBase() { - internal readonly TracerProviderBuilderState? State; - private const string DefaultInstrumentationVersion = "1.0.0.0"; + var services = new ServiceCollection(); - private readonly bool ownsServices; - private IServiceCollection? services; + services + .AddOpenTelemetrySharedProviderBuilderServices() + .AddOpenTelemetryTracerProviderBuilderServices() + .TryAddSingleton( + sp => throw new NotSupportedException("Self-contained TracerProvider cannot be accessed using the application IServiceProvider call Build instead.")); - // This ctor is for a builder created from TracerProviderBuilderState which - // happens after the service provider has been created. - internal TracerProviderBuilderBase(TracerProviderBuilderState state) - { - Debug.Assert(state != null, "state was null"); + services.ConfigureOpenTelemetryTracerProvider((sp, builder) => this.services = null); - this.State = state; - } + this.services = services; - // This ctor is for ConfigureOpenTelemetryTracing + - // AddOpenTelemetryTracing scenarios where the builder is bound to an - // external service collection. - internal TracerProviderBuilderBase(IServiceCollection services) - { - Guard.ThrowIfNull(services); + this.allowBuild = true; + } - services.AddOpenTelemetryTracerProviderBuilderServices(); - services.TryAddSingleton(sp => new TracerProviderSdk(sp, ownsServiceProvider: false)); + internal TracerProviderBuilderBase(IServiceCollection services) + { + Guard.ThrowIfNull(services); - this.services = services; - this.ownsServices = false; - } + services + .AddOpenTelemetryTracerProviderBuilderServices() + .TryAddSingleton(sp => new TracerProviderSdk(sp, ownsServiceProvider: false)); - // This ctor is for Sdk.CreateTracerProviderBuilder where the builder - // owns its services and service provider. - protected TracerProviderBuilderBase() - { - var services = new ServiceCollection(); + services.ConfigureOpenTelemetryTracerProvider((sp, builder) => this.services = null); - services.AddOpenTelemetryTracerProviderBuilderServices(); - services.AddSingleton( - sp => throw new NotSupportedException("External TracerProvider created through Sdk.CreateTracerProviderBuilder cannot be accessed using service provider.")); + this.services = services; - this.services = services; - this.ownsServices = true; - } + this.allowBuild = false; + } - /// - public override TracerProviderBuilder AddInstrumentation( - Func instrumentationFactory) - where TInstrumentation : class - { - Guard.ThrowIfNull(instrumentationFactory); + /// + TracerProvider? ITracerProviderBuilder.Provider => null; - return this.AddInstrumentation((sp) => instrumentationFactory()); - } + /// + public override TracerProviderBuilder AddInstrumentation(Func instrumentationFactory) + { + Guard.ThrowIfNull(instrumentationFactory); - /// - public override TracerProviderBuilder AddSource(params string[] names) + this.ConfigureBuilder((sp, builder) => { - Guard.ThrowIfNull(names); - - return this.ConfigureState((sp, state) => state.AddSource(names)); - } + builder.AddInstrumentation(instrumentationFactory); + }); - /// - public override TracerProviderBuilder AddLegacySource(string operationName) - { - Guard.ThrowIfNullOrWhitespace(operationName); + return this; + } - return this.ConfigureState((sp, state) => state.AddLegacySource(operationName)); - } + /// + public override TracerProviderBuilder AddSource(params string[] names) + { + Guard.ThrowIfNull(names); - /// - TracerProviderBuilder IDeferredTracerProviderBuilder.Configure( - Action configure) + this.ConfigureBuilder((sp, builder) => { - Guard.ThrowIfNull(configure); - - if (this.State != null) - { - configure(this.State.ServiceProvider, this); - } - else - { - this.ConfigureServices(services - => CallbackHelper.RegisterConfigureBuilderCallback(services, configure)); - } - - return this; - } + builder.AddSource(names); + }); - internal TracerProviderBuilder AddInstrumentation() - where T : class - { - this.TryAddSingleton(); - this.AddInstrumentation((sp) => sp.GetRequiredService()); + return this; + } - return this; - } + /// + public override TracerProviderBuilder AddLegacySource(string operationName) + { + Guard.ThrowIfNullOrWhitespace(operationName); - internal TracerProviderBuilder AddProcessor() - where T : BaseProcessor + this.ConfigureBuilder((sp, builder) => { - this.TryAddSingleton(); - this.ConfigureState((sp, state) => state.AddProcessor(sp.GetRequiredService())); + builder.AddLegacySource(operationName); + }); - return this; - } - - internal TracerProviderBuilder AddProcessor(BaseProcessor processor) - { - Guard.ThrowIfNull(processor); + return this; + } - return this.ConfigureState((sp, state) => state.AddProcessor(processor)); - } + /// + public TracerProviderBuilder ConfigureBuilder(Action configure) + { + var services = this.services; - internal TracerProviderBuilder ConfigureResource(Action configure) + if (services == null) { - Guard.ThrowIfNull(configure); - - return this.ConfigureState((sp, state) => state.ConfigureResource(configure)); + throw new NotSupportedException("Builder cannot be configured during TracerProvider construction."); } - internal TracerProviderBuilder ConfigureServices(Action configure) - { - Guard.ThrowIfNull(configure); - - var services = this.services; + services.ConfigureOpenTelemetryTracerProvider(configure); - if (services == null) - { - throw new NotSupportedException("Services cannot be configured after ServiceProvider has been created."); - } - - configure(services); + return this; + } - return this; - } + /// + public TracerProviderBuilder ConfigureServices(Action configure) + { + Guard.ThrowIfNull(configure); - internal TracerProvider InvokeBuild() - => this.Build(); + var services = this.services; - internal TracerProviderBuilder SetErrorStatusOnException(bool enabled) + if (services == null) { - return this.ConfigureState((sp, state) => state.SetErrorStatusOnException = enabled); + throw new NotSupportedException("Services cannot be configured during TracerProvider construction."); } - internal TracerProviderBuilder SetResourceBuilder(ResourceBuilder resourceBuilder) - { - Guard.ThrowIfNull(resourceBuilder); + configure(services); - return this.ConfigureState((sp, state) => state.SetResourceBuilder(resourceBuilder)); - } + return this; + } - internal TracerProviderBuilder SetSampler() - where T : Sampler - { - this.TryAddSingleton(); - this.ConfigureState((sp, state) => state.SetSampler(sp.GetRequiredService())); + /// + TracerProviderBuilder IDeferredTracerProviderBuilder.Configure(Action configure) + => this.ConfigureBuilder(configure); - return this; - } + internal TracerProvider InvokeBuild() + => this.Build(); - internal TracerProviderBuilder SetSampler(Sampler sampler) - { - Guard.ThrowIfNull(sampler); - - return this.ConfigureState((sp, state) => state.SetSampler(sampler)); - } + /// + /// Adds instrumentation to the provider. + /// d + /// Instrumentation name. + /// Instrumentation version. + /// Function that builds instrumentation. + /// Returns for chaining. + protected TracerProviderBuilder AddInstrumentation( + string instrumentationName, + string instrumentationVersion, + Func instrumentationFactory) + { + Guard.ThrowIfNullOrWhitespace(instrumentationName); + Guard.ThrowIfNullOrWhitespace(instrumentationVersion); + Guard.ThrowIfNull(instrumentationFactory); - /// - /// Adds instrumentation to the provider. - /// d - /// Instrumentation name. - /// Instrumentation version. - /// Function that builds instrumentation. - /// Returns for chaining. - protected TracerProviderBuilder AddInstrumentation( - string instrumentationName, - string instrumentationVersion, - Func instrumentationFactory) + return this.ConfigureBuilder((sp, builder) => { - Guard.ThrowIfNullOrWhitespace(instrumentationName); - Guard.ThrowIfNullOrWhitespace(instrumentationVersion); - Guard.ThrowIfNull(instrumentationFactory); - - return this.ConfigureState((sp, state) - => state.AddInstrumentation( + if (builder is TracerProviderBuilderSdk tracerProviderBuilderState) + { + tracerProviderBuilderState.AddInstrumentation( instrumentationName, instrumentationVersion, - instrumentationFactory())); - } + instrumentationFactory); + } + }); + } - /// - /// Run the configured actions to initialize the . - /// - /// . - protected TracerProvider Build() + /// + /// Run the configured actions to initialize the . + /// + /// . + protected TracerProvider Build() + { + if (!this.allowBuild) { - if (!this.ownsServices || this.State != null) - { - throw new NotSupportedException("Build cannot be called directly on TracerProviderBuilder tied to external services."); - } + throw new NotSupportedException("A TracerProviderBuilder bound to external service cannot be built directly. Access the TracerProvider using the application IServiceProvider instead."); + } - var services = this.services; + var services = this.services; - if (services == null) - { - throw new NotSupportedException("TracerProviderBuilder build method cannot be called multiple times."); - } + if (services == null) + { + throw new NotSupportedException("TracerProviderBuilder build method cannot be called multiple times."); + } - this.services = null; + this.services = null; #if DEBUG - bool validateScopes = true; + bool validateScopes = true; #else - bool validateScopes = false; + bool validateScopes = false; #endif - var serviceProvider = services.BuildServiceProvider(validateScopes); - - return new TracerProviderSdk(serviceProvider, ownsServiceProvider: true); - } - - private TracerProviderBuilder AddInstrumentation(Func instrumentationFactory) - where T : class - { - this.ConfigureState((sp, state) - => state.AddInstrumentation( - typeof(T).Name, - typeof(T).Assembly.GetName().Version?.ToString() ?? DefaultInstrumentationVersion, - instrumentationFactory(sp))); - - return this; - } - - private TracerProviderBuilder ConfigureState(Action configure) - { - Debug.Assert(configure != null, "configure was null"); - - if (this.State != null) - { - configure!(this.State.ServiceProvider, this.State); - } - else - { - this.ConfigureServices(services => - CallbackHelper.RegisterConfigureStateCallback(services, configure!)); - } + var serviceProvider = services.BuildServiceProvider(validateScopes); - return this; - } - - private void TryAddSingleton() - where T : class - { - var services = this.services; - - services?.TryAddSingleton(); - } + return new TracerProviderSdk(serviceProvider, ownsServiceProvider: true); } } diff --git a/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderExtensions.cs b/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderExtensions.cs index 654b368c721..880dbb0055f 100644 --- a/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderExtensions.cs +++ b/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderExtensions.cs @@ -18,6 +18,8 @@ using System.Diagnostics; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using OpenTelemetry.Internal; using OpenTelemetry.Resources; namespace OpenTelemetry.Trace @@ -36,10 +38,13 @@ public static class TracerProviderBuilderExtensions /// Returns for chaining. public static TracerProviderBuilder SetErrorStatusOnException(this TracerProviderBuilder tracerProviderBuilder, bool enabled = true) { - if (tracerProviderBuilder is TracerProviderBuilderBase tracerProviderBuilderBase) + tracerProviderBuilder.ConfigureBuilder((sp, builder) => { - tracerProviderBuilderBase.SetErrorStatusOnException(enabled); - } + if (builder is TracerProviderBuilderSdk tracerProviderBuilderSdk) + { + tracerProviderBuilderSdk.SetErrorStatusOnException(enabled); + } + }); return tracerProviderBuilder; } @@ -52,10 +57,15 @@ public static TracerProviderBuilder SetErrorStatusOnException(this TracerProvide /// Returns for chaining. public static TracerProviderBuilder SetSampler(this TracerProviderBuilder tracerProviderBuilder, Sampler sampler) { - if (tracerProviderBuilder is TracerProviderBuilderBase tracerProviderBuilderBase) + Guard.ThrowIfNull(sampler); + + tracerProviderBuilder.ConfigureBuilder((sp, builder) => { - tracerProviderBuilderBase.SetSampler(sampler); - } + if (builder is TracerProviderBuilderSdk tracerProviderBuilderSdk) + { + tracerProviderBuilderSdk.SetSampler(sampler); + } + }); return tracerProviderBuilder; } @@ -73,10 +83,15 @@ public static TracerProviderBuilder SetSampler(this TracerProviderBuilder tracer public static TracerProviderBuilder SetSampler(this TracerProviderBuilder tracerProviderBuilder) where T : Sampler { - if (tracerProviderBuilder is TracerProviderBuilderBase tracerProviderBuilderBase) + tracerProviderBuilder.ConfigureServices(services => services.TryAddSingleton()); + + tracerProviderBuilder.ConfigureBuilder((sp, builder) => { - tracerProviderBuilderBase.SetSampler(); - } + if (builder is TracerProviderBuilderSdk tracerProviderBuilderSdk) + { + tracerProviderBuilderSdk.SetSampler(sp.GetRequiredService()); + } + }); return tracerProviderBuilder; } @@ -92,10 +107,15 @@ public static TracerProviderBuilder SetSampler(this TracerProviderBuilder tra /// Returns for chaining. public static TracerProviderBuilder SetResourceBuilder(this TracerProviderBuilder tracerProviderBuilder, ResourceBuilder resourceBuilder) { - if (tracerProviderBuilder is TracerProviderBuilderBase tracerProviderBuilderBase) + Guard.ThrowIfNull(resourceBuilder); + + tracerProviderBuilder.ConfigureBuilder((sp, builder) => { - tracerProviderBuilderBase.SetResourceBuilder(resourceBuilder); - } + if (builder is TracerProviderBuilderSdk tracerProviderBuilderSdk) + { + tracerProviderBuilderSdk.SetResourceBuilder(resourceBuilder); + } + }); return tracerProviderBuilder; } @@ -109,10 +129,15 @@ public static TracerProviderBuilder SetResourceBuilder(this TracerProviderBuilde /// Returns for chaining. public static TracerProviderBuilder ConfigureResource(this TracerProviderBuilder tracerProviderBuilder, Action configure) { - if (tracerProviderBuilder is TracerProviderBuilderBase tracerProviderBuilderBase) + Guard.ThrowIfNull(configure); + + tracerProviderBuilder.ConfigureBuilder((sp, builder) => { - tracerProviderBuilderBase.ConfigureResource(configure); - } + if (builder is TracerProviderBuilderSdk tracerProviderBuilderSdk) + { + tracerProviderBuilderSdk.ConfigureResource(configure); + } + }); return tracerProviderBuilder; } @@ -125,10 +150,15 @@ public static TracerProviderBuilder ConfigureResource(this TracerProviderBuilder /// Returns for chaining. public static TracerProviderBuilder AddProcessor(this TracerProviderBuilder tracerProviderBuilder, BaseProcessor processor) { - if (tracerProviderBuilder is TracerProviderBuilderBase tracerProviderBuilderBase) + Guard.ThrowIfNull(processor); + + tracerProviderBuilder.ConfigureBuilder((sp, builder) => { - tracerProviderBuilderBase.AddProcessor(processor); - } + if (builder is TracerProviderBuilderSdk tracerProviderBuilderSdk) + { + tracerProviderBuilderSdk.AddProcessor(processor); + } + }); return tracerProviderBuilder; } @@ -146,74 +176,15 @@ public static TracerProviderBuilder AddProcessor(this TracerProviderBuilder trac public static TracerProviderBuilder AddProcessor(this TracerProviderBuilder tracerProviderBuilder) where T : BaseProcessor { - if (tracerProviderBuilder is TracerProviderBuilderBase tracerProviderBuilderBase) - { - tracerProviderBuilderBase.AddProcessor(); - } - - return tracerProviderBuilder; - } + tracerProviderBuilder.ConfigureServices(services => services.TryAddSingleton()); - /// - /// Adds instrumentation to the provider. - /// - /// - /// Note: The type specified by will be - /// registered as a singleton service into application services. - /// - /// Instrumentation type. - /// . - /// The supplied for chaining. - public static TracerProviderBuilder AddInstrumentation(this TracerProviderBuilder tracerProviderBuilder) - where T : class - { - if (tracerProviderBuilder is TracerProviderBuilderBase tracerProviderBuilderBase) + tracerProviderBuilder.ConfigureBuilder((sp, builder) => { - tracerProviderBuilderBase.AddInstrumentation(); - } - - return tracerProviderBuilder; - } - - /// - /// Register a callback action to configure the where tracing services are configured. - /// - /// - /// Note: Tracing services are only available during the application - /// configuration phase. - /// - /// . - /// Configuration callback. - /// The supplied for chaining. - public static TracerProviderBuilder ConfigureServices( - this TracerProviderBuilder tracerProviderBuilder, - Action configure) - { - if (tracerProviderBuilder is TracerProviderBuilderBase tracerProviderBuilderBase) - { - tracerProviderBuilderBase.ConfigureServices(configure); - } - - return tracerProviderBuilder; - } - - /// - /// Register a callback action to configure the once the application is available. - /// - /// . - /// Configuration callback. - /// The supplied for chaining. - public static TracerProviderBuilder ConfigureBuilder( - this TracerProviderBuilder tracerProviderBuilder, - Action configure) - { - if (tracerProviderBuilder is IDeferredTracerProviderBuilder deferredTracerProviderBuilder) - { - deferredTracerProviderBuilder.Configure(configure); - } + if (builder is TracerProviderBuilderSdk tracerProviderBuilderSdk) + { + tracerProviderBuilderSdk.AddProcessor(sp.GetRequiredService()); + } + }); return tracerProviderBuilder; } diff --git a/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderSdk.cs b/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderSdk.cs index a13d105e8db..c56044b884a 100644 --- a/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderSdk.cs +++ b/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderSdk.cs @@ -16,24 +16,199 @@ #nullable enable +using System.Diagnostics; using Microsoft.Extensions.DependencyInjection; +using OpenTelemetry.Internal; +using OpenTelemetry.Resources; namespace OpenTelemetry.Trace { - internal sealed class TracerProviderBuilderSdk : TracerProviderBuilderBase + /// + /// Stores state used to build a . + /// + internal sealed class TracerProviderBuilderSdk : TracerProviderBuilder, ITracerProviderBuilder { - public TracerProviderBuilderSdk() + private const string DefaultInstrumentationVersion = "1.0.0.0"; + + private readonly IServiceProvider serviceProvider; + private TracerProviderSdk? tracerProvider; + + public TracerProviderBuilderSdk(IServiceProvider serviceProvider) + { + this.serviceProvider = serviceProvider; + } + + public List Instrumentation { get; } = new(); + + public ResourceBuilder? ResourceBuilder { get; private set; } + + public TracerProvider? Provider => this.tracerProvider; + + public List> Processors { get; } = new(); + + public List Sources { get; } = new(); + + public HashSet LegacyActivityOperationNames { get; } = new(StringComparer.OrdinalIgnoreCase); + + public Sampler? Sampler { get; private set; } + + public bool ExceptionProcessorEnabled { get; private set; } + + public void RegisterProvider(TracerProviderSdk tracerProvider) + { + Debug.Assert(tracerProvider != null, "tracerProvider was null"); + + if (this.tracerProvider != null) + { + throw new NotSupportedException("TracerProvider cannot be accessed while build is executing."); + } + + this.tracerProvider = tracerProvider; + } + + public override TracerProviderBuilder AddInstrumentation( + Func instrumentationFactory) + { + Debug.Assert(instrumentationFactory != null, "instrumentationFactory was null"); + + return this.AddInstrumentation( + typeof(TInstrumentation).Name, + typeof(TInstrumentation).Assembly.GetName().Version?.ToString() ?? DefaultInstrumentationVersion, + instrumentationFactory!()); + } + + public TracerProviderBuilder AddInstrumentation( + string instrumentationName, + string instrumentationVersion, + object instrumentation) + { + Debug.Assert(!string.IsNullOrWhiteSpace(instrumentationName), "instrumentationName was null or whitespace"); + Debug.Assert(!string.IsNullOrWhiteSpace(instrumentationVersion), "instrumentationVersion was null or whitespace"); + Debug.Assert(instrumentation != null, "instrumentation was null"); + + this.Instrumentation.Add( + new InstrumentationRegistration( + instrumentationName, + instrumentationVersion, + instrumentation!)); + + return this; + } + + public TracerProviderBuilder ConfigureResource(Action configure) + { + Debug.Assert(configure != null, "configure was null"); + + var resourceBuilder = this.ResourceBuilder ??= ResourceBuilder.CreateDefault(); + + configure!(resourceBuilder); + + return this; + } + + public TracerProviderBuilder SetResourceBuilder(ResourceBuilder resourceBuilder) + { + Debug.Assert(resourceBuilder != null, "resourceBuilder was null"); + + this.ResourceBuilder = resourceBuilder; + + return this; + } + + public override TracerProviderBuilder AddLegacySource(string operationName) + { + Debug.Assert(!string.IsNullOrWhiteSpace(operationName), "operationName was null or whitespace"); + + this.LegacyActivityOperationNames.Add(operationName); + + return this; + } + + public override TracerProviderBuilder AddSource(params string[] names) + { + Debug.Assert(names != null, "names was null"); + + foreach (var name in names!) + { + Guard.ThrowIfNullOrWhitespace(name); + + // TODO: We need to fix the listening model. + // Today it ignores version. + this.Sources.Add(name); + } + + return this; + } + + public TracerProviderBuilder AddProcessor(BaseProcessor processor) { + Debug.Assert(processor != null, "processor was null"); + + this.Processors.Add(processor!); + + return this; } - public TracerProviderBuilderSdk(IServiceCollection services) - : base(services) + public TracerProviderBuilder SetSampler(Sampler sampler) { + Debug.Assert(sampler != null, "sampler was null"); + + this.Sampler = sampler; + + return this; } - public TracerProviderBuilderSdk(TracerProviderBuilderState state) - : base(state) + public TracerProviderBuilder SetErrorStatusOnException(bool enabled) { + this.ExceptionProcessorEnabled = enabled; + + return this; + } + + public TracerProviderBuilder ConfigureBuilder(Action configure) + { + Debug.Assert(configure != null, "configure was null"); + + configure!(this.serviceProvider, this); + + return this; + } + + public TracerProviderBuilder ConfigureServices(Action configure) + { + throw new NotSupportedException("Services cannot be configured after ServiceProvider has been created."); + } + + public void AddExceptionProcessorIfEnabled() + { + if (this.ExceptionProcessorEnabled) + { + try + { + this.Processors.Insert(0, new ExceptionProcessor()); + } + catch (Exception ex) + { + throw new NotSupportedException($"'{nameof(TracerProviderBuilderExtensions.SetErrorStatusOnException)}' is not supported on this platform", ex); + } + } + } + + TracerProviderBuilder IDeferredTracerProviderBuilder.Configure(Action configure) + => this.ConfigureBuilder(configure); + + internal readonly struct InstrumentationRegistration + { + public readonly string Name; + public readonly string Version; + public readonly object Instance; + + internal InstrumentationRegistration(string name, string version, object instance) + { + this.Name = name; + this.Version = version; + this.Instance = instance; + } } } } diff --git a/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderServiceCollectionExtensions.cs b/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderServiceCollectionExtensions.cs deleted file mode 100644 index 68408ae056b..00000000000 --- a/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderServiceCollectionExtensions.cs +++ /dev/null @@ -1,76 +0,0 @@ -// -// 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. -// - -#nullable enable - -using OpenTelemetry; -using OpenTelemetry.Internal; -using OpenTelemetry.Trace; - -namespace Microsoft.Extensions.DependencyInjection; - -/// -/// Extension methods for setting up OpenTelemetry tracing services in an . -/// -public static class TracerProviderBuilderServiceCollectionExtensions -{ - /// - /// Configures OpenTelemetry tracing services in the supplied . - /// - /// - /// Notes: - /// - /// A will not be created automatically - /// using this method. Either use the - /// IServiceCollection.AddOpenTelemetryTracing extension in the - /// OpenTelemetry.Extensions.Hosting package or access the through the application to begin collecting traces. - /// This is safe to be called multiple times and by library authors. - /// Only a single will be created for a given - /// . - /// - /// - /// The to add services to. - /// The so that additional calls can be chained. - public static IServiceCollection ConfigureOpenTelemetryTracing(this IServiceCollection services) - => ConfigureOpenTelemetryTracing(services, (b) => { }); - - /// - /// Configures OpenTelemetry tracing services in the supplied . - /// - /// - /// The to add services to. - /// Callback action to configure the . - /// The so that additional calls can be chained. - public static IServiceCollection ConfigureOpenTelemetryTracing(this IServiceCollection services, Action configure) - { - Guard.ThrowIfNull(services); - Guard.ThrowIfNull(configure); - - // Accessing Sdk class is just to trigger its static ctor, - // which sets default Propagators and default Activity Id format - _ = Sdk.SuppressInstrumentation; - - // Note: We need to create a builder even if there is no configure - // because the builder will register services - var builder = new TracerProviderBuilderSdk(services); - - configure(builder); - - return services; - } -} diff --git a/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderState.cs b/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderState.cs deleted file mode 100644 index 129efc55d97..00000000000 --- a/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderState.cs +++ /dev/null @@ -1,96 +0,0 @@ -// -// 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. -// - -#nullable enable - -using System.Diagnostics; -using OpenTelemetry.Internal; - -namespace OpenTelemetry.Trace -{ - /// - /// Stores state used to build a . - /// - internal sealed class TracerProviderBuilderState : ProviderBuilderState - { - private TracerProviderBuilderSdk? builder; - - public TracerProviderBuilderState(IServiceProvider serviceProvider) - : base(serviceProvider) - { - } - - public override TracerProviderBuilderSdk Builder - => this.builder ??= new TracerProviderBuilderSdk(this); - - public List> Processors { get; } = new(); - - public List Sources { get; } = new(); - - public HashSet LegacyActivityOperationNames { get; } = new(StringComparer.OrdinalIgnoreCase); - - public Sampler? Sampler { get; private set; } - - public bool SetErrorStatusOnException { get; set; } - - public void AddLegacySource(string operationName) - { - Debug.Assert(!string.IsNullOrWhiteSpace(operationName), "operationName was null or whitespace"); - - this.LegacyActivityOperationNames.Add(operationName); - } - - public void AddProcessor(BaseProcessor processor) - { - Debug.Assert(processor != null, "processor was null"); - - this.Processors.Add(processor!); - } - - public void AddSource(params string[] names) - { - Debug.Assert(names != null, "names was null"); - - foreach (var name in names!) - { - Guard.ThrowIfNullOrWhitespace(name); - - // TODO: We need to fix the listening model. - // Today it ignores version. - this.Sources.Add(name); - } - } - - public void SetSampler(Sampler sampler) - { - Debug.Assert(sampler != null, "sampler was null"); - - this.Sampler = sampler; - } - - internal void EnableErrorStatusOnException() - { - try - { - this.Processors.Insert(0, new ExceptionProcessor()); - } - catch (Exception ex) - { - throw new NotSupportedException($"'{nameof(TracerProviderBuilderExtensions.SetErrorStatusOnException)}' is not supported on this platform", ex); - } - } - } -} diff --git a/src/OpenTelemetry/Trace/TracerProviderExtensions.cs b/src/OpenTelemetry/Trace/TracerProviderExtensions.cs index 188e316bafe..91e4f610490 100644 --- a/src/OpenTelemetry/Trace/TracerProviderExtensions.cs +++ b/src/OpenTelemetry/Trace/TracerProviderExtensions.cs @@ -21,8 +21,17 @@ namespace OpenTelemetry.Trace { + /// + /// Contains extension methods for the class. + /// public static class TracerProviderExtensions { + /// + /// Add a processor to the provider. + /// + /// . + /// . + /// The supplied instance for call chaining. public static TracerProvider AddProcessor(this TracerProvider provider, BaseProcessor processor) { Guard.ThrowIfNull(provider); diff --git a/src/OpenTelemetry/Trace/TracerProviderSdk.cs b/src/OpenTelemetry/Trace/TracerProviderSdk.cs index 3505d71adb0..218bf4c7a9a 100644 --- a/src/OpenTelemetry/Trace/TracerProviderSdk.cs +++ b/src/OpenTelemetry/Trace/TracerProviderSdk.cs @@ -23,11 +23,6 @@ using OpenTelemetry.Internal; using OpenTelemetry.Resources; -using CallbackHelper = OpenTelemetry.ProviderBuilderServiceCollectionCallbackHelper< - OpenTelemetry.Trace.TracerProviderBuilderSdk, - OpenTelemetry.Trace.TracerProviderSdk, - OpenTelemetry.Trace.TracerProviderBuilderState>; - namespace OpenTelemetry.Trace { internal sealed class TracerProviderSdk : TracerProvider @@ -50,8 +45,8 @@ internal TracerProviderSdk( { Debug.Assert(serviceProvider != null, "serviceProvider was null"); - var state = serviceProvider!.GetRequiredService(); - state.RegisterProvider(nameof(TracerProvider), this); + var state = serviceProvider!.GetRequiredService(); + state.RegisterProvider(this); this.ServiceProvider = serviceProvider!; @@ -63,17 +58,16 @@ internal TracerProviderSdk( OpenTelemetrySdkEventSource.Log.TracerProviderSdkEvent("Building TracerProvider."); - CallbackHelper.InvokeRegisteredConfigureStateCallbacks( - serviceProvider!, - state); + var configureProviderBuilders = serviceProvider!.GetServices(); + foreach (var configureProviderBuilder in configureProviderBuilders) + { + configureProviderBuilder.ConfigureBuilder(serviceProvider!, state); + } StringBuilder processorsAdded = new StringBuilder(); StringBuilder instrumentationFactoriesAdded = new StringBuilder(); - if (state.SetErrorStatusOnException) - { - state.EnableErrorStatusOnException(); - } + state.AddExceptionProcessorIfEnabled(); var resourceBuilder = state.ResourceBuilder ?? ResourceBuilder.CreateDefault(); resourceBuilder.ServiceProvider = serviceProvider; diff --git a/test/OpenTelemetry.Exporter.Jaeger.Tests/JaegerExporterTests.cs b/test/OpenTelemetry.Exporter.Jaeger.Tests/JaegerExporterTests.cs index 10f1f9b3324..afd276282e6 100644 --- a/test/OpenTelemetry.Exporter.Jaeger.Tests/JaegerExporterTests.cs +++ b/test/OpenTelemetry.Exporter.Jaeger.Tests/JaegerExporterTests.cs @@ -124,8 +124,8 @@ public void ServiceProviderHttpClientFactoryInvoked() services.AddHttpClient("JaegerExporter", configureClient: (client) => invocations++); - services.AddOpenTelemetryTracing(builder => builder.AddJaegerExporter( - o => o.Protocol = JaegerExportProtocol.HttpBinaryThrift)); + services.AddOpenTelemetry().WithTracing(builder => builder + .AddJaegerExporter(o => o.Protocol = JaegerExportProtocol.HttpBinaryThrift)); using var serviceProvider = services.BuildServiceProvider(); diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpMetricsExporterTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpMetricsExporterTests.cs index e501446e595..fd11e42c343 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpMetricsExporterTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpMetricsExporterTests.cs @@ -161,8 +161,8 @@ public void ServiceProviderHttpClientFactoryInvoked() services.AddHttpClient("OtlpMetricExporter", configureClient: (client) => invocations++); - services.AddOpenTelemetryMetrics(builder => builder.AddOtlpExporter( - o => o.Protocol = OtlpExportProtocol.HttpProtobuf)); + services.AddOpenTelemetry().WithMetrics(builder => builder + .AddOtlpExporter(o => o.Protocol = OtlpExportProtocol.HttpProtobuf)); using var serviceProvider = services.BuildServiceProvider(); diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs index e302f5654f0..3fe9ac9f517 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs @@ -136,8 +136,8 @@ public void ServiceProviderHttpClientFactoryInvoked() services.AddHttpClient("OtlpTraceExporter", configureClient: (client) => invocations++); - services.AddOpenTelemetryTracing(builder => builder.AddOtlpExporter( - o => o.Protocol = OtlpExportProtocol.HttpProtobuf)); + services.AddOpenTelemetry().WithTracing(builder => builder + .AddOtlpExporter(o => o.Protocol = OtlpExportProtocol.HttpProtobuf)); using var serviceProvider = services.BuildServiceProvider(); diff --git a/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusExporterMiddlewareTests.cs b/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusExporterMiddlewareTests.cs index 8a6fb6eca9f..a85ed9e2771 100644 --- a/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusExporterMiddlewareTests.cs +++ b/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusExporterMiddlewareTests.cs @@ -258,7 +258,7 @@ private static async Task RunPrometheusExporterMiddlewareIntegrationTest( { if (registerMeterProvider) { - services.AddOpenTelemetryMetrics(builder => builder + services.AddOpenTelemetry().WithMetrics(builder => builder .AddMeter(MeterName) .AddPrometheusExporter(o => { diff --git a/test/OpenTelemetry.Exporter.Zipkin.Tests/ZipkinExporterTests.cs b/test/OpenTelemetry.Exporter.Zipkin.Tests/ZipkinExporterTests.cs index 683089e9479..18898912325 100644 --- a/test/OpenTelemetry.Exporter.Zipkin.Tests/ZipkinExporterTests.cs +++ b/test/OpenTelemetry.Exporter.Zipkin.Tests/ZipkinExporterTests.cs @@ -283,7 +283,8 @@ public void ServiceProviderHttpClientFactoryInvoked() services.AddHttpClient("ZipkinExporter", configureClient: (client) => invocations++); - services.AddOpenTelemetryTracing(builder => builder.AddZipkinExporter()); + services.AddOpenTelemetry().WithTracing(builder => builder + .AddZipkinExporter()); using var serviceProvider = services.BuildServiceProvider(); diff --git a/test/OpenTelemetry.Extensions.DependencyInjection.Tests/MeterProviderBuilderExtensionsTests.cs b/test/OpenTelemetry.Extensions.DependencyInjection.Tests/MeterProviderBuilderExtensionsTests.cs new file mode 100644 index 00000000000..14136ffa92a --- /dev/null +++ b/test/OpenTelemetry.Extensions.DependencyInjection.Tests/MeterProviderBuilderExtensionsTests.cs @@ -0,0 +1,144 @@ +// +// 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 Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using OpenTelemetry.Metrics; +using Xunit; + +namespace OpenTelemetry.Extensions.DependencyInjection.Tests; + +public class MeterProviderBuilderExtensionsTests +{ + [Fact] + public void AddInstrumentationFromServiceProviderTest() + { + using var builder = new TestMeterProviderBuilder(); + + builder.AddInstrumentation(); + + var serviceProvider = builder.BuildServiceProvider(); + + var instrumentation = serviceProvider.GetRequiredService(); + + Assert.NotNull(instrumentation); + + var registrationCount = builder.InvokeRegistrations(); + + Assert.Equal(1, registrationCount); + Assert.Single(builder.Instrumentation); + Assert.Equal(instrumentation, builder.Instrumentation[0]); + } + + [Fact] + public void AddInstrumentationUsingInstanceTest() + { + using var builder = new TestMeterProviderBuilder(); + + var instrumentation = new TestInstrumentation(); + + builder.AddInstrumentation(instrumentation); + + var serviceProvider = builder.BuildServiceProvider(); + var registrationCount = builder.InvokeRegistrations(); + + Assert.Equal(1, registrationCount); + Assert.Single(builder.Instrumentation); + Assert.Equal(instrumentation, builder.Instrumentation[0]); + } + + [Fact] + public void AddInstrumentationUsingFactoryTest() + { + using var builder = new TestMeterProviderBuilder(); + + var instrumentation = new TestInstrumentation(); + + builder.AddInstrumentation(sp => + { + Assert.NotNull(sp); + + return instrumentation; + }); + + var serviceProvider = builder.BuildServiceProvider(); + var registrationCount = builder.InvokeRegistrations(); + + Assert.Equal(1, registrationCount); + Assert.Single(builder.Instrumentation); + Assert.Equal(instrumentation, builder.Instrumentation[0]); + } + + [Fact] + public void AddInstrumentationUsingFactoryAndProviderTest() + { + using var builder = new TestMeterProviderBuilder(); + + var instrumentation = new TestInstrumentation(); + + builder.AddInstrumentation((sp, provider) => + { + Assert.NotNull(sp); + Assert.NotNull(provider); + + return instrumentation; + }); + + var serviceProvider = builder.BuildServiceProvider(); + var registrationCount = builder.InvokeRegistrations(); + + Assert.Equal(1, registrationCount); + Assert.Single(builder.Instrumentation); + Assert.Equal(instrumentation, builder.Instrumentation[0]); + } + + [Fact] + public void ConfigureServicesTest() + { + using var builder = new TestMeterProviderBuilder(); + + builder.ConfigureServices(services => services.TryAddSingleton()); + + var serviceProvider = builder.BuildServiceProvider(); + + serviceProvider.GetRequiredService(); + } + + [Fact] + public void ConfigureBuilderTest() + { + using var builder = new TestMeterProviderBuilder(); + + builder.ConfigureBuilder((sp, builder) => + { + Assert.NotNull(sp); + Assert.NotNull(builder); + + builder.AddMeter("HelloWorld"); + }); + + var serviceProvider = builder.BuildServiceProvider(); + var registrationCount = builder.InvokeRegistrations(); + + Assert.Equal(1, registrationCount); + Assert.Single(builder.Meters); + Assert.Equal("HelloWorld", builder.Meters[0]); + } + + private sealed class TestInstrumentation + { + } +} diff --git a/test/OpenTelemetry.Extensions.DependencyInjection.Tests/OpenTelemetry.Extensions.DependencyInjection.Tests.csproj b/test/OpenTelemetry.Extensions.DependencyInjection.Tests/OpenTelemetry.Extensions.DependencyInjection.Tests.csproj new file mode 100644 index 00000000000..1156b1c5633 --- /dev/null +++ b/test/OpenTelemetry.Extensions.DependencyInjection.Tests/OpenTelemetry.Extensions.DependencyInjection.Tests.csproj @@ -0,0 +1,24 @@ + + + Unit test project for OpenTelemetry .NET dependency injection extensions + + net7.0;net6.0 + $(TargetFrameworks);net462 + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + + diff --git a/test/OpenTelemetry.Extensions.DependencyInjection.Tests/ServiceCollectionExtensionsTests.cs b/test/OpenTelemetry.Extensions.DependencyInjection.Tests/ServiceCollectionExtensionsTests.cs new file mode 100644 index 00000000000..72ede87e3e9 --- /dev/null +++ b/test/OpenTelemetry.Extensions.DependencyInjection.Tests/ServiceCollectionExtensionsTests.cs @@ -0,0 +1,81 @@ +// +// 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 Microsoft.Extensions.DependencyInjection; +using OpenTelemetry.Metrics; +using OpenTelemetry.Trace; +using Xunit; + +namespace OpenTelemetry.Extensions.DependencyInjection.Tests; + +public class ServiceCollectionExtensionsTests +{ + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(3)] + public void ConfigureOpenTelemetryTracerProvider(int numberOfCalls) + { + var invocations = 0; + + var services = new ServiceCollection(); + + for (int i = 0; i < numberOfCalls; i++) + { + services.ConfigureOpenTelemetryTracerProvider((sp, builder) => invocations++); + } + + using var serviceProvider = services.BuildServiceProvider(); + + var registrations = serviceProvider.GetServices(); + + foreach (var registration in registrations) + { + registration.ConfigureBuilder(serviceProvider, null!); + } + + Assert.Equal(invocations, registrations.Count()); + Assert.Equal(numberOfCalls, registrations.Count()); + } + + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(3)] + public void ConfigureOpenTelemetryMeterProvider(int numberOfCalls) + { + var invocations = 0; + + var services = new ServiceCollection(); + + for (int i = 0; i < numberOfCalls; i++) + { + services.ConfigureOpenTelemetryMeterProvider((sp, builder) => invocations++); + } + + using var serviceProvider = services.BuildServiceProvider(); + + var registrations = serviceProvider.GetServices(); + + foreach (var registration in registrations) + { + registration.ConfigureBuilder(serviceProvider, null!); + } + + Assert.Equal(invocations, registrations.Count()); + Assert.Equal(numberOfCalls, registrations.Count()); + } +} diff --git a/test/OpenTelemetry.Extensions.DependencyInjection.Tests/TestMeterProviderBuilder.cs b/test/OpenTelemetry.Extensions.DependencyInjection.Tests/TestMeterProviderBuilder.cs new file mode 100644 index 00000000000..86f7d523274 --- /dev/null +++ b/test/OpenTelemetry.Extensions.DependencyInjection.Tests/TestMeterProviderBuilder.cs @@ -0,0 +1,140 @@ +// +// 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 Microsoft.Extensions.DependencyInjection; +using OpenTelemetry.Metrics; + +namespace OpenTelemetry.Extensions.DependencyInjection.Tests; + +public sealed class TestMeterProviderBuilder : MeterProviderBuilder, IMeterProviderBuilder, IDisposable +{ + public TestMeterProviderBuilder() + { + this.Services = new ServiceCollection(); + } + + public IServiceCollection? Services { get; private set; } + + public ServiceProvider? ServiceProvider { get; private set; } + + public List Meters { get; } = new(); + + public List Instrumentation { get; } = new(); + + public MeterProvider? Provider { get; private set; } + + public override MeterProviderBuilder AddInstrumentation(Func instrumentationFactory) + { + if (this.Services != null) + { + this.ConfigureBuilder((sp, builder) => builder.AddInstrumentation(instrumentationFactory)); + } + else + { + this.Instrumentation.Add(instrumentationFactory()); + } + + return this; + } + + public override MeterProviderBuilder AddMeter(params string[] names) + { + if (this.Services != null) + { + this.ConfigureBuilder((sp, builder) => builder.AddMeter(names)); + } + else + { + foreach (string name in names) + { + this.Meters.Add(name); + } + } + + return this; + } + + public MeterProviderBuilder ConfigureBuilder(Action configure) + { + var services = this.Services; + if (services != null) + { + services.ConfigureOpenTelemetryMeterProvider(configure); + } + else + { + var serviceProvider = this.ServiceProvider ?? throw new InvalidOperationException("Test failure"); + configure(serviceProvider, this); + } + + return this; + } + + public MeterProviderBuilder ConfigureServices(Action configure) + { + var services = this.Services; + if (services != null) + { + configure(services); + } + else + { + throw new NotSupportedException("Services cannot be configured after the ServiceProvider has been created."); + } + + return this; + } + + public IServiceProvider BuildServiceProvider() + { + var services = this.Services ?? throw new InvalidOperationException(); + + this.Services = null; + + this.Provider = new NoopMeterProvider(); + + return this.ServiceProvider = services.BuildServiceProvider(); + } + + public int InvokeRegistrations() + { + var serviceProvider = this.ServiceProvider ?? throw new InvalidOperationException(); + + var registrations = serviceProvider.GetServices(); + + var count = 0; + + foreach (var registration in registrations) + { + registration.ConfigureBuilder(serviceProvider, this); + count++; + } + + return count; + } + + public void Dispose() + { + this.ServiceProvider?.Dispose(); + } + + MeterProviderBuilder IDeferredMeterProviderBuilder.Configure(Action configure) + => this.ConfigureBuilder(configure); + + private sealed class NoopMeterProvider : MeterProvider + { + } +} diff --git a/test/OpenTelemetry.Extensions.DependencyInjection.Tests/TestTracerProviderBuilder.cs b/test/OpenTelemetry.Extensions.DependencyInjection.Tests/TestTracerProviderBuilder.cs new file mode 100644 index 00000000000..89f61ae2bcf --- /dev/null +++ b/test/OpenTelemetry.Extensions.DependencyInjection.Tests/TestTracerProviderBuilder.cs @@ -0,0 +1,156 @@ +// +// 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 Microsoft.Extensions.DependencyInjection; +using OpenTelemetry.Trace; + +namespace OpenTelemetry.Extensions.DependencyInjection.Tests; + +public sealed class TestTracerProviderBuilder : TracerProviderBuilder, ITracerProviderBuilder, IDisposable +{ + public TestTracerProviderBuilder() + { + this.Services = new ServiceCollection(); + } + + public IServiceCollection? Services { get; private set; } + + public ServiceProvider? ServiceProvider { get; private set; } + + public List Sources { get; } = new(); + + public List LegacySources { get; } = new(); + + public List Instrumentation { get; } = new(); + + public TracerProvider? Provider { get; private set; } + + public override TracerProviderBuilder AddInstrumentation(Func instrumentationFactory) + { + if (this.Services != null) + { + this.ConfigureBuilder((sp, builder) => builder.AddInstrumentation(instrumentationFactory)); + } + else + { + this.Instrumentation.Add(instrumentationFactory()); + } + + return this; + } + + public override TracerProviderBuilder AddLegacySource(string operationName) + { + if (this.Services != null) + { + this.ConfigureBuilder((sp, builder) => builder.AddLegacySource(operationName)); + } + else + { + this.LegacySources.Add(operationName); + } + + return this; + } + + public override TracerProviderBuilder AddSource(params string[] names) + { + if (this.Services != null) + { + this.ConfigureBuilder((sp, builder) => builder.AddSource(names)); + } + else + { + foreach (string name in names) + { + this.Sources.Add(name); + } + } + + return this; + } + + public TracerProviderBuilder ConfigureBuilder(Action configure) + { + var services = this.Services; + if (services != null) + { + services.ConfigureOpenTelemetryTracerProvider(configure); + } + else + { + var serviceProvider = this.ServiceProvider ?? throw new InvalidOperationException("Test failure"); + configure(serviceProvider, this); + } + + return this; + } + + public TracerProviderBuilder ConfigureServices(Action configure) + { + var services = this.Services; + if (services != null) + { + configure(services); + } + else + { + throw new NotSupportedException("Services cannot be configured after the ServiceProvider has been created."); + } + + return this; + } + + public IServiceProvider BuildServiceProvider() + { + var services = this.Services ?? throw new InvalidOperationException(); + + this.Services = null; + + this.Provider = new NoopTracerProvider(); + + return this.ServiceProvider = services.BuildServiceProvider(); + } + + public int InvokeRegistrations() + { + var serviceProvider = this.ServiceProvider ?? throw new InvalidOperationException(); + + var registrations = serviceProvider.GetServices(); + + var count = 0; + + foreach (var registration in registrations) + { + registration.ConfigureBuilder(serviceProvider, this); + count++; + } + + return count; + } + + public void Dispose() + { + this.ServiceProvider?.Dispose(); + } + + TracerProviderBuilder IDeferredTracerProviderBuilder.Configure(Action configure) + => this.ConfigureBuilder(configure); + + private sealed class NoopTracerProvider : TracerProvider + { + } +} diff --git a/test/OpenTelemetry.Extensions.DependencyInjection.Tests/TracerProviderBuilderExtensionsTests.cs b/test/OpenTelemetry.Extensions.DependencyInjection.Tests/TracerProviderBuilderExtensionsTests.cs new file mode 100644 index 00000000000..48f8ec50993 --- /dev/null +++ b/test/OpenTelemetry.Extensions.DependencyInjection.Tests/TracerProviderBuilderExtensionsTests.cs @@ -0,0 +1,144 @@ +// +// 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 Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using OpenTelemetry.Trace; +using Xunit; + +namespace OpenTelemetry.Extensions.DependencyInjection.Tests; + +public class TracerProviderBuilderExtensionsTests +{ + [Fact] + public void AddInstrumentationFromServiceProviderTest() + { + using var builder = new TestTracerProviderBuilder(); + + builder.AddInstrumentation(); + + var serviceProvider = builder.BuildServiceProvider(); + + var instrumentation = serviceProvider.GetRequiredService(); + + Assert.NotNull(instrumentation); + + var registrationCount = builder.InvokeRegistrations(); + + Assert.Equal(1, registrationCount); + Assert.Single(builder.Instrumentation); + Assert.Equal(instrumentation, builder.Instrumentation[0]); + } + + [Fact] + public void AddInstrumentationUsingInstanceTest() + { + using var builder = new TestTracerProviderBuilder(); + + var instrumentation = new TestInstrumentation(); + + builder.AddInstrumentation(instrumentation); + + var serviceProvider = builder.BuildServiceProvider(); + var registrationCount = builder.InvokeRegistrations(); + + Assert.Equal(1, registrationCount); + Assert.Single(builder.Instrumentation); + Assert.Equal(instrumentation, builder.Instrumentation[0]); + } + + [Fact] + public void AddInstrumentationUsingFactoryTest() + { + using var builder = new TestTracerProviderBuilder(); + + var instrumentation = new TestInstrumentation(); + + builder.AddInstrumentation(sp => + { + Assert.NotNull(sp); + + return instrumentation; + }); + + var serviceProvider = builder.BuildServiceProvider(); + var registrationCount = builder.InvokeRegistrations(); + + Assert.Equal(1, registrationCount); + Assert.Single(builder.Instrumentation); + Assert.Equal(instrumentation, builder.Instrumentation[0]); + } + + [Fact] + public void AddInstrumentationUsingFactoryAndProviderTest() + { + using var builder = new TestTracerProviderBuilder(); + + var instrumentation = new TestInstrumentation(); + + builder.AddInstrumentation((sp, provider) => + { + Assert.NotNull(sp); + Assert.NotNull(provider); + + return instrumentation; + }); + + var serviceProvider = builder.BuildServiceProvider(); + var registrationCount = builder.InvokeRegistrations(); + + Assert.Equal(1, registrationCount); + Assert.Single(builder.Instrumentation); + Assert.Equal(instrumentation, builder.Instrumentation[0]); + } + + [Fact] + public void ConfigureServicesTest() + { + using var builder = new TestTracerProviderBuilder(); + + builder.ConfigureServices(services => services.TryAddSingleton()); + + var serviceProvider = builder.BuildServiceProvider(); + + serviceProvider.GetRequiredService(); + } + + [Fact] + public void ConfigureBuilderTest() + { + using var builder = new TestTracerProviderBuilder(); + + builder.ConfigureBuilder((sp, builder) => + { + Assert.NotNull(sp); + Assert.NotNull(builder); + + builder.AddSource("HelloWorld"); + }); + + var serviceProvider = builder.BuildServiceProvider(); + var registrationCount = builder.InvokeRegistrations(); + + Assert.Equal(1, registrationCount); + Assert.Single(builder.Sources); + Assert.Equal("HelloWorld", builder.Sources[0]); + } + + private sealed class TestInstrumentation + { + } +} diff --git a/test/OpenTelemetry.Extensions.Hosting.Tests/HostingMeterExtensionTests.cs b/test/OpenTelemetry.Extensions.Hosting.Tests/HostingMeterExtensionTests.cs index 4553ae33926..dcc9598c5f8 100644 --- a/test/OpenTelemetry.Extensions.Hosting.Tests/HostingMeterExtensionTests.cs +++ b/test/OpenTelemetry.Extensions.Hosting.Tests/HostingMeterExtensionTests.cs @@ -14,9 +14,7 @@ // limitations under the License. // -using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -29,175 +27,41 @@ namespace OpenTelemetry.Extensions.Hosting.Tests public class HostingMeterExtensionTests { [Fact] - public async Task AddOpenTelemetryMeterProviderInstrumentationCreationAndDisposal() + public async Task AddOpenTelemetry_StartWithHost_CreationAndDisposal() { - var testInstrumentation = new TestInstrumentation(); var callbackRun = false; var builder = new HostBuilder().ConfigureServices(services => { - services.AddOpenTelemetryMetrics(builder => - { - builder.AddInstrumentation(() => - { - callbackRun = true; - return testInstrumentation; - }); - }); + services.AddOpenTelemetry() + .WithMetrics(builder => builder + .AddInstrumentation(() => + { + callbackRun = true; + return new object(); + })) + .StartWithHost(); }); var host = builder.Build(); Assert.False(callbackRun); - Assert.False(testInstrumentation.Disposed); await host.StartAsync(); Assert.True(callbackRun); - Assert.False(testInstrumentation.Disposed); await host.StopAsync(); Assert.True(callbackRun); - Assert.False(testInstrumentation.Disposed); host.Dispose(); Assert.True(callbackRun); - Assert.True(testInstrumentation.Disposed); - } - - [Fact] - public void AddOpenTelemetryMeterProvider_HostBuilt_OpenTelemetrySdk_RegisteredAsSingleton() - { - var builder = new HostBuilder().ConfigureServices(services => - { - services.AddOpenTelemetryMetrics(); - }); - - var host = builder.Build(); - - var meterProvider1 = host.Services.GetRequiredService(); - var meterProvider2 = host.Services.GetRequiredService(); - - Assert.Same(meterProvider1, meterProvider2); - } - - [Fact] - public void AddOpenTelemetryMeterProvider_ServiceProviderArgument_ServicesRegistered() - { - var testInstrumentation = new TestInstrumentation(); - - var services = new ServiceCollection(); - services.AddSingleton(testInstrumentation); - services.AddOpenTelemetryMetrics(builder => - { - builder.ConfigureBuilder( - (sp, b) => b.AddInstrumentation(() => sp.GetRequiredService())); - }); - - var serviceProvider = services.BuildServiceProvider(); - - var meterFactory = serviceProvider.GetRequiredService(); - Assert.NotNull(meterFactory); - - Assert.False(testInstrumentation.Disposed); - - serviceProvider.Dispose(); - - Assert.True(testInstrumentation.Disposed); } [Fact] - public void AddOpenTelemetryMeterProvider_BadArgs_NullServiceCollection() - { - ServiceCollection services = null; - Assert.Throws(() => services.AddOpenTelemetryMetrics(null)); - Assert.Throws(() => - services.AddOpenTelemetryMetrics(builder => - { - builder.ConfigureBuilder( - (sp, b) => b.AddInstrumentation(() => sp.GetRequiredService())); - })); - } - - [Fact] - public void AddOpenTelemetryMeterProvider_GetServicesExtension() - { - var services = new ServiceCollection(); - services.AddOpenTelemetryMetrics(builder => AddMyFeature(builder)); - - using var serviceProvider = services.BuildServiceProvider(); - - var meterProvider = (MeterProviderSdk)serviceProvider.GetRequiredService(); - - Assert.True(meterProvider.Reader is TestReader); - } - - [Fact] - public void AddOpenTelemetryMeterProvider_NestedConfigureCallbacks() - { - int configureCalls = 0; - var services = new ServiceCollection(); - services.AddOpenTelemetryMetrics(builder => builder - .ConfigureBuilder((sp1, builder1) => - { - configureCalls++; - builder1.ConfigureBuilder((sp2, builder2) => - { - configureCalls++; - }); - })); - - using var serviceProvider = services.BuildServiceProvider(); - - var meterFactory = serviceProvider.GetRequiredService(); - - Assert.Equal(2, configureCalls); - } - - [Fact] - public void AddOpenTelemetryMeterProvider_ConfigureCallbacksUsingExtensions() - { - var services = new ServiceCollection(); - - services.AddSingleton(); - services.AddSingleton(); - - services.AddOpenTelemetryMetrics(builder => builder - .ConfigureBuilder((sp1, builder1) => - { - builder1 - .AddInstrumentation() - .AddReader(); - })); - - using var serviceProvider = services.BuildServiceProvider(); - - var meterProvider = (MeterProviderSdk)serviceProvider.GetRequiredService(); - - Assert.True(meterProvider.Instrumentations.FirstOrDefault() is TestInstrumentation); - Assert.True(meterProvider.Reader is TestReader); - } - - [Fact] - public void AddOpenTelemetryMetrics_MultipleCallsConfigureSingleProvider() - { - var services = new ServiceCollection(); - - services.AddOpenTelemetryMetrics(builder => builder.AddMeter("TestSourceBuilder1")); - services.AddOpenTelemetryMetrics(); - services.AddOpenTelemetryMetrics(builder => builder.AddMeter("TestSourceBuilder2")); - - using var serviceProvider = services.BuildServiceProvider(); - - var providers = serviceProvider.GetServices(); - - Assert.Single(providers); - } - - [Fact] - public async Task AddOpenTelemetryMetrics_HostConfigurationHonoredTest() + public async Task AddOpenTelemetry_StartWithHost_HostConfigurationHonoredTest() { bool configureBuilderCalled = false; @@ -211,19 +75,19 @@ public async Task AddOpenTelemetryMetrics_HostConfigurationHonoredTest() }) .ConfigureServices(services => { - services.AddOpenTelemetryMetrics(builder => - { - builder.ConfigureBuilder((sp, builder) => - { - configureBuilderCalled = true; + services.AddOpenTelemetry() + .WithMetrics(builder => builder + .ConfigureBuilder((sp, builder) => + { + configureBuilderCalled = true; - var configuration = sp.GetRequiredService(); + var configuration = sp.GetRequiredService(); - var testKeyValue = configuration.GetValue("TEST_KEY", null); + var testKeyValue = configuration.GetValue("TEST_KEY", null); - Assert.Equal("TEST_KEY_VALUE", testKeyValue); - }); - }); + Assert.Equal("TEST_KEY_VALUE", testKeyValue); + })) + .StartWithHost(); }); var host = builder.Build(); @@ -238,26 +102,5 @@ public async Task AddOpenTelemetryMetrics_HostConfigurationHonoredTest() host.Dispose(); } - - private static MeterProviderBuilder AddMyFeature(MeterProviderBuilder meterProviderBuilder) - { - meterProviderBuilder.ConfigureServices(services => services.AddSingleton()); - - return meterProviderBuilder.AddReader(); - } - - internal class TestInstrumentation : IDisposable - { - public bool Disposed { get; private set; } - - public void Dispose() - { - this.Disposed = true; - } - } - - internal class TestReader : MetricReader - { - } } } diff --git a/test/OpenTelemetry.Extensions.Hosting.Tests/HostingTracerExtensionTests.cs b/test/OpenTelemetry.Extensions.Hosting.Tests/HostingTracerExtensionTests.cs index 22432e3f4a7..2c1f666dc6d 100644 --- a/test/OpenTelemetry.Extensions.Hosting.Tests/HostingTracerExtensionTests.cs +++ b/test/OpenTelemetry.Extensions.Hosting.Tests/HostingTracerExtensionTests.cs @@ -14,10 +14,7 @@ // limitations under the License. // -using System; using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -30,178 +27,41 @@ namespace OpenTelemetry.Extensions.Hosting.Tests public class HostingTracerExtensionTests { [Fact] - public async Task AddOpenTelemetryTracerProviderInstrumentationCreationAndDisposal() + public async Task AddOpenTelemetry_StartWithHost_CreationAndDisposal() { - var testInstrumentation = new TestInstrumentation(); var callbackRun = false; var builder = new HostBuilder().ConfigureServices(services => { - services.AddOpenTelemetryTracing(builder => - { - builder.AddInstrumentation(() => - { - callbackRun = true; - return testInstrumentation; - }); - }); + services.AddOpenTelemetry() + .WithTracing(builder => builder + .AddInstrumentation(() => + { + callbackRun = true; + return new object(); + })) + .StartWithHost(); }); var host = builder.Build(); Assert.False(callbackRun); - Assert.False(testInstrumentation.Disposed); await host.StartAsync(); Assert.True(callbackRun); - Assert.False(testInstrumentation.Disposed); await host.StopAsync(); Assert.True(callbackRun); - Assert.False(testInstrumentation.Disposed); host.Dispose(); Assert.True(callbackRun); - Assert.True(testInstrumentation.Disposed); - } - - [Fact] - public void AddOpenTelemetryTracerProvider_HostBuilt_OpenTelemetrySdk_RegisteredAsSingleton() - { - var builder = new HostBuilder().ConfigureServices(services => - { - services.AddOpenTelemetryTracing(); - }); - - var host = builder.Build(); - - var tracerProvider1 = host.Services.GetRequiredService(); - var tracerProvider2 = host.Services.GetRequiredService(); - - Assert.Same(tracerProvider1, tracerProvider2); - } - - [Fact] - public void AddOpenTelemetryTracerProvider_ServiceProviderArgument_ServicesRegistered() - { - var testInstrumentation = new TestInstrumentation(); - - var services = new ServiceCollection(); - services.AddSingleton(testInstrumentation); - services.AddOpenTelemetryTracing(builder => - { - builder.ConfigureBuilder( - (sp, b) => b.AddInstrumentation(() => sp.GetRequiredService())); - }); - - var serviceProvider = services.BuildServiceProvider(); - - var tracerFactory = serviceProvider.GetRequiredService(); - Assert.NotNull(tracerFactory); - - Assert.False(testInstrumentation.Disposed); - - serviceProvider.Dispose(); - - Assert.True(testInstrumentation.Disposed); - } - - [Fact] - public void AddOpenTelemetryTracerProvider_BadArgs_NullServiceCollection() - { - ServiceCollection services = null; - Assert.Throws(() => services.AddOpenTelemetryTracing(null)); - Assert.Throws(() => - services.AddOpenTelemetryTracing(builder => - { - builder.ConfigureBuilder( - (sp, b) => b.AddInstrumentation(() => sp.GetRequiredService())); - })); } [Fact] - public void AddOpenTelemetryTracerProvider_GetServicesExtension() - { - var services = new ServiceCollection(); - services.AddOpenTelemetryTracing(builder => AddMyFeature(builder)); - - using var serviceProvider = services.BuildServiceProvider(); - - var tracerProvider = (TracerProviderSdk)serviceProvider.GetRequiredService(); - - Assert.True(tracerProvider.Sampler is TestSampler); - } - - [Fact] - public void AddOpenTelemetryTracerProvider_NestedConfigureCallbacks() - { - int configureCalls = 0; - var services = new ServiceCollection(); - services.AddOpenTelemetryTracing(builder => builder - .ConfigureBuilder((sp1, builder1) => - { - configureCalls++; - builder1.ConfigureBuilder((sp2, builder2) => - { - configureCalls++; - }); - })); - - using var serviceProvider = services.BuildServiceProvider(); - - var tracerFactory = serviceProvider.GetRequiredService(); - - Assert.Equal(2, configureCalls); - } - - [Fact] - public void AddOpenTelemetryTracerProvider_ConfigureCallbacksUsingExtensions() - { - var services = new ServiceCollection(); - - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - - services.AddOpenTelemetryTracing(builder => builder - .ConfigureBuilder((sp1, builder1) => - { - builder1 - .AddInstrumentation() - .AddProcessor() - .SetSampler(); - })); - - using var serviceProvider = services.BuildServiceProvider(); - - var tracerProvider = (TracerProviderSdk)serviceProvider.GetRequiredService(); - - Assert.True(tracerProvider.Instrumentations.FirstOrDefault() is TestInstrumentation); - Assert.True(tracerProvider.Processor is TestProcessor); - Assert.True(tracerProvider.Sampler is TestSampler); - } - - [Fact] - public void AddOpenTelemetryTracing_MultipleCallsConfigureSingleProvider() - { - var services = new ServiceCollection(); - - services.AddOpenTelemetryTracing(builder => builder.AddSource("TestSourceBuilder1")); - services.AddOpenTelemetryTracing(); - services.AddOpenTelemetryTracing(builder => builder.AddSource("TestSourceBuilder2")); - - using var serviceProvider = services.BuildServiceProvider(); - - var providers = serviceProvider.GetServices(); - - Assert.Single(providers); - } - - [Fact] - public async Task AddOpenTelemetryTracing_HostConfigurationHonoredTest() + public async Task AddOpenTelemetry_StartWithHost_HostConfigurationHonoredTest() { bool configureBuilderCalled = false; @@ -215,19 +75,19 @@ public async Task AddOpenTelemetryTracing_HostConfigurationHonoredTest() }) .ConfigureServices(services => { - services.AddOpenTelemetryTracing(builder => - { - builder.ConfigureBuilder((sp, builder) => - { - configureBuilderCalled = true; + services.AddOpenTelemetry() + .WithTracing(builder => builder + .ConfigureBuilder((sp, builder) => + { + configureBuilderCalled = true; - var configuration = sp.GetRequiredService(); + var configuration = sp.GetRequiredService(); - var testKeyValue = configuration.GetValue("TEST_KEY", null); + var testKeyValue = configuration.GetValue("TEST_KEY", null); - Assert.Equal("TEST_KEY_VALUE", testKeyValue); - }); - }); + Assert.Equal("TEST_KEY_VALUE", testKeyValue); + })) + .StartWithHost(); }); var host = builder.Build(); @@ -242,34 +102,5 @@ public async Task AddOpenTelemetryTracing_HostConfigurationHonoredTest() host.Dispose(); } - - private static TracerProviderBuilder AddMyFeature(TracerProviderBuilder tracerProviderBuilder) - { - tracerProviderBuilder.ConfigureServices(services => services.AddSingleton()); - - return tracerProviderBuilder.SetSampler(); - } - - internal class TestInstrumentation : IDisposable - { - public bool Disposed { get; private set; } - - public void Dispose() - { - this.Disposed = true; - } - } - - internal class TestProcessor : BaseProcessor - { - } - - internal class TestSampler : Sampler - { - public override SamplingResult ShouldSample(in SamplingParameters samplingParameters) - { - return new SamplingResult(SamplingDecision.RecordAndSample); - } - } } } diff --git a/test/OpenTelemetry.Extensions.Hosting.Tests/InMemoryExporterMetricsExtensionsTests.cs b/test/OpenTelemetry.Extensions.Hosting.Tests/InMemoryExporterMetricsExtensionsTests.cs index fc39977157b..c749b6f9ccb 100644 --- a/test/OpenTelemetry.Extensions.Hosting.Tests/InMemoryExporterMetricsExtensionsTests.cs +++ b/test/OpenTelemetry.Extensions.Hosting.Tests/InMemoryExporterMetricsExtensionsTests.cs @@ -89,7 +89,7 @@ private static async Task RunMetricsTest(Action configure, using var host = await new HostBuilder() .ConfigureWebHost(webBuilder => webBuilder .UseTestServer() - .ConfigureServices(services => services.AddOpenTelemetryMetrics(configure)) + .ConfigureServices(services => services.AddOpenTelemetry().WithMetrics(configure).StartWithHost()) .Configure(app => app.Run(httpContext => { testAction.Invoke(); diff --git a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs index 5c1e9548fad..598815fd969 100644 --- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs +++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs @@ -655,9 +655,12 @@ public async Task ActivitiesStartedInMiddlewareBySettingHostActivityToNullShould builder.ConfigureTestServices((IServiceCollection services) => { services.AddSingleton(new TestNullHostActivityMiddlewareImpl(activitySourceName, activityName)); - services.AddOpenTelemetryTracing((builder) => builder.AddAspNetCoreInstrumentation() - .AddSource(activitySourceName) - .AddInMemoryExporter(exportedItems)); + services.AddOpenTelemetry() + .WithTracing(builder => builder + .AddAspNetCoreInstrumentation() + .AddSource(activitySourceName) + .AddInMemoryExporter(exportedItems)) + .StartWithHost(); }); builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders()); }) @@ -692,11 +695,11 @@ public async Task UserRegisteredActivitySourceIsUsedForActivityCreationByAspNetC var exportedItems = new List(); void ConfigureTestServices(IServiceCollection services) { - services.AddOpenTelemetryTracing(options => - { - options.AddAspNetCoreInstrumentation() - .AddInMemoryExporter(exportedItems); - }); + services.AddOpenTelemetry() + .WithTracing(builder => builder + .AddAspNetCoreInstrumentation() + .AddInMemoryExporter(exportedItems)) + .StartWithHost(); // Register ActivitySource here so that it will be used // by ASP.NET Core to create activities diff --git a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/DependencyInjectionConfigTests.cs b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/DependencyInjectionConfigTests.cs index 447a54902ac..16136110509 100644 --- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/DependencyInjectionConfigTests.cs +++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/DependencyInjectionConfigTests.cs @@ -44,8 +44,10 @@ public void TestTracingOptionsDIConfig(string name) bool optionsPickedFromDI = false; void ConfigureTestServices(IServiceCollection services) { - services.AddOpenTelemetryTracing( - builder => builder.AddAspNetCoreInstrumentation(name, configureAspNetCoreInstrumentationOptions: null)); + services.AddOpenTelemetry() + .WithTracing(builder => builder + .AddAspNetCoreInstrumentation(name, configureAspNetCoreInstrumentationOptions: null)) + .StartWithHost(); services.Configure(name, options => { @@ -74,8 +76,10 @@ public void TestMetricsOptionsDIConfig(string name) bool optionsPickedFromDI = false; void ConfigureTestServices(IServiceCollection services) { - services.AddOpenTelemetryMetrics( - builder => builder.AddAspNetCoreInstrumentation(name, configureAspNetCoreInstrumentationOptions: null)); + services.AddOpenTelemetry() + .WithMetrics(builder => builder + .AddAspNetCoreInstrumentation(name, configureAspNetCoreInstrumentationOptions: null)) + .StartWithHost(); services.Configure(name, options => { @@ -85,9 +89,9 @@ void ConfigureTestServices(IServiceCollection services) // Arrange using (var client = this.factory - .WithWebHostBuilder(builder => - builder.ConfigureTestServices(ConfigureTestServices)) - .CreateClient()) + .WithWebHostBuilder(builder => + builder.ConfigureTestServices(ConfigureTestServices)) + .CreateClient()) { } diff --git a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/IncomingRequestsCollectionsIsAccordingToTheSpecTests.cs b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/IncomingRequestsCollectionsIsAccordingToTheSpecTests.cs index 930bbcd0eb6..a0836beea3a 100644 --- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/IncomingRequestsCollectionsIsAccordingToTheSpecTests.cs +++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/IncomingRequestsCollectionsIsAccordingToTheSpecTests.cs @@ -64,8 +64,11 @@ public async Task SuccessfulTemplateControllerCallGeneratesASpan( builder.ConfigureTestServices((IServiceCollection services) => { services.AddSingleton(new TestCallbackMiddlewareImpl(statusCode, reasonPhrase)); - services.AddOpenTelemetryTracing((builder) => builder.AddAspNetCoreInstrumentation(options => options.RecordException = recordException) - .AddInMemoryExporter(exportedItems)); + services.AddOpenTelemetry() + .WithTracing(builder => builder + .AddAspNetCoreInstrumentation(options => options.RecordException = recordException) + .AddInMemoryExporter(exportedItems)) + .StartWithHost(); }); builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders()); }) diff --git a/test/OpenTelemetry.Tests/Metrics/MeterProviderBuilderExtensionsTests.cs b/test/OpenTelemetry.Tests/Metrics/MeterProviderBuilderExtensionsTests.cs index 5fac30cdd53..da06b6fee69 100644 --- a/test/OpenTelemetry.Tests/Metrics/MeterProviderBuilderExtensionsTests.cs +++ b/test/OpenTelemetry.Tests/Metrics/MeterProviderBuilderExtensionsTests.cs @@ -32,8 +32,6 @@ public void ServiceLifecycleAvailableToSDKBuilderTest() { var builder = Sdk.CreateMeterProviderBuilder(); - builder.ConfigureServices(services => services.AddSingleton()); - MyInstrumentation myInstrumentation = null; RunBuilderServiceLifecycleTest( @@ -71,7 +69,7 @@ public void ServiceLifecycleAvailableToServicesBuilderTest() ServiceProvider serviceProvider = null; MeterProviderSdk provider = null; - services.ConfigureOpenTelemetryMetrics(builder => + services.AddOpenTelemetry().WithMetrics(builder => { testRun = true; @@ -111,12 +109,12 @@ public void SingleProviderForServiceCollectionTest() { var services = new ServiceCollection(); - services.ConfigureOpenTelemetryMetrics(builder => + services.AddOpenTelemetry().WithMetrics(builder => { builder.AddInstrumentation(() => new()); }); - services.ConfigureOpenTelemetryMetrics(builder => + services.AddOpenTelemetry().WithMetrics(builder => { builder.AddInstrumentation(() => new()); }); @@ -273,7 +271,7 @@ public void MeterProviderNestedResolutionUsingBuilderTest(bool callNestedConfigu { if (callNestedConfigure) { - services.ConfigureOpenTelemetryMetrics(); + services.AddOpenTelemetry().WithMetrics(builder => { }); } }) .ConfigureBuilder((sp, builder) => @@ -293,9 +291,9 @@ public void MeterProviderNestedResolutionUsingConfigureTest() { bool innerTestExecuted = false; - var serviceCollection = new ServiceCollection(); + var services = new ServiceCollection(); - serviceCollection.ConfigureOpenTelemetryMetrics(builder => + services.AddOpenTelemetry().WithMetrics(builder => { builder.ConfigureBuilder((sp, builder) => { @@ -304,7 +302,7 @@ public void MeterProviderNestedResolutionUsingConfigureTest() }); }); - using var serviceProvider = serviceCollection.BuildServiceProvider(); + using var serviceProvider = services.BuildServiceProvider(); var resolvedProvider = serviceProvider.GetRequiredService(); @@ -317,7 +315,6 @@ private static void RunBuilderServiceLifecycleTest( Action postAction) { var baseBuilder = builder as MeterProviderBuilderBase; - Assert.Null(baseBuilder.State); builder.AddMeter("TestSource"); @@ -328,12 +325,15 @@ private static void RunBuilderServiceLifecycleTest( Assert.NotNull(services); + services.TryAddSingleton(); services.TryAddSingleton(); - services.ConfigureOpenTelemetryMetrics(b => + // Note: This is strange to call ConfigureOpenTelemetryMeterProvider here, but supported + services.ConfigureOpenTelemetryMeterProvider((sp, b) => { - // Note: This is strange to call ConfigureOpenTelemetryMetrics here, but supported - b.AddInstrumentation(); + Assert.Throws(() => b.ConfigureServices(services => { })); + + b.AddInstrumentation(sp.GetRequiredService()); }); }); @@ -342,13 +342,13 @@ private static void RunBuilderServiceLifecycleTest( { configureBuilderInvocations++; - var baseBuilder = builder as MeterProviderBuilderBase; - Assert.NotNull(baseBuilder?.State); + var sdkBuilder = builder as MeterProviderBuilderSdk; + Assert.NotNull(sdkBuilder); builder.AddMeter("TestSource2"); - Assert.Contains(baseBuilder.State.MeterSources, s => s == "TestSource"); - Assert.Contains(baseBuilder.State.MeterSources, s => s == "TestSource2"); + Assert.Contains(sdkBuilder.MeterSources, s => s == "TestSource"); + Assert.Contains(sdkBuilder.MeterSources, s => s == "TestSource2"); // Note: Services can't be configured at this stage Assert.Throws( diff --git a/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs b/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs index 342fffe7107..3d20f3833ca 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs @@ -1356,26 +1356,26 @@ int MetricPointCount() // for no tag point! // This may be changed later. counterLong.Add(10); - for (int i = 0; i < MeterProviderBuilderState.MaxMetricPointsPerMetricDefault + 1; i++) + for (int i = 0; i < MeterProviderBuilderSdk.MaxMetricPointsPerMetricDefault + 1; i++) { counterLong.Add(10, new KeyValuePair("key", "value" + i)); } meterProvider.ForceFlush(MaxTimeToAllowForFlush); - Assert.Equal(MeterProviderBuilderState.MaxMetricPointsPerMetricDefault, MetricPointCount()); + Assert.Equal(MeterProviderBuilderSdk.MaxMetricPointsPerMetricDefault, MetricPointCount()); exportedItems.Clear(); counterLong.Add(10); - for (int i = 0; i < MeterProviderBuilderState.MaxMetricPointsPerMetricDefault + 1; i++) + for (int i = 0; i < MeterProviderBuilderSdk.MaxMetricPointsPerMetricDefault + 1; i++) { counterLong.Add(10, new KeyValuePair("key", "value" + i)); } meterProvider.ForceFlush(MaxTimeToAllowForFlush); - Assert.Equal(MeterProviderBuilderState.MaxMetricPointsPerMetricDefault, MetricPointCount()); + Assert.Equal(MeterProviderBuilderSdk.MaxMetricPointsPerMetricDefault, MetricPointCount()); counterLong.Add(10); - for (int i = 0; i < MeterProviderBuilderState.MaxMetricPointsPerMetricDefault + 1; i++) + for (int i = 0; i < MeterProviderBuilderSdk.MaxMetricPointsPerMetricDefault + 1; i++) { counterLong.Add(10, new KeyValuePair("key", "value" + i)); } @@ -1386,7 +1386,7 @@ int MetricPointCount() counterLong.Add(10, new KeyValuePair("key", "valueC")); exportedItems.Clear(); meterProvider.ForceFlush(MaxTimeToAllowForFlush); - Assert.Equal(MeterProviderBuilderState.MaxMetricPointsPerMetricDefault, MetricPointCount()); + Assert.Equal(MeterProviderBuilderSdk.MaxMetricPointsPerMetricDefault, MetricPointCount()); } [Fact] diff --git a/test/OpenTelemetry.Tests/Trace/TracerProviderBuilderExtensionsTest.cs b/test/OpenTelemetry.Tests/Trace/TracerProviderBuilderExtensionsTest.cs index f7b5149c1d6..fe7186eba8d 100644 --- a/test/OpenTelemetry.Tests/Trace/TracerProviderBuilderExtensionsTest.cs +++ b/test/OpenTelemetry.Tests/Trace/TracerProviderBuilderExtensionsTest.cs @@ -118,8 +118,6 @@ public void ServiceLifecycleAvailableToSDKBuilderTest() { var builder = Sdk.CreateTracerProviderBuilder(); - builder.ConfigureServices(services => services.AddSingleton()); - MyInstrumentation myInstrumentation = null; RunBuilderServiceLifecycleTest( @@ -157,7 +155,7 @@ public void ServiceLifecycleAvailableToServicesBuilderTest() ServiceProvider serviceProvider = null; TracerProviderSdk provider = null; - services.ConfigureOpenTelemetryTracing(builder => + services.AddOpenTelemetry().WithTracing(builder => { testRun = true; @@ -197,12 +195,12 @@ public void SingleProviderForServiceCollectionTest() { var services = new ServiceCollection(); - services.ConfigureOpenTelemetryTracing(builder => + services.AddOpenTelemetry().WithTracing(builder => { builder.AddInstrumentation(() => new()); }); - services.ConfigureOpenTelemetryTracing(builder => + services.AddOpenTelemetry().WithTracing(builder => { builder.AddInstrumentation(() => new()); }); @@ -359,7 +357,7 @@ public void TracerProviderNestedResolutionUsingBuilderTest(bool callNestedConfig { if (callNestedConfigure) { - services.ConfigureOpenTelemetryTracing(); + services.AddOpenTelemetry().WithTracing(builder => { }); } }) .ConfigureBuilder((sp, builder) => @@ -379,9 +377,9 @@ public void TracerProviderNestedResolutionUsingConfigureTest() { bool innerTestExecuted = false; - var serviceCollection = new ServiceCollection(); + var services = new ServiceCollection(); - serviceCollection.ConfigureOpenTelemetryTracing(builder => + services.AddOpenTelemetry().WithTracing(builder => { builder.ConfigureBuilder((sp, builder) => { @@ -390,7 +388,7 @@ public void TracerProviderNestedResolutionUsingConfigureTest() }); }); - using var serviceProvider = serviceCollection.BuildServiceProvider(); + using var serviceProvider = services.BuildServiceProvider(); var resolvedProvider = serviceProvider.GetRequiredService(); @@ -403,7 +401,6 @@ private static void RunBuilderServiceLifecycleTest( Action postAction) { var baseBuilder = builder as TracerProviderBuilderBase; - Assert.Null(baseBuilder.State); builder .AddSource("TestSource") @@ -417,12 +414,15 @@ private static void RunBuilderServiceLifecycleTest( Assert.NotNull(services); + services.TryAddSingleton(); services.TryAddSingleton(); - services.ConfigureOpenTelemetryTracing(b => + // Note: This is strange to call ConfigureOpenTelemetryTracerProvider here, but supported + services.ConfigureOpenTelemetryTracerProvider((sp, b) => { - // Note: This is strange to call ConfigureOpenTelemetryTracing here, but supported - b.AddInstrumentation(); + Assert.Throws(() => b.ConfigureServices(services => { })); + + b.AddInstrumentation(sp.GetRequiredService()); }); }); @@ -431,17 +431,17 @@ private static void RunBuilderServiceLifecycleTest( { configureBuilderInvocations++; - var baseBuilder = builder as TracerProviderBuilderBase; - Assert.NotNull(baseBuilder?.State); + var sdkBuilder = builder as TracerProviderBuilderSdk; + Assert.NotNull(sdkBuilder); builder .AddSource("TestSource2") .AddLegacySource("TestLegacySource2"); - Assert.Contains(baseBuilder.State.Sources, s => s == "TestSource"); - Assert.Contains(baseBuilder.State.Sources, s => s == "TestSource2"); - Assert.Contains(baseBuilder.State.LegacyActivityOperationNames, s => s == "TestLegacySource"); - Assert.Contains(baseBuilder.State.LegacyActivityOperationNames, s => s == "TestLegacySource2"); + Assert.Contains(sdkBuilder.Sources, s => s == "TestSource"); + Assert.Contains(sdkBuilder.Sources, s => s == "TestSource2"); + Assert.Contains(sdkBuilder.LegacyActivityOperationNames, s => s == "TestLegacySource"); + Assert.Contains(sdkBuilder.LegacyActivityOperationNames, s => s == "TestLegacySource2"); // Note: Services can't be configured at this stage Assert.Throws(