[DependencyInjection] Introduce new package and refactor SDK (#3923)

This commit is contained in:
Mikel Blanchard 2022-12-08 15:24:44 -08:00 committed by GitHub
parent f0f5158ba1
commit 9836d3addb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
84 changed files with 3169 additions and 2102 deletions

View File

@ -238,9 +238,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "redaction", "docs\logs\reda
EndProject 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}" 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 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 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 EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution 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}.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.ActiveCfg = Release|Any CPU
{011E70E1-152A-47BB-AF83-12DD12B125ED}.Release|Any CPU.Build.0 = 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 {171A87CB-393C-4296-913F-E704CD8CEAE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{329AD438-6D15-4432-99BE-B0E85F00B3CB}.Debug|Any CPU.Build.0 = Debug|Any CPU {171A87CB-393C-4296-913F-E704CD8CEAE9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{329AD438-6D15-4432-99BE-B0E85F00B3CB}.Release|Any CPU.ActiveCfg = Release|Any CPU {171A87CB-393C-4296-913F-E704CD8CEAE9}.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}.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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -541,7 +547,6 @@ Global
{9A07D215-90AC-4BAF-BCDB-73D74FD3A5C5} = {3862190B-E2C5-418E-AFDC-DB281FB5C705} {9A07D215-90AC-4BAF-BCDB-73D74FD3A5C5} = {3862190B-E2C5-418E-AFDC-DB281FB5C705}
{5FDAF679-DE5A-4C73-A49B-8ABCF2399229} = {77C7929A-2EED-4AA6-8705-B5C443C8AA0F} {5FDAF679-DE5A-4C73-A49B-8ABCF2399229} = {77C7929A-2EED-4AA6-8705-B5C443C8AA0F}
{A2DF46DE-50D7-4887-8C9D-4BD79CA19FAA} = {3862190B-E2C5-418E-AFDC-DB281FB5C705} {A2DF46DE-50D7-4887-8C9D-4BD79CA19FAA} = {3862190B-E2C5-418E-AFDC-DB281FB5C705}
{329AD438-6D15-4432-99BE-B0E85F00B3CB} = {5B7FB835-3FFF-4BC2-99C5-A5B5FAE3C818}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {55639B5C-0770-4A22-AB56-859604650521} SolutionGuid = {55639B5C-0770-4A22-AB56-859604650521}

View File

@ -35,6 +35,7 @@
<MicrosoftCodeAnalysisAnalyzersPkgVer>[3.3.3]</MicrosoftCodeAnalysisAnalyzersPkgVer> <MicrosoftCodeAnalysisAnalyzersPkgVer>[3.3.3]</MicrosoftCodeAnalysisAnalyzersPkgVer>
<MicrosoftCodeCoveragePkgVer>[17.3.0]</MicrosoftCodeCoveragePkgVer> <MicrosoftCodeCoveragePkgVer>[17.3.0]</MicrosoftCodeCoveragePkgVer>
<MicrosoftExtensionsConfigurationEnvironmentVariablesPkgVer>[3.1.0,)</MicrosoftExtensionsConfigurationEnvironmentVariablesPkgVer> <MicrosoftExtensionsConfigurationEnvironmentVariablesPkgVer>[3.1.0,)</MicrosoftExtensionsConfigurationEnvironmentVariablesPkgVer>
<MicrosoftExtensionsDependencyInjectionAbstractionsPkgVer>[3.1.0,)</MicrosoftExtensionsDependencyInjectionAbstractionsPkgVer>
<MicrosoftExtensionsHostingAbstractionsPkgVer>[2.1.0,)</MicrosoftExtensionsHostingAbstractionsPkgVer> <MicrosoftExtensionsHostingAbstractionsPkgVer>[2.1.0,)</MicrosoftExtensionsHostingAbstractionsPkgVer>
<MicrosoftExtensionsLoggingPkgVer>[3.1.0,)</MicrosoftExtensionsLoggingPkgVer> <MicrosoftExtensionsLoggingPkgVer>[3.1.0,)</MicrosoftExtensionsLoggingPkgVer>
<MicrosoftExtensionsLoggingConfigurationPkgVer>[3.1.0,)</MicrosoftExtensionsLoggingConfigurationPkgVer> <MicrosoftExtensionsLoggingConfigurationPkgVer>[3.1.0,)</MicrosoftExtensionsLoggingConfigurationPkgVer>

View File

@ -411,21 +411,24 @@ var appBuilder = WebApplication.CreateBuilder(args);
appBuilder.Services.AddSingleton<MyCustomService>(); appBuilder.Services.AddSingleton<MyCustomService>();
appBuilder.Services.AddOpenTelemetryTracing(builder => builder appBuilder.Services.AddOpenTelemetry()
.AddProcessor<MyCustomProcessor>(); .WithTracing(builder => builder
.AddProcessor<MyCustomProcessor>())
.StartWithHost();
``` ```
When using the `AddOpenTelemetryTracing` method the `TracerProvider` does not When using the `AddOpenTelemetry` & `WithTracing` extension methods the
own its `IServiceCollection` and instead registers into an existing collection `TracerProvider` does not own its `IServiceCollection` and instead registers
(typically the collection used is the one managed by the application host). The into an existing collection (typically the collection used is the one managed by
`TracerProviderBuilder` will be able to access all services registered into that the application host). The `TracerProviderBuilder` will be able to access all
collection. For lifecycle management, an [IHostedService services registered into that collection. For lifecycle management, the
`StartWithHost` registers an [IHostedService
](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.ihostedservice) ](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.ihostedservice)
is used to automatically start the `TracerProvider` when the host starts and the which is used to automatically start the `TracerProvider` when the host starts
host will automatically shutdown and dispose the `TracerProvider` when it is and the host will automatically shutdown and dispose the `TracerProvider` when
shutdown. 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 `TracerProvider`. Only a single `TraceProvider` may exist in an
`IServiceCollection` \ `IServiceProvider`. `IServiceCollection` \ `IServiceProvider`.
@ -451,15 +454,17 @@ shutdown.
```csharp ```csharp
var appBuilder = WebApplication.CreateBuilder(args); var appBuilder = WebApplication.CreateBuilder(args);
appBuilder.Services.AddOpenTelemetryTracing(builder => builder appBuilder.Services.AddOpenTelemetry()
.ConfigureBuilder((sp, builder) => .WithTracing(builder => builder
{ .ConfigureBuilder((sp, builder) =>
builder.AddProcessor( {
new MyCustomProcessor( builder.AddProcessor(
// Note: This example uses the final IServiceProvider once it is available. new MyCustomProcessor(
sp.GetRequiredService<MyCustomService>(), // Note: This example uses the final IServiceProvider once it is available.
sp.GetRequiredService<IOptions<MyOptions>>().Value)); sp.GetRequiredService<MyCustomService>(),
})); sp.GetRequiredService<IOptions<MyOptions>>().Value));
}))
.StartWithHost();
``` ```
**Note:** `ConfigureBuilder` is an advanced API and is expected to be used **Note:** `ConfigureBuilder` is an advanced API and is expected to be used
@ -612,8 +617,9 @@ var appBuilder = WebApplication.CreateBuilder(args);
appBuilder.Services.Configure<JaegerExporterOptions>( appBuilder.Services.Configure<JaegerExporterOptions>(
appBuilder.Configuration.GetSection("OpenTelemetry:Jaeger")); appBuilder.Configuration.GetSection("OpenTelemetry:Jaeger"));
appBuilder.Services.AddOpenTelemetryTracing( appBuilder.Services.AddOpenTelemetry()
builder => builder.AddJaegerExporter()); .WithTracing(builder => builder.AddJaegerExporter())
.StartWithHost();
``` ```
The OpenTelemetry .NET SDK supports running multiple `TracerProvider`s inside The OpenTelemetry .NET SDK supports running multiple `TracerProvider`s inside
@ -654,7 +660,9 @@ appBuilder.Services.Configure<JaegerExporterOptions>(
"JaegerSecondary", "JaegerSecondary",
appBuilder.Configuration.GetSection("OpenTelemetry:JaegerSecondary")); appBuilder.Configuration.GetSection("OpenTelemetry:JaegerSecondary"));
appBuilder.Services.AddOpenTelemetryTracing(builder => builder appBuilder.Services.AddOpenTelemetry()
.AddJaegerExporter(name: "JaegerPrimary", configure: null) .WithTracing(builder => builder
.AddJaegerExporter(name: "JaegerSecondary", configure: null)); .AddJaegerExporter(name: "JaegerPrimary", configure: null)
.AddJaegerExporter(name: "JaegerSecondary", configure: null))
.StartWithHost();
``` ```

View File

@ -530,7 +530,7 @@ the target type for registration extension methods.
The following example shows how a library might enable tracing and metric The following example shows how a library might enable tracing and metric
support using an `IServiceCollection` extension by calling support using an `IServiceCollection` extension by calling
`ConfigureOpenTelemetryTracing`. `ConfigureOpenTelemetryTracerProvider`.
```csharp ```csharp
using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.DependencyInjection.Extensions;
@ -563,7 +563,7 @@ namespace Microsoft.Extensions.DependencyInjection
} }
// Configure OpenTelemetry tracing. // Configure OpenTelemetry tracing.
services.ConfigureOpenTelemetryTracing(builder => builder.ConfigureBuilder((sp, builder) => services.ConfigureOpenTelemetryTracerProvider((sp, builder) =>
{ {
var options = sp.GetRequiredService<IOptionsMonitor<MyLibraryOptions>>().Get(name); var options = sp.GetRequiredService<IOptionsMonitor<MyLibraryOptions>>().Get(name);
if (options.EnableTracing) if (options.EnableTracing)
@ -573,7 +573,7 @@ namespace Microsoft.Extensions.DependencyInjection
})); }));
// Configure OpenTelemetry metrics. // Configure OpenTelemetry metrics.
services.ConfigureOpenTelemetryMetrics(builder => builder.ConfigureBuilder((sp, builder) => services.ConfigureOpenTelemetryMeterProvider((sp, builder) =>
{ {
var options = sp.GetRequiredService<IOptionsMonitor<MyLibraryOptions>>().Get(name); var options = sp.GetRequiredService<IOptionsMonitor<MyLibraryOptions>>().Get(name);
if (options.EnableMetrics) 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 turn on OpenTelemetry integration for multiple signals (tracing & metrics in
this case). this case).
**Note:** `ConfigureOpenTelemetryTracing` does not automatically start **Note:** `ConfigureOpenTelemetryTracerProvider` does not automatically start
OpenTelemetry. The host is responsible for either calling OpenTelemetry. The host is responsible for either calling `StartWithHost` in the
`AddOpenTelemetryTracing` in the
[OpenTelemetry.Extensions.Hosting](../../../src/OpenTelemetry.Extensions.Hosting/README.md) [OpenTelemetry.Extensions.Hosting](../../../src/OpenTelemetry.Extensions.Hosting/README.md)
package, calling `Build` when using the `Sdk.CreateTracerProviderBuilder` package, calling `Build` when using the `Sdk.CreateTracerProviderBuilder`
method, or by accessing the `TracerProvider` from the `IServiceCollection` where method, or by accessing the `TracerProvider` from the `IServiceCollection` where
`ConfigureOpenTelemetryTracing` was performed. `ConfigureOpenTelemetryTracerProvider` was performed.
When providing `IServiceCollection` registration extensions: When providing `IServiceCollection` registration extensions:

View File

@ -15,6 +15,7 @@
// </copyright> // </copyright>
using System.Reflection; using System.Reflection;
using OpenTelemetry;
using OpenTelemetry.Exporter; using OpenTelemetry.Exporter;
using OpenTelemetry.Instrumentation.AspNetCore; using OpenTelemetry.Instrumentation.AspNetCore;
using OpenTelemetry.Logs; using OpenTelemetry.Logs;
@ -22,83 +23,122 @@ using OpenTelemetry.Metrics;
using OpenTelemetry.Resources; using OpenTelemetry.Resources;
using OpenTelemetry.Trace; using OpenTelemetry.Trace;
var builder = WebApplication.CreateBuilder(args); var appBuilder = WebApplication.CreateBuilder(args);
// OpenTelemetry // Note: Switch between Zipkin/Jaeger/OTLP/Console by setting UseTracingExporter in appsettings.json.
var assemblyVersion = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "unknown"; var tracingExporter = appBuilder.Configuration.GetValue<string>("UseTracingExporter").ToLowerInvariant();
// Switch between Zipkin/Jaeger/OTLP/Console by setting UseTracingExporter in appsettings.json. // Note: Switch between Prometheus/OTLP/Console by setting UseMetricsExporter in appsettings.json.
var tracingExporter = builder.Configuration.GetValue<string>("UseTracingExporter").ToLowerInvariant(); var metricsExporter = appBuilder.Configuration.GetValue<string>("UseMetricsExporter").ToLowerInvariant();
var serviceName = tracingExporter switch // Note: Switch between Console/OTLP by setting UseLogExporter in appsettings.json.
{ var logExporter = appBuilder.Configuration.GetValue<string>("UseLogExporter").ToLowerInvariant();
"jaeger" => builder.Configuration.GetValue<string>("Jaeger:ServiceName"),
"zipkin" => builder.Configuration.GetValue<string>("Zipkin:ServiceName"),
"otlp" => builder.Configuration.GetValue<string>("Otlp:ServiceName"),
_ => "AspNetCoreExampleService",
};
// Build a resource configuration action to set service information.
Action<ResourceBuilder> configureResource = r => r.AddService( Action<ResourceBuilder> configureResource = r => r.AddService(
serviceName, serviceVersion: assemblyVersion, serviceInstanceId: Environment.MachineName); serviceName: appBuilder.Configuration.GetValue<string>("ServiceName"),
serviceVersion: Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "unknown",
serviceInstanceId: Environment.MachineName);
// Traces // Configure OpenTelemetry tracing & metrics with auto-start using the
builder.Services.AddOpenTelemetryTracing(options => // StartWithHost extension from OpenTelemetry.Extensions.Hosting.
{ appBuilder.Services.AddOpenTelemetry()
options .ConfigureResource(configureResource)
.ConfigureResource(configureResource) .WithTracing(builder =>
.SetSampler(new AlwaysOnSampler())
.AddHttpClientInstrumentation()
.AddAspNetCoreInstrumentation();
switch (tracingExporter)
{ {
case "jaeger": // Tracing
options.AddJaegerExporter();
builder.Services.Configure<JaegerExporterOptions>(builder.Configuration.GetSection("Jaeger")); builder
.SetSampler(new AlwaysOnSampler())
.AddHttpClientInstrumentation()
.AddAspNetCoreInstrumentation();
// Customize the HttpClient that will be used when JaegerExporter is configured for HTTP transport. // Use IConfiguration binding for AspNetCore instrumentation options.
builder.Services.AddHttpClient("JaegerExporter", configureClient: (client) => client.DefaultRequestHeaders.Add("X-MyCustomHeader", "value")); appBuilder.Services.Configure<AspNetCoreInstrumentationOptions>(appBuilder.Configuration.GetSection("AspNetCoreInstrumentation"));
break;
case "zipkin": switch (tracingExporter)
options.AddZipkinExporter(); {
case "jaeger":
builder.AddJaegerExporter();
builder.Services.Configure<ZipkinExporterOptions>(builder.Configuration.GetSection("Zipkin")); builder.ConfigureServices(services =>
break;
case "otlp":
options.AddOtlpExporter(otlpOptions =>
{ {
otlpOptions.Endpoint = new Uri(builder.Configuration.GetValue<string>("Otlp:Endpoint")); // Use IConfiguration binding for Jaeger exporter options.
services.Configure<JaegerExporterOptions>(appBuilder.Configuration.GetSection("Jaeger"));
// 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; break;
default: case "zipkin":
options.AddConsoleExporter(); builder.AddZipkinExporter();
break; builder.ConfigureServices(services =>
} {
}); // Use IConfiguration binding for Zipkin exporter options.
services.Configure<ZipkinExporterOptions>(appBuilder.Configuration.GetSection("Zipkin"));
});
break;
// For options which can be bound from IConfiguration. case "otlp":
builder.Services.Configure<AspNetCoreInstrumentationOptions>(builder.Configuration.GetSection("AspNetCoreInstrumentation")); builder.AddOtlpExporter(otlpOptions =>
{
// Use IConfiguration directly for Otlp exporter endpoint option.
otlpOptions.Endpoint = new Uri(appBuilder.Configuration.GetValue<string>("Otlp:Endpoint"));
});
break;
// Logging default:
builder.Logging.ClearProviders(); builder.AddConsoleExporter();
break;
}
})
.WithMetrics(builder =>
{
// Metrics
builder.Logging.AddOpenTelemetry(options => 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<string>("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 =>
{ {
// Note: See appsettings.json Logging:OpenTelemetry section for configuration.
options.ConfigureResource(configureResource); options.ConfigureResource(configureResource);
// Switch between Console/OTLP by setting UseLogExporter in appsettings.json.
var logExporter = builder.Configuration.GetValue<string>("UseLogExporter").ToLowerInvariant();
switch (logExporter) switch (logExporter)
{ {
case "otlp": case "otlp":
options.AddOtlpExporter(otlpOptions => options.AddOtlpExporter(otlpOptions =>
{ {
otlpOptions.Endpoint = new Uri(builder.Configuration.GetValue<string>("Otlp:Endpoint")); // Use IConfiguration directly for Otlp exporter endpoint option.
otlpOptions.Endpoint = new Uri(appBuilder.Configuration.GetValue<string>("Otlp:Endpoint"));
}); });
break; break;
default: default:
@ -107,52 +147,14 @@ builder.Logging.AddOpenTelemetry(options =>
} }
}); });
builder.Services.Configure<OpenTelemetryLoggerOptions>(opt => appBuilder.Services.AddControllers();
{
opt.IncludeScopes = true;
opt.ParseStateValues = true;
opt.IncludeFormattedMessage = true;
});
// Metrics appBuilder.Services.AddEndpointsApiExplorer();
// Switch between Prometheus/OTLP/Console by setting UseMetricsExporter in appsettings.json.
var metricsExporter = builder.Configuration.GetValue<string>("UseMetricsExporter").ToLowerInvariant();
builder.Services.AddOpenTelemetryMetrics(options => appBuilder.Services.AddSwaggerGen();
{
options.ConfigureResource(configureResource)
.AddRuntimeInstrumentation()
.AddHttpClientInstrumentation()
.AddAspNetCoreInstrumentation();
switch (metricsExporter) var app = appBuilder.Build();
{
case "prometheus":
options.AddPrometheusExporter();
break;
case "otlp":
options.AddOtlpExporter(otlpOptions =>
{
otlpOptions.Endpoint = new Uri(builder.Configuration.GetValue<string>("Otlp:Endpoint"));
});
break;
default:
options.AddConsoleExporter();
break;
}
});
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()) if (app.Environment.IsDevelopment())
{ {
app.UseSwagger(); app.UseSwagger();
@ -165,6 +167,7 @@ app.UseAuthorization();
app.MapControllers(); app.MapControllers();
// Configure OpenTelemetry Prometheus AspNetCore middleware scrape endpoint if enabled.
if (metricsExporter.Equals("prometheus", StringComparison.OrdinalIgnoreCase)) if (metricsExporter.Equals("prometheus", StringComparison.OrdinalIgnoreCase))
{ {
app.UseOpenTelemetryPrometheusScrapingEndpoint(); app.UseOpenTelemetryPrometheusScrapingEndpoint();

View File

@ -1,27 +1,29 @@
{ {
"Logging": { "Logging": {
"LogLevel": { "LogLevel": {
"Default": "Information", "Default": "Information"
"Microsoft.AspNetCore": "Warning" },
"OpenTelemetry": {
"IncludeFormattedMessage": true,
"IncludeScopes": true,
"ParseStateValues": true
} }
}, },
"ServiceName": "otel-test",
"AllowedHosts": "*", "AllowedHosts": "*",
"UseTracingExporter": "console", "UseTracingExporter": "console",
"UseMetricsExporter": "console", "UseMetricsExporter": "console",
"UseLogExporter": "console", "UseLogExporter": "console",
"Jaeger": { "Jaeger": {
"ServiceName": "jaeger-test",
"AgentHost": "localhost", "AgentHost": "localhost",
"AgentPort": 6831, "AgentPort": 6831,
"Endpoint": "http://localhost:14268", "Endpoint": "http://localhost:14268",
"Protocol": "UdpCompactThrift" "Protocol": "UdpCompactThrift"
}, },
"Zipkin": { "Zipkin": {
"ServiceName": "zipkin-test",
"Endpoint": "http://localhost:9411/api/v2/spans" "Endpoint": "http://localhost:9411/api/v2/spans"
}, },
"Otlp": { "Otlp": {
"ServiceName": "otlp-test",
"Endpoint": "http://localhost:4317" "Endpoint": "http://localhost:4317"
}, },
"AspNetCoreInstrumentation": { "AspNetCoreInstrumentation": {

View File

@ -21,6 +21,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using OpenTelemetry;
using OpenTelemetry.Resources; using OpenTelemetry.Resources;
using OpenTelemetry.Trace; using OpenTelemetry.Trace;
@ -39,34 +40,36 @@ namespace Examples.GrpcService
{ {
services.AddGrpc(); services.AddGrpc();
// Switch between Jaeger/Zipkin by setting UseExporter in appsettings.json. services.AddOpenTelemetry()
var exporter = this.Configuration.GetValue<string>("UseExporter").ToLowerInvariant(); .WithTracing(builder =>
switch (exporter) {
{ builder
case "jaeger": .ConfigureResource(r => r.AddService(this.Configuration.GetValue<string>("ServiceName")))
services.AddOpenTelemetryTracing((builder) => builder .AddAspNetCoreInstrumentation();
.ConfigureResource(r => r.AddService(this.Configuration.GetValue<string>("Jaeger:ServiceName")))
.AddAspNetCoreInstrumentation() // Switch between Jaeger/Zipkin/Console by setting UseExporter in appsettings.json.
.AddJaegerExporter(jaegerOptions => var exporter = this.Configuration.GetValue<string>("UseExporter").ToLowerInvariant();
{ switch (exporter)
jaegerOptions.AgentHost = this.Configuration.GetValue<string>("Jaeger:Host"); {
jaegerOptions.AgentPort = this.Configuration.GetValue<int>("Jaeger:Port"); case "jaeger":
})); builder.AddJaegerExporter(jaegerOptions =>
break; {
case "zipkin": jaegerOptions.AgentHost = this.Configuration.GetValue<string>("Jaeger:Host");
services.AddOpenTelemetryTracing((builder) => builder jaegerOptions.AgentPort = this.Configuration.GetValue<int>("Jaeger:Port");
.AddAspNetCoreInstrumentation() });
.AddZipkinExporter(zipkinOptions => break;
{ case "zipkin":
zipkinOptions.Endpoint = new Uri(this.Configuration.GetValue<string>("Zipkin:Endpoint")); builder.AddZipkinExporter(zipkinOptions =>
})); {
break; zipkinOptions.Endpoint = new Uri(this.Configuration.GetValue<string>("Zipkin:Endpoint"));
default: });
services.AddOpenTelemetryTracing((builder) => builder break;
.AddAspNetCoreInstrumentation() default:
.AddConsoleExporter()); builder.AddConsoleExporter();
break; break;
} }
})
.StartWithHost();
} }
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

View File

@ -12,14 +12,13 @@
"Protocols": "Http2" "Protocols": "Http2"
} }
}, },
"ServiceName": "otel-test",
"UseExporter": "console", "UseExporter": "console",
"Jaeger": { "Jaeger": {
"ServiceName": "jaeger-test",
"Host": "localhost", "Host": "localhost",
"Port": 6831 "Port": 6831
}, },
"Zipkin": { "Zipkin": {
"ServiceName": "zipkin-test",
"Endpoint": "http://localhost:9411/api/v2/spans" "Endpoint": "http://localhost:9411/api/v2/spans"
} }
} }

View File

@ -20,6 +20,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using OpenTelemetry;
using OpenTelemetry.Trace; using OpenTelemetry.Trace;
using Utils.Messaging; using Utils.Messaging;
@ -40,14 +41,16 @@ namespace WebApi
services.AddSingleton<MessageSender>(); services.AddSingleton<MessageSender>();
services.AddOpenTelemetryTracing((builder) => builder services.AddOpenTelemetry()
.AddAspNetCoreInstrumentation() .WithTracing(builder => builder
.AddSource(nameof(MessageSender)) .AddAspNetCoreInstrumentation()
.AddZipkinExporter(b => .AddSource(nameof(MessageSender))
{ .AddZipkinExporter(b =>
var zipkinHostName = Environment.GetEnvironmentVariable("ZIPKIN_HOSTNAME") ?? "localhost"; {
b.Endpoint = new Uri($"http://{zipkinHostName}:9411/api/v2/spans"); 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) public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

View File

@ -17,6 +17,7 @@
using System; using System;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using OpenTelemetry;
using OpenTelemetry.Trace; using OpenTelemetry.Trace;
using Utils.Messaging; using Utils.Messaging;
@ -37,16 +38,15 @@ namespace WorkerService
services.AddSingleton<MessageReceiver>(); services.AddSingleton<MessageReceiver>();
services.AddOpenTelemetryTracing(builder => services.AddOpenTelemetry()
{ .WithTracing(builder => builder
builder
.AddSource(nameof(MessageReceiver)) .AddSource(nameof(MessageReceiver))
.AddZipkinExporter(b => .AddZipkinExporter(b =>
{ {
var zipkinHostName = Environment.GetEnvironmentVariable("ZIPKIN_HOSTNAME") ?? "localhost"; var zipkinHostName = Environment.GetEnvironmentVariable("ZIPKIN_HOSTNAME") ?? "localhost";
b.Endpoint = new Uri($"http://{zipkinHostName}:9411/api/v2/spans"); b.Endpoint = new Uri($"http://{zipkinHostName}:9411/api/v2/spans");
}); }))
}); .StartWithHost();
}); });
} }
} }

View File

@ -90,17 +90,19 @@ who want to configure the `HttpClient` used by the `JaegerExporter` when
implementation if you want to customize the generated `HttpClient`: implementation if you want to customize the generated `HttpClient`:
```csharp ```csharp
services.AddOpenTelemetryTracing((builder) => builder services.AddOpenTelemetry()
.AddJaegerExporter(o => .WithTracing(builder => builder
{ .AddJaegerExporter(o =>
o.Protocol = JaegerExportProtocol.HttpBinaryThrift;
o.HttpClientFactory = () =>
{ {
HttpClient client = new HttpClient(); o.Protocol = JaegerExportProtocol.HttpBinaryThrift;
client.DefaultRequestHeaders.Add("X-MyCustomHeader", "value"); o.HttpClientFactory = () =>
return client; {
}; HttpClient client = new HttpClient();
})); client.DefaultRequestHeaders.Add("X-MyCustomHeader", "value");
return client;
};
}))
.StartWithHost();
``` ```
For users using For users using

View File

@ -127,17 +127,19 @@ function with your own implementation if you want to customize the generated
`HttpClient`: `HttpClient`:
```csharp ```csharp
services.AddOpenTelemetryTracing((builder) => builder services.AddOpenTelemetry()
.AddOtlpExporter(o => .WithTracing(builder => builder
{ .AddOtlpExporter(o =>
o.Protocol = OtlpExportProtocol.HttpProtobuf;
o.HttpClientFactory = () =>
{ {
HttpClient client = new HttpClient(); o.Protocol = OtlpExportProtocol.HttpProtobuf;
client.DefaultRequestHeaders.Add("X-MyCustomHeader", "value"); o.HttpClientFactory = () =>
return client; {
}; HttpClient client = new HttpClient();
})); client.DefaultRequestHeaders.Add("X-MyCustomHeader", "value");
return client;
};
}))
.StartWithHost();
``` ```
For users using For users using

View File

@ -26,10 +26,10 @@ dotnet add package --prerelease OpenTelemetry.Exporter.Prometheus.AspNetCore
package on .NET 6.0+: package on .NET 6.0+:
```csharp ```csharp
services.AddOpenTelemetryMetrics(builder => services.AddOpenTelemetry()
{ .WithMetrics(builder => builder
builder.AddPrometheusExporter(); .AddPrometheusExporter())
}); .StartWithHost();
``` ```
* Or configure directly: * Or configure directly:

View File

@ -83,13 +83,15 @@ replace the function with your own implementation if you want to customize the
generated `HttpClient`: generated `HttpClient`:
```csharp ```csharp
services.AddOpenTelemetryTracing((builder) => builder services.AddOpenTelemetry()
.AddZipkinExporter(o => o.HttpClientFactory = () => .WithTracing(builder => builder
{ .AddZipkinExporter(o => o.HttpClientFactory = () =>
HttpClient client = new HttpClient(); {
client.DefaultRequestHeaders.Add("X-MyCustomHeader", "value"); HttpClient client = new HttpClient();
return client; client.DefaultRequestHeaders.Add("X-MyCustomHeader", "value");
})); return client;
}))
.StartWithHost();
``` ```
For users using For users using

View File

@ -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<System.IServiceProvider!, OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
OpenTelemetry.Metrics.IMeterProviderBuilder.ConfigureServices(System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection!>! 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<System.IServiceProvider!, OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
OpenTelemetry.Trace.ITracerProviderBuilder.ConfigureServices(System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
OpenTelemetry.Trace.ITracerProviderBuilder.Provider.get -> OpenTelemetry.Trace.TracerProvider?
OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions
OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracingServiceCollectionExtensions
static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Func<System.IServiceProvider!, OpenTelemetry.Metrics.MeterProvider!, T!>! instrumentationFactory) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Func<System.IServiceProvider!, T!>! instrumentationFactory) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, T! instrumentation) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action<System.IServiceProvider!, OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMetricsServiceCollectionExtensions.ConfigureOpenTelemetryMeterProvider(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action<System.IServiceProvider!, OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Func<System.IServiceProvider!, OpenTelemetry.Trace.TracerProvider!, T!>! instrumentationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Func<System.IServiceProvider!, T!>! instrumentationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, T! instrumentation) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action<System.IServiceProvider!, OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracingServiceCollectionExtensions.ConfigureOpenTelemetryTracerProvider(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action<System.IServiceProvider!, OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!

View File

@ -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<System.IServiceProvider!, OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
OpenTelemetry.Metrics.IMeterProviderBuilder.ConfigureServices(System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection!>! 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<System.IServiceProvider!, OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
OpenTelemetry.Trace.ITracerProviderBuilder.ConfigureServices(System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
OpenTelemetry.Trace.ITracerProviderBuilder.Provider.get -> OpenTelemetry.Trace.TracerProvider?
OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions
OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracingServiceCollectionExtensions
static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Func<System.IServiceProvider!, OpenTelemetry.Metrics.MeterProvider!, T!>! instrumentationFactory) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Func<System.IServiceProvider!, T!>! instrumentationFactory) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, T! instrumentation) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action<System.IServiceProvider!, OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.OpenTelemetryDependencyInjectionMetricsServiceCollectionExtensions.ConfigureOpenTelemetryMeterProvider(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action<System.IServiceProvider!, OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Func<System.IServiceProvider!, OpenTelemetry.Trace.TracerProvider!, T!>! instrumentationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Func<System.IServiceProvider!, T!>! instrumentationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, T! instrumentation) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action<System.IServiceProvider!, OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracingServiceCollectionExtensions.ConfigureOpenTelemetryTracerProvider(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action<System.IServiceProvider!, OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!

View File

@ -0,0 +1,33 @@
// <copyright file="AssemblyInfo.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
using 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

View File

@ -0,0 +1,5 @@
# Changelog
## Unreleased
Initial release.

View File

@ -0,0 +1,30 @@
// <copyright file="IConfigureMeterProviderBuilder.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
namespace OpenTelemetry.Metrics;
/// <summary>
/// Represents something that configures the <see cref="MeterProviderBuilder"/> type.
/// </summary>
public interface IConfigureMeterProviderBuilder
{
/// <summary>
/// Invoked to configure a <see cref="MeterProviderBuilder"/> instance.
/// </summary>
/// <param name="serviceProvider"><see cref="IServiceProvider"/>.</param>
/// <param name="meterProviderBuilder"><see cref="MeterProviderBuilder"/>.</param>
void ConfigureBuilder(IServiceProvider serviceProvider, MeterProviderBuilder meterProviderBuilder);
}

View File

@ -0,0 +1,58 @@
// <copyright file="IMeterProviderBuilder.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
using Microsoft.Extensions.DependencyInjection;
namespace OpenTelemetry.Metrics;
/// <summary>
/// Describes a <see cref="MeterProviderBuilder"/> backed by an <see cref="IServiceCollection"/>.
/// </summary>
public interface IMeterProviderBuilder : IDeferredMeterProviderBuilder
{
/// <summary>
/// Gets the <see cref="MeterProvider"/> being constructed by the builder.
/// </summary>
/// <remarks>
/// Note: <see cref="Provider"/> should return <see langword="null"/> until
/// construction has started and the <see cref="IServiceCollection"/> has
/// closed.
/// </remarks>
MeterProvider? Provider { get; }
/// <summary>
/// Register a callback action to configure the <see
/// cref="IServiceCollection"/> where metric services are configured.
/// </summary>
/// <remarks>
/// Note: Metric services are only available during the application
/// configuration phase. This method should throw a <see
/// cref="NotSupportedException"/> if services are configured after the
/// application <see cref="IServiceProvider"/> has been created.
/// </remarks>
/// <param name="configure">Configuration callback.</param>
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
MeterProviderBuilder ConfigureServices(Action<IServiceCollection> configure);
/// <summary>
/// Register a callback action to configure the <see
/// cref="MeterProviderBuilder"/> once the application <see
/// cref="IServiceProvider"/> is available.
/// </summary>
/// <param name="configure">Configuration callback.</param>
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
MeterProviderBuilder ConfigureBuilder(Action<IServiceProvider, MeterProviderBuilder> configure);
}

View File

@ -0,0 +1,161 @@
// <copyright file="OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using OpenTelemetry.Internal;
namespace OpenTelemetry.Metrics;
/// <summary>
/// Contains extension methods for the <see cref="MeterProviderBuilder"/> class.
/// </summary>
public static class OpenTelemetryDependencyInjectionMeterProviderBuilderExtensions
{
/// <summary>
/// Adds instrumentation to the provider.
/// </summary>
/// <remarks>
/// Note: The type specified by <typeparamref name="T"/> will be
/// registered as a singleton service into application services.
/// </remarks>
/// <typeparam name="T">Instrumentation type.</typeparam>
/// <param name="meterProviderBuilder"><see cref="MeterProviderBuilder"/>.</param>
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
public static MeterProviderBuilder AddInstrumentation<T>(this MeterProviderBuilder meterProviderBuilder)
where T : class
{
meterProviderBuilder.ConfigureServices(services => services.TryAddSingleton<T>());
meterProviderBuilder.ConfigureBuilder((sp, builder) =>
{
builder.AddInstrumentation(() => sp.GetRequiredService<T>());
});
return meterProviderBuilder;
}
/// <summary>
/// Adds instrumentation to the provider.
/// </summary>
/// <typeparam name="T">Instrumentation type.</typeparam>
/// <param name="meterProviderBuilder"><see cref="MeterProviderBuilder"/>.</param>
/// <param name="instrumentation">Instrumentation instance.</param>
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
public static MeterProviderBuilder AddInstrumentation<T>(this MeterProviderBuilder meterProviderBuilder, T instrumentation)
where T : class
{
Guard.ThrowIfNull(instrumentation);
meterProviderBuilder.ConfigureBuilder((sp, builder) =>
{
builder.AddInstrumentation(() => instrumentation);
});
return meterProviderBuilder;
}
/// <summary>
/// Adds instrumentation to the provider.
/// </summary>
/// <typeparam name="T">Instrumentation type.</typeparam>
/// <param name="meterProviderBuilder"><see cref="MeterProviderBuilder"/>.</param>
/// <param name="instrumentationFactory">Instrumentation factory.</param>
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
public static MeterProviderBuilder AddInstrumentation<T>(
this MeterProviderBuilder meterProviderBuilder,
Func<IServiceProvider, T> instrumentationFactory)
where T : class
{
Guard.ThrowIfNull(instrumentationFactory);
meterProviderBuilder.ConfigureBuilder((sp, builder) =>
{
builder.AddInstrumentation(() => instrumentationFactory(sp));
});
return meterProviderBuilder;
}
/// <summary>
/// Adds instrumentation to the provider.
/// </summary>
/// <typeparam name="T">Instrumentation type.</typeparam>
/// <param name="meterProviderBuilder"><see cref="MeterProviderBuilder"/>.</param>
/// <param name="instrumentationFactory">Instrumentation factory.</param>
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
public static MeterProviderBuilder AddInstrumentation<T>(
this MeterProviderBuilder meterProviderBuilder,
Func<IServiceProvider, MeterProvider, T> 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;
}
/// <summary>
/// Register a callback action to configure the <see
/// cref="IServiceCollection"/> where tracing services are configured.
/// </summary>
/// <remarks>
/// Note: Tracing services are only available during the application
/// configuration phase.
/// </remarks>
/// <param name="meterProviderBuilder"><see cref="MeterProviderBuilder"/>.</param>
/// <param name="configure">Configuration callback.</param>
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
public static MeterProviderBuilder ConfigureServices(
this MeterProviderBuilder meterProviderBuilder,
Action<IServiceCollection> configure)
{
if (meterProviderBuilder is IMeterProviderBuilder iMeterProviderBuilder)
{
iMeterProviderBuilder.ConfigureServices(configure);
}
return meterProviderBuilder;
}
/// <summary>
/// Register a callback action to configure the <see
/// cref="MeterProviderBuilder"/> once the application <see
/// cref="IServiceProvider"/> is available.
/// </summary>
/// <param name="meterProviderBuilder"><see cref="MeterProviderBuilder"/>.</param>
/// <param name="configure">Configuration callback.</param>
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
public static MeterProviderBuilder ConfigureBuilder(
this MeterProviderBuilder meterProviderBuilder,
Action<IServiceProvider, MeterProviderBuilder> configure)
{
if (meterProviderBuilder is IDeferredMeterProviderBuilder deferredMeterProviderBuilder)
{
deferredMeterProviderBuilder.Configure(configure);
}
return meterProviderBuilder;
}
}

View File

@ -0,0 +1,85 @@
// <copyright file="OpenTelemetryDependencyInjectionMetricsServiceCollectionExtensions.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry.Internal;
namespace OpenTelemetry.Metrics;
/// <summary>
/// Extension methods for setting up OpenTelemetry Metrics services in an <see cref="IServiceCollection" />.
/// </summary>
public static class OpenTelemetryDependencyInjectionMetricsServiceCollectionExtensions
{
/// <summary>
/// Registers an action used to configure the OpenTelemetry <see
/// cref="MeterProviderBuilder"/> used to create the <see
/// cref="MeterProvider"/> for the <see cref="IServiceCollection"/> being
/// configured.
/// </summary>
/// <remarks>
/// Notes:
/// <list type="bullet">
/// <item>This is safe to be called multiple times and by library authors.
/// Each registered configuration action will be applied
/// sequentially.</item>
/// <item>A <see cref="MeterProvider"/> will not be created automatically
/// using this method. To begin collecting metrics use the
/// <c>IServiceCollection.AddOpenTelemetry</c> extension in the
/// <c>OpenTelemetry</c> package.</item>
/// </list>
/// </remarks>
/// <param name="services">The <see cref="IServiceCollection" /> to add
/// services to.</param>
/// <param name="configure">Callback action to configure the <see
/// cref="MeterProviderBuilder"/>.</param>
/// <returns>The <see cref="IServiceCollection"/> so that additional calls
/// can be chained.</returns>
public static IServiceCollection ConfigureOpenTelemetryMeterProvider(
this IServiceCollection services,
Action<IServiceProvider, MeterProviderBuilder> configure)
{
RegisterBuildAction(services, configure);
return services;
}
private static void RegisterBuildAction(IServiceCollection services, Action<IServiceProvider, MeterProviderBuilder> configure)
{
Guard.ThrowIfNull(services);
Guard.ThrowIfNull(configure);
services.AddSingleton<IConfigureMeterProviderBuilder>(
new ConfigureMeterProviderBuilderCallbackWrapper(configure));
}
private sealed class ConfigureMeterProviderBuilderCallbackWrapper : IConfigureMeterProviderBuilder
{
private readonly Action<IServiceProvider, MeterProviderBuilder> configure;
public ConfigureMeterProviderBuilderCallbackWrapper(Action<IServiceProvider, MeterProviderBuilder> configure)
{
Guard.ThrowIfNull(configure);
this.configure = configure;
}
public void ConfigureBuilder(IServiceProvider serviceProvider, MeterProviderBuilder meterProviderBuilder)
{
this.configure(serviceProvider, meterProviderBuilder);
}
}
}

View File

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- OmniSharp/VS Code requires TargetFrameworks to be in descending order for IntelliSense and analysis. -->
<TargetFrameworks>netstandard2.0;net462</TargetFrameworks>
<Description>Contains extensions to register OpenTelemetry in applications using Microsoft.Extensions.DependencyInjection</Description>
<RootNamespace>OpenTelemetry</RootNamespace>
<MinVerTagPrefix>core-</MinVerTagPrefix>
</PropertyGroup>
<!--Do not run ApiCompat for netstandard2.0/net462 as this is newly added. Remove this property once we have released a stable version.-->
<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard2.0' OR '$(TargetFramework)' == 'net462'">
<RunApiCompat>false</RunApiCompat>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(RepoRoot)\src\OpenTelemetry.Api\Internal\Guard.cs" Link="Includes\Guard.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Api\OpenTelemetry.Api.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="$(MicrosoftExtensionsDependencyInjectionAbstractionsPkgVer)" />
</ItemGroup>
</Project>

View File

@ -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/)

View File

@ -0,0 +1,30 @@
// <copyright file="IConfigureTracerProviderBuilder.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
namespace OpenTelemetry.Trace;
/// <summary>
/// Represents something that configures the <see cref="TracerProviderBuilder"/> type.
/// </summary>
public interface IConfigureTracerProviderBuilder
{
/// <summary>
/// Invoked to configure a <see cref="TracerProviderBuilder"/> instance.
/// </summary>
/// <param name="serviceProvider"><see cref="IServiceProvider"/>.</param>
/// <param name="tracerProviderBuilder"><see cref="TracerProviderBuilder"/>.</param>
void ConfigureBuilder(IServiceProvider serviceProvider, TracerProviderBuilder tracerProviderBuilder);
}

View File

@ -0,0 +1,58 @@
// <copyright file="ITracerProviderBuilder.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
using Microsoft.Extensions.DependencyInjection;
namespace OpenTelemetry.Trace;
/// <summary>
/// Describes a <see cref="TracerProviderBuilder"/> backed by an <see cref="IServiceCollection"/>.
/// </summary>
public interface ITracerProviderBuilder : IDeferredTracerProviderBuilder
{
/// <summary>
/// Gets the <see cref="TracerProvider"/> being constructed by the builder.
/// </summary>
/// <remarks>
/// Note: <see cref="Provider"/> should return <see langword="null"/> until
/// construction has started and the <see cref="IServiceCollection"/> has
/// closed.
/// </remarks>
TracerProvider? Provider { get; }
/// <summary>
/// Register a callback action to configure the <see
/// cref="IServiceCollection"/> where tracing services are configured.
/// </summary>
/// <remarks>
/// Note: Tracing services are only available during the application
/// configuration phase. This method should throw a <see
/// cref="NotSupportedException"/> if services are configured after the
/// application <see cref="IServiceProvider"/> has been created.
/// </remarks>
/// <param name="configure">Configuration callback.</param>
/// <returns>The supplied <see cref="TracerProviderBuilder"/> for chaining.</returns>
TracerProviderBuilder ConfigureServices(Action<IServiceCollection> configure);
/// <summary>
/// Register a callback action to configure the <see
/// cref="TracerProviderBuilder"/> once the application <see
/// cref="IServiceProvider"/> is available.
/// </summary>
/// <param name="configure">Configuration callback.</param>
/// <returns>The supplied <see cref="TracerProviderBuilder"/> for chaining.</returns>
TracerProviderBuilder ConfigureBuilder(Action<IServiceProvider, TracerProviderBuilder> configure);
}

View File

@ -0,0 +1,161 @@
// <copyright file="OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using OpenTelemetry.Internal;
namespace OpenTelemetry.Trace;
/// <summary>
/// Contains extension methods for the <see cref="TracerProviderBuilder"/> class.
/// </summary>
public static class OpenTelemetryDependencyInjectionTracerProviderBuilderExtensions
{
/// <summary>
/// Adds instrumentation to the provider.
/// </summary>
/// <remarks>
/// Note: The type specified by <typeparamref name="T"/> will be
/// registered as a singleton service into application services.
/// </remarks>
/// <typeparam name="T">Instrumentation type.</typeparam>
/// <param name="tracerProviderBuilder"><see cref="TracerProviderBuilder"/>.</param>
/// <returns>The supplied <see cref="TracerProviderBuilder"/> for chaining.</returns>
public static TracerProviderBuilder AddInstrumentation<T>(this TracerProviderBuilder tracerProviderBuilder)
where T : class
{
tracerProviderBuilder.ConfigureServices(services => services.TryAddSingleton<T>());
tracerProviderBuilder.ConfigureBuilder((sp, builder) =>
{
builder.AddInstrumentation(() => sp.GetRequiredService<T>());
});
return tracerProviderBuilder;
}
/// <summary>
/// Adds instrumentation to the provider.
/// </summary>
/// <typeparam name="T">Instrumentation type.</typeparam>
/// <param name="tracerProviderBuilder"><see cref="TracerProviderBuilder"/>.</param>
/// <param name="instrumentation">Instrumentation instance.</param>
/// <returns>The supplied <see cref="TracerProviderBuilder"/> for chaining.</returns>
public static TracerProviderBuilder AddInstrumentation<T>(this TracerProviderBuilder tracerProviderBuilder, T instrumentation)
where T : class
{
Guard.ThrowIfNull(instrumentation);
tracerProviderBuilder.ConfigureBuilder((sp, builder) =>
{
builder.AddInstrumentation(() => instrumentation);
});
return tracerProviderBuilder;
}
/// <summary>
/// Adds instrumentation to the provider.
/// </summary>
/// <typeparam name="T">Instrumentation type.</typeparam>
/// <param name="tracerProviderBuilder"><see cref="TracerProviderBuilder"/>.</param>
/// <param name="instrumentationFactory">Instrumentation factory.</param>
/// <returns>The supplied <see cref="TracerProviderBuilder"/> for chaining.</returns>
public static TracerProviderBuilder AddInstrumentation<T>(
this TracerProviderBuilder tracerProviderBuilder,
Func<IServiceProvider, T> instrumentationFactory)
where T : class
{
Guard.ThrowIfNull(instrumentationFactory);
tracerProviderBuilder.ConfigureBuilder((sp, builder) =>
{
builder.AddInstrumentation(() => instrumentationFactory(sp));
});
return tracerProviderBuilder;
}
/// <summary>
/// Adds instrumentation to the provider.
/// </summary>
/// <typeparam name="T">Instrumentation type.</typeparam>
/// <param name="tracerProviderBuilder"><see cref="TracerProviderBuilder"/>.</param>
/// <param name="instrumentationFactory">Instrumentation factory.</param>
/// <returns>The supplied <see cref="TracerProviderBuilder"/> for chaining.</returns>
public static TracerProviderBuilder AddInstrumentation<T>(
this TracerProviderBuilder tracerProviderBuilder,
Func<IServiceProvider, TracerProvider, T> 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;
}
/// <summary>
/// Register a callback action to configure the <see
/// cref="IServiceCollection"/> where tracing services are configured.
/// </summary>
/// <remarks>
/// Note: Tracing services are only available during the application
/// configuration phase.
/// </remarks>
/// <param name="tracerProviderBuilder"><see cref="TracerProviderBuilder"/>.</param>
/// <param name="configure">Configuration callback.</param>
/// <returns>The supplied <see cref="TracerProviderBuilder"/> for chaining.</returns>
public static TracerProviderBuilder ConfigureServices(
this TracerProviderBuilder tracerProviderBuilder,
Action<IServiceCollection> configure)
{
if (tracerProviderBuilder is ITracerProviderBuilder iTracerProviderBuilder)
{
iTracerProviderBuilder.ConfigureServices(configure);
}
return tracerProviderBuilder;
}
/// <summary>
/// Register a callback action to configure the <see
/// cref="TracerProviderBuilder"/> once the application <see
/// cref="IServiceProvider"/> is available.
/// </summary>
/// <param name="tracerProviderBuilder"><see cref="TracerProviderBuilder"/>.</param>
/// <param name="configure">Configuration callback.</param>
/// <returns>The supplied <see cref="TracerProviderBuilder"/> for chaining.</returns>
public static TracerProviderBuilder ConfigureBuilder(
this TracerProviderBuilder tracerProviderBuilder,
Action<IServiceProvider, TracerProviderBuilder> configure)
{
if (tracerProviderBuilder is IDeferredTracerProviderBuilder deferredTracerProviderBuilder)
{
deferredTracerProviderBuilder.Configure(configure);
}
return tracerProviderBuilder;
}
}

View File

@ -0,0 +1,85 @@
// <copyright file="OpenTelemetryDependencyInjectionTracingServiceCollectionExtensions.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry.Internal;
namespace OpenTelemetry.Trace;
/// <summary>
/// Extension methods for setting up OpenTelemetry tracing services in an <see cref="IServiceCollection" />.
/// </summary>
public static class OpenTelemetryDependencyInjectionTracingServiceCollectionExtensions
{
/// <summary>
/// Registers an action used to configure the OpenTelemetry <see
/// cref="TracerProviderBuilder"/> used to create the <see
/// cref="TracerProvider"/> for the <see cref="IServiceCollection"/> being
/// configured.
/// </summary>
/// <remarks>
/// Notes:
/// <list type="bullet">
/// <item>This is safe to be called multiple times and by library authors.
/// Each registered configuration action will be applied
/// sequentially.</item>
/// <item>A <see cref="TracerProvider"/> will not be created automatically
/// using this method. To begin collecting metrics use the
/// <c>IServiceCollection.AddOpenTelemetry</c> extension in the
/// <c>OpenTelemetry</c> package.</item>
/// </list>
/// </remarks>
/// <param name="services">The <see cref="IServiceCollection" /> to add
/// services to.</param>
/// <param name="configure">Callback action to configure the <see
/// cref="TracerProviderBuilder"/>.</param>
/// <returns>The <see cref="IServiceCollection"/> so that additional calls
/// can be chained.</returns>
public static IServiceCollection ConfigureOpenTelemetryTracerProvider(
this IServiceCollection services,
Action<IServiceProvider, TracerProviderBuilder> configure)
{
RegisterBuildAction(services, configure);
return services;
}
private static void RegisterBuildAction(IServiceCollection services, Action<IServiceProvider, TracerProviderBuilder> configure)
{
Guard.ThrowIfNull(services);
Guard.ThrowIfNull(configure);
services.AddSingleton<IConfigureTracerProviderBuilder>(
new ConfigureTracerProviderBuilderCallbackWrapper(configure));
}
private sealed class ConfigureTracerProviderBuilderCallbackWrapper : IConfigureTracerProviderBuilder
{
private readonly Action<IServiceProvider, TracerProviderBuilder> configure;
public ConfigureTracerProviderBuilderCallbackWrapper(Action<IServiceProvider, TracerProviderBuilder> configure)
{
Guard.ThrowIfNull(configure);
this.configure = configure;
}
public void ConfigureBuilder(IServiceProvider serviceProvider, TracerProviderBuilder tracerProviderBuilder)
{
this.configure(serviceProvider, tracerProviderBuilder);
}
}
}

View File

@ -1,5 +1,6 @@
Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions
OpenTelemetry.Metrics.MeterProviderBuilderExtensions OpenTelemetry.Metrics.MeterProviderBuilderExtensions
OpenTelemetry.OpenTelemetryBuilderHostingExtensions
OpenTelemetry.Trace.TracerProviderBuilderExtensions 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) -> Microsoft.Extensions.DependencyInjection.IServiceCollection
static Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions.AddOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<OpenTelemetry.Metrics.MeterProviderBuilder> configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection static Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions.AddOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<OpenTelemetry.Metrics.MeterProviderBuilder> 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<OpenTelemetry.Trace.TracerProviderBuilder> configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection static Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions.AddOpenTelemetryTracing(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<OpenTelemetry.Trace.TracerProviderBuilder> configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.Configure(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, System.Action<System.IServiceProvider, OpenTelemetry.Metrics.MeterProviderBuilder> configure) -> OpenTelemetry.Metrics.MeterProviderBuilder static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.Configure(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, System.Action<System.IServiceProvider, OpenTelemetry.Metrics.MeterProviderBuilder> configure) -> OpenTelemetry.Metrics.MeterProviderBuilder
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.GetServices(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder) -> Microsoft.Extensions.DependencyInjection.IServiceCollection static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.GetServices(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder) -> Microsoft.Extensions.DependencyInjection.IServiceCollection
static OpenTelemetry.OpenTelemetryBuilderHostingExtensions.StartWithHost(this OpenTelemetry.OpenTelemetryBuilder builder) -> OpenTelemetry.OpenTelemetryBuilder
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.Configure(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, System.Action<System.IServiceProvider, OpenTelemetry.Trace.TracerProviderBuilder> configure) -> OpenTelemetry.Trace.TracerProviderBuilder static OpenTelemetry.Trace.TracerProviderBuilderExtensions.Configure(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, System.Action<System.IServiceProvider, OpenTelemetry.Trace.TracerProviderBuilder> configure) -> OpenTelemetry.Trace.TracerProviderBuilder
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.GetServices(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder) -> Microsoft.Extensions.DependencyInjection.IServiceCollection static OpenTelemetry.Trace.TracerProviderBuilderExtensions.GetServices(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder) -> Microsoft.Extensions.DependencyInjection.IServiceCollection

View File

@ -2,6 +2,9 @@
## Unreleased ## Unreleased
* Added the `OpenTelemetryBuilder.StartWithHost` extension.
([#3923](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3923))
## 1.0.0-rc9.9 ## 1.0.0-rc9.9
Released 2022-Nov-07 Released 2022-Nov-07

View File

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<!-- OmniSharp/VS Code requires TargetFrameworks to be in descending order for IntelliSense and analysis. --> <!-- OmniSharp/VS Code requires TargetFrameworks to be in descending order for IntelliSense and analysis. -->
<TargetFrameworks>netstandard2.0</TargetFrameworks> <TargetFrameworks>netstandard2.0</TargetFrameworks>
<Description>Contains extensions to register and start OpenTelemetry in applications using Microsoft.Extensions.Hosting</Description> <Description>Contains extensions to start OpenTelemetry in applications using Microsoft.Extensions.Hosting</Description>
<RootNamespace>OpenTelemetry</RootNamespace> <RootNamespace>OpenTelemetry</RootNamespace>
<!-- this is temporary. will remove in future PR. --> <!-- this is temporary. will remove in future PR. -->

View File

@ -0,0 +1,54 @@
// <copyright file="OpenTelemetryBuilderHostingExtensions.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using OpenTelemetry.Extensions.Hosting.Implementation;
using OpenTelemetry.Internal;
namespace OpenTelemetry;
/// <summary>
/// Contains hosting extension methods for the <see
/// cref="OpenTelemetryBuilder"/> class.
/// </summary>
public static class OpenTelemetryBuilderHostingExtensions
{
/// <summary>
/// Registers an <see cref="IHostedService"/> to automatically start all
/// configured OpenTelemetry services in the supplied <see
/// cref="IServiceCollection" />.
/// </summary>
/// <remarks>
/// Note: This is safe to be called multiple times. Only a single <see
/// cref="IHostedService"/> will be created for a given <see
/// cref="IServiceCollection"/>. This should generally be called by hosting
/// application code and NOT library authors.
/// </remarks>
/// <param name="builder"><see cref="OpenTelemetryBuilder"/>.</param>
/// <returns>The supplied <see cref="OpenTelemetryBuilder"/> for chaining
/// calls.</returns>
public static OpenTelemetryBuilder StartWithHost(this OpenTelemetryBuilder builder)
{
Guard.ThrowIfNull(builder);
builder.Services.TryAddEnumerable(
ServiceDescriptor.Singleton<IHostedService, TelemetryHostedService>());
return builder;
}
}

View File

@ -14,121 +14,114 @@
// limitations under the License. // limitations under the License.
// </copyright> // </copyright>
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using OpenTelemetry.Extensions.Hosting.Implementation; using OpenTelemetry;
using OpenTelemetry.Internal;
using OpenTelemetry.Metrics; using OpenTelemetry.Metrics;
using OpenTelemetry.Trace; using OpenTelemetry.Trace;
namespace Microsoft.Extensions.DependencyInjection namespace Microsoft.Extensions.DependencyInjection;
/// <summary>
/// Extension methods for setting up OpenTelemetry services in an <see
/// cref="IServiceCollection" />.
/// </summary>
public static class OpenTelemetryServicesExtensions
{ {
/// <summary> /// <summary>
/// Extension methods for setting up OpenTelemetry services in an <see /// Configure OpenTelemetry and register a <see cref="IHostedService"/>
/// to automatically start tracing services in the supplied <see
/// cref="IServiceCollection" />. /// cref="IServiceCollection" />.
/// </summary> /// </summary>
public static class OpenTelemetryServicesExtensions /// <remarks>
/// Notes:
/// <list type="bullet">
/// <item>
/// This is safe to be called multiple times. Only a single <see
/// cref="TracerProvider"/> will be created for a given <see
/// cref="IServiceCollection"/>.
/// </item>
/// <item>
/// This method should be called by application host code. Library
/// authors should call <see
/// cref="OpenTelemetryDependencyInjectionTracingServiceCollectionExtensions.ConfigureOpenTelemetryTracerProvider(IServiceCollection, Action{IServiceProvider, TracerProviderBuilder})"/>
/// instead.
/// </item>
/// </list>
/// </remarks>
/// <param name="services"><see cref="IServiceCollection"/>.</param>
/// <returns>Supplied <see cref="IServiceCollection"/> for chaining
/// calls.</returns>
[Obsolete("Use the AddOpenTelemetry().WithTracing(configure).StartWithHost() pattern instead. This method will be removed in a future version.")]
public static IServiceCollection AddOpenTelemetryTracing(this IServiceCollection services)
=> AddOpenTelemetryTracing(services, b => { });
/// <summary>
/// Configure OpenTelemetry and register a <see cref="IHostedService"/>
/// to automatically start tracing services in the supplied <see
/// cref="IServiceCollection" />.
/// </summary>
/// <remarks><inheritdoc
/// cref="AddOpenTelemetryTracing(IServiceCollection)"
/// path="/remarks"/></remarks>
/// <param name="services"><see cref="IServiceCollection"/>.</param>
/// <param name="configure">Callback action to configure the <see
/// cref="TracerProviderBuilder"/>.</param>
/// <returns>Supplied <see cref="IServiceCollection"/> for chaining
/// calls.</returns>
[Obsolete("Use the AddOpenTelemetry().WithTracing(configure).StartWithHost() pattern instead. This method will be removed in a future version.")]
public static IServiceCollection AddOpenTelemetryTracing(this IServiceCollection services, Action<TracerProviderBuilder> configure)
{ {
/// <summary> services.AddOpenTelemetry().WithTracing(configure).StartWithHost();
/// Configure OpenTelemetry and register a <see cref="IHostedService"/>
/// to automatically start tracing services in the supplied <see
/// cref="IServiceCollection" />.
/// </summary>
/// <remarks>
/// Notes:
/// <list type="bullet">
/// <item>
/// This is safe to be called multiple times. Only a single <see
/// cref="TracerProvider"/> will be created for a given <see
/// cref="IServiceCollection"/>.
/// </item>
/// <item>
/// This method should be called by application host code. Library
/// authors should call <see
/// cref="TracerProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryTracing(IServiceCollection)"/>
/// instead.
/// </item>
/// </list>
/// </remarks>
/// <param name="services"><see cref="IServiceCollection"/>.</param>
/// <returns>Supplied <see cref="IServiceCollection"/> for chaining
/// calls.</returns>
public static IServiceCollection AddOpenTelemetryTracing(this IServiceCollection services)
=> AddOpenTelemetryTracing(services, b => { });
/// <summary> return services;
/// Configure OpenTelemetry and register a <see cref="IHostedService"/> }
/// to automatically start tracing services in the supplied <see
/// cref="IServiceCollection" />.
/// </summary>
/// <remarks><inheritdoc
/// cref="AddOpenTelemetryTracing(IServiceCollection)"
/// path="/remarks"/></remarks>
/// <param name="services"><see cref="IServiceCollection"/>.</param>
/// <param name="configure">Callback action to configure the <see
/// cref="TracerProviderBuilder"/>.</param>
/// <returns>Supplied <see cref="IServiceCollection"/> for chaining
/// calls.</returns>
public static IServiceCollection AddOpenTelemetryTracing(this IServiceCollection services, Action<TracerProviderBuilder> configure)
{
Guard.ThrowIfNull(services);
services.ConfigureOpenTelemetryTracing(configure); /// <summary>
/// Configure OpenTelemetry and register a <see cref="IHostedService"/>
/// to automatically start metric services in the supplied <see
/// cref="IServiceCollection" />.
/// </summary>
/// <remarks>
/// Notes:
/// <list type="bullet">
/// <item>
/// This is safe to be called multiple times. Only a single <see
/// cref="MeterProvider"/> will be created for a given <see
/// cref="IServiceCollection"/>.
/// </item>
/// <item>
/// This method should be called by application host code. Library
/// authors should call <see
/// cref="OpenTelemetryDependencyInjectionMetricsServiceCollectionExtensions.ConfigureOpenTelemetryMeterProvider(IServiceCollection, Action{IServiceProvider, MeterProviderBuilder})"/>
/// instead.
/// </item>
/// </list>
/// </remarks>
/// <param name="services"><see cref="IServiceCollection"/>.</param>
/// <returns>Supplied <see cref="IServiceCollection"/> for chaining
/// calls.</returns>
[Obsolete("Use the AddOpenTelemetry().WithMetrics(configure).StartWithHost() pattern instead. This method will be removed in a future version.")]
public static IServiceCollection AddOpenTelemetryMetrics(this IServiceCollection services)
=> AddOpenTelemetryMetrics(services, b => { });
services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService, TelemetryHostedService>()); /// <summary>
/// Configure OpenTelemetry and register a <see cref="IHostedService"/>
/// to automatically start metric services in the supplied <see
/// cref="IServiceCollection" />.
/// </summary>
/// <remarks><inheritdoc
/// cref="AddOpenTelemetryMetrics(IServiceCollection)"
/// path="/remarks"/></remarks>
/// <param name="services"><see cref="IServiceCollection"/>.</param>
/// <param name="configure">Callback action to configure the <see
/// cref="TracerProviderBuilder"/>.</param>
/// <returns>Supplied <see cref="IServiceCollection"/> for chaining
/// calls.</returns>
[Obsolete("Use the AddOpenTelemetry().WithMetrics(configure).StartWithHost() pattern instead. This method will be removed in a future version.")]
public static IServiceCollection AddOpenTelemetryMetrics(this IServiceCollection services, Action<MeterProviderBuilder> configure)
{
services.AddOpenTelemetry().WithMetrics(configure).StartWithHost();
return services; return services;
}
/// <summary>
/// Configure OpenTelemetry and register a <see cref="IHostedService"/>
/// to automatically start metric services in the supplied <see
/// cref="IServiceCollection" />.
/// </summary>
/// <remarks>
/// Notes:
/// <list type="bullet">
/// <item>
/// This is safe to be called multiple times. Only a single <see
/// cref="MeterProvider"/> will be created for a given <see
/// cref="IServiceCollection"/>.
/// </item>
/// <item>
/// This method should be called by application host code. Library
/// authors should call <see
/// cref="MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(IServiceCollection)"/>
/// instead.
/// </item>
/// </list>
/// </remarks>
/// <param name="services"><see cref="IServiceCollection"/>.</param>
/// <returns>Supplied <see cref="IServiceCollection"/> for chaining
/// calls.</returns>
public static IServiceCollection AddOpenTelemetryMetrics(this IServiceCollection services)
=> AddOpenTelemetryMetrics(services, b => { });
/// <summary>
/// Configure OpenTelemetry and register a <see cref="IHostedService"/>
/// to automatically start metric services in the supplied <see
/// cref="IServiceCollection" />.
/// </summary>
/// <remarks><inheritdoc
/// cref="AddOpenTelemetryMetrics(IServiceCollection)"
/// path="/remarks"/></remarks>
/// <param name="services"><see cref="IServiceCollection"/>.</param>
/// <param name="configure">Callback action to configure the <see
/// cref="TracerProviderBuilder"/>.</param>
/// <returns>Supplied <see cref="IServiceCollection"/> for chaining
/// calls.</returns>
public static IServiceCollection AddOpenTelemetryMetrics(this IServiceCollection services, Action<MeterProviderBuilder> configure)
{
Guard.ThrowIfNull(services);
services.ConfigureOpenTelemetryMetrics(configure);
services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService, TelemetryHostedService>());
return services;
}
} }
} }

View File

@ -21,8 +21,16 @@ and metrics (`MeterProvider`) in [ASP.NET
## Extension method reference ## Extension method reference
**Note:** The below extension methods target ### Current OpenTelemetry SDK v1.4.0 and newer extensions
`Microsoft.Extensions.DependencyInjection.IServiceCollection`.
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 **Note:** The below extension methods should be called by application host code
only. Library authors see: [Registration extension method guidance for library 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) MeterProvider](../../docs/metrics/customizing-the-sdk/README.md#building-a-meterprovider)
for more details. for more details.
Targeting `Microsoft.Extensions.DependencyInjection.IServiceCollection`:
* `AddOpenTelemetryTracing`: Configure OpenTelemetry and register an * `AddOpenTelemetryTracing`: Configure OpenTelemetry and register an
[IHostedService](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.ihostedservice) [IHostedService](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.ihostedservice)
to automatically start tracing services in the supplied to automatically start tracing services in the supplied
@ -60,11 +70,10 @@ using OpenTelemetry.Trace;
var appBuilder = WebApplication.CreateBuilder(args); var appBuilder = WebApplication.CreateBuilder(args);
appBuilder.Services.AddOpenTelemetryTracing( appBuilder.Services.AddOpenTelemetry()
builder => builder.AddConsoleExporter()); .WithTracing(builder => builder.AddConsoleExporter())
.WithMetrics(builder => builder.AddConsoleExporter())
appBuilder.Services.AddOpenTelemetryMetrics( .StartWithHost();
builder => builder.AddConsoleExporter());
var app = appBuilder.Build(); var app = appBuilder.Build();

View File

@ -55,10 +55,11 @@ using OpenTelemetry.Trace;
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
services.AddOpenTelemetryTracing((builder) => builder services.AddOpenTelemetry()
.AddAspNetCoreInstrumentation() .WithTracing(builder => builder
.AddJaegerExporter() .AddAspNetCoreInstrumentation()
); .AddJaegerExporter())
.StartWithHost();
} }
``` ```
@ -84,10 +85,11 @@ services.Configure<AspNetCoreInstrumentationOptions>(options =>
}; };
}); });
services.AddOpenTelemetryTracing((builder) => builder services.AddOpenTelemetry()
.AddAspNetCoreInstrumentation() .WithTracing(builder => builder
.AddJaegerExporter() .AddAspNetCoreInstrumentation()
); .AddJaegerExporter())
.StartWithHost();
``` ```
### Filter ### Filter
@ -103,14 +105,15 @@ The following code snippet shows how to use `Filter` to only allow GET
requests. requests.
```csharp ```csharp
services.AddOpenTelemetryTracing((builder) => builder services.AddOpenTelemetry()
.AddAspNetCoreInstrumentation((options) => options.Filter = httpContext => .WithTracing(builder => builder
{ .AddAspNetCoreInstrumentation((options) => options.Filter = httpContext =>
// only collect telemetry about HTTP GET requests {
return httpContext.Request.Method.Equals("GET"); // only collect telemetry about HTTP GET requests
}) return httpContext.Request.Method.Equals("GET");
.AddJaegerExporter() })
); .AddJaegerExporter())
.StartWithHost();
``` ```
It is important to note that this `Filter` option is specific to this 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. different options.
```csharp ```csharp
services.AddOpenTelemetryTracing((builder) => services.AddOpenTelemetry()
{ .WithTracing(builder => builder
builder.AddAspNetCoreInstrumentation(o => .AddAspNetCoreInstrumentation(o =>
{
o.EnrichWithHttpRequest = (activity, httpRequest) =>
{ {
activity.SetTag("requestProtocol", httpRequest.Protocol); o.EnrichWithHttpRequest = (activity, httpRequest) =>
}; {
o.EnrichWithHttpResponse = (activity, httpResponse) => activity.SetTag("requestProtocol", httpRequest.Protocol);
{ };
activity.SetTag("responseLength", httpResponse.ContentLength); o.EnrichWithHttpResponse = (activity, httpResponse) =>
}; {
o.EnrichWithException = (activity, exception) => activity.SetTag("responseLength", httpResponse.ContentLength);
{ };
activity.SetTag("exceptionType", exception.GetType().ToString()); o.EnrichWithException = (activity, exception) =>
}; {
}) activity.SetTag("exceptionType", exception.GetType().ToString());
}); };
}))
.StartWithHost();
``` ```
[Processor](../../docs/trace/extending-the-sdk/README.md#processor), [Processor](../../docs/trace/extending-the-sdk/README.md#processor),

View File

@ -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. following code snippet shows how to add additional tags using these options.
```csharp ```csharp
services.AddOpenTelemetryTracing((builder) => services.AddOpenTelemetry()
{ .WithTracing(builder => builder
builder .AddGrpcClientInstrumentation(options =>
.AddGrpcClientInstrumentation((options) =>
{
options.EnrichWithHttpRequestMessage = (activity, httpRequestMessage) =>
{ {
activity.SetTag("requestVersion", httpRequestMessage.Version); options.EnrichWithHttpRequestMessage = (activity, httpRequestMessage) =>
}; {
options.EnrichWithHttpResponseMessage = (activity, httpResponseMessage) => activity.SetTag("requestVersion", httpRequestMessage.Version);
{ };
activity.SetTag("responseVersion", httpResponseMessage.Version); options.EnrichWithHttpResponseMessage = (activity, httpResponseMessage) =>
}; {
}) activity.SetTag("responseVersion", httpResponseMessage.Version);
};
})
.StartWithHost();
``` ```
[Processor](../../docs/trace/extending-the-sdk/README.md#processor), [Processor](../../docs/trace/extending-the-sdk/README.md#processor),

View File

@ -1,5 +1,3 @@
Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions
Microsoft.Extensions.DependencyInjection.TracerProviderBuilderServiceCollectionExtensions
OpenTelemetry.Logs.LogRecord.CategoryName.set -> void OpenTelemetry.Logs.LogRecord.CategoryName.set -> void
OpenTelemetry.Logs.LogRecord.EventId.set -> void OpenTelemetry.Logs.LogRecord.EventId.set -> void
OpenTelemetry.Logs.LogRecord.Exception.set -> void OpenTelemetry.Logs.LogRecord.Exception.set -> void
@ -14,27 +12,30 @@ OpenTelemetry.Metrics.HistogramConfiguration
OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void
OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool
OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void
OpenTelemetry.Metrics.MeterProviderBuilderBase.ConfigureBuilder(System.Action<System.IServiceProvider!, OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
OpenTelemetry.Metrics.MeterProviderBuilderBase.ConfigureServices(System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMinMaxValues(out double min, out double max) -> bool OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMinMaxValues(out double min, out double max) -> bool
OpenTelemetry.OpenTelemetryBuilder
OpenTelemetry.OpenTelemetryBuilder.ConfigureResource(System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.Services.get -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
OpenTelemetry.OpenTelemetryBuilder.WithMetrics() -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithMetrics(System.Action<OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithTracing() -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithTracing(System.Action<OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.Resources.ResourceBuilder.AddDetector(System.Func<System.IServiceProvider?, OpenTelemetry.Resources.IResourceDetector!>! resourceDetectorFactory) -> OpenTelemetry.Resources.ResourceBuilder! OpenTelemetry.Resources.ResourceBuilder.AddDetector(System.Func<System.IServiceProvider?, OpenTelemetry.Resources.IResourceDetector!>! resourceDetectorFactory) -> OpenTelemetry.Resources.ResourceBuilder!
static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! OpenTelemetry.Trace.TracerProviderBuilderBase.ConfigureBuilder(System.Action<System.IServiceProvider!, OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action<OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! OpenTelemetry.Trace.TracerProviderBuilderBase.ConfigureServices(System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! OpenTelemetry.OpenTelemetryServiceCollectionExtensions
static OpenTelemetry.OpenTelemetryServiceCollectionExtensions.AddOpenTelemetry(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> OpenTelemetry.OpenTelemetryBuilder!
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader<T>(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader<T>(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action<System.IServiceProvider!, OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
OpenTelemetry.Trace.SamplingResult.TraceStateString.get -> string? 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, string! traceStateString) -> void
OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string!, object!>>? attributes, string? traceStateString) -> void OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string!, object!>>? attributes, string? traceStateString) -> void
*REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action<OpenTelemetry.Logs.OpenTelemetryLoggerOptions!>? configure = null) -> Microsoft.Extensions.Logging.ILoggingBuilder! *REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action<OpenTelemetry.Logs.OpenTelemetryLoggerOptions!>? 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) -> Microsoft.Extensions.Logging.ILoggingBuilder!
static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action<OpenTelemetry.Logs.OpenTelemetryLoggerOptions!>? configure) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action<OpenTelemetry.Logs.OpenTelemetryLoggerOptions!>? configure) -> Microsoft.Extensions.Logging.ILoggingBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddProcessor<T>(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddProcessor<T>(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action<System.IServiceProvider!, OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.SetSampler<T>(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.SetSampler<T>(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<OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
OpenTelemetry.Metrics.MetricType.LongSumNonMonotonic = 138 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.LongSumNonMonotonic = 138 -> OpenTelemetry.Metrics.MetricType

View File

@ -1,5 +1,3 @@
Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions
Microsoft.Extensions.DependencyInjection.TracerProviderBuilderServiceCollectionExtensions
OpenTelemetry.Logs.LogRecord.CategoryName.set -> void OpenTelemetry.Logs.LogRecord.CategoryName.set -> void
OpenTelemetry.Logs.LogRecord.EventId.set -> void OpenTelemetry.Logs.LogRecord.EventId.set -> void
OpenTelemetry.Logs.LogRecord.Exception.set -> void OpenTelemetry.Logs.LogRecord.Exception.set -> void
@ -14,27 +12,30 @@ OpenTelemetry.Metrics.HistogramConfiguration
OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void
OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool
OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void
OpenTelemetry.Metrics.MeterProviderBuilderBase.ConfigureBuilder(System.Action<System.IServiceProvider!, OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
OpenTelemetry.Metrics.MeterProviderBuilderBase.ConfigureServices(System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMinMaxValues(out double min, out double max) -> bool OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMinMaxValues(out double min, out double max) -> bool
OpenTelemetry.OpenTelemetryBuilder
OpenTelemetry.OpenTelemetryBuilder.ConfigureResource(System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.Services.get -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
OpenTelemetry.OpenTelemetryBuilder.WithMetrics() -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithMetrics(System.Action<OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithTracing() -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithTracing(System.Action<OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.Resources.ResourceBuilder.AddDetector(System.Func<System.IServiceProvider?, OpenTelemetry.Resources.IResourceDetector!>! resourceDetectorFactory) -> OpenTelemetry.Resources.ResourceBuilder! OpenTelemetry.Resources.ResourceBuilder.AddDetector(System.Func<System.IServiceProvider?, OpenTelemetry.Resources.IResourceDetector!>! resourceDetectorFactory) -> OpenTelemetry.Resources.ResourceBuilder!
static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! OpenTelemetry.Trace.TracerProviderBuilderBase.ConfigureBuilder(System.Action<System.IServiceProvider!, OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action<OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! OpenTelemetry.Trace.TracerProviderBuilderBase.ConfigureServices(System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! OpenTelemetry.OpenTelemetryServiceCollectionExtensions
static OpenTelemetry.OpenTelemetryServiceCollectionExtensions.AddOpenTelemetry(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> OpenTelemetry.OpenTelemetryBuilder!
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader<T>(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader<T>(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action<System.IServiceProvider!, OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
OpenTelemetry.Trace.SamplingResult.TraceStateString.get -> string? 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, string! traceStateString) -> void
OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string!, object!>>? attributes, string? traceStateString) -> void OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string!, object!>>? attributes, string? traceStateString) -> void
*REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action<OpenTelemetry.Logs.OpenTelemetryLoggerOptions!>? configure = null) -> Microsoft.Extensions.Logging.ILoggingBuilder! *REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action<OpenTelemetry.Logs.OpenTelemetryLoggerOptions!>? 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) -> Microsoft.Extensions.Logging.ILoggingBuilder!
static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action<OpenTelemetry.Logs.OpenTelemetryLoggerOptions!>? configure) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action<OpenTelemetry.Logs.OpenTelemetryLoggerOptions!>? configure) -> Microsoft.Extensions.Logging.ILoggingBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddProcessor<T>(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddProcessor<T>(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action<System.IServiceProvider!, OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.SetSampler<T>(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.SetSampler<T>(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<OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
OpenTelemetry.Metrics.MetricType.LongSumNonMonotonic = 138 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.LongSumNonMonotonic = 138 -> OpenTelemetry.Metrics.MetricType

View File

@ -1,5 +1,3 @@
Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions
Microsoft.Extensions.DependencyInjection.TracerProviderBuilderServiceCollectionExtensions
OpenTelemetry.Logs.LogRecord.CategoryName.set -> void OpenTelemetry.Logs.LogRecord.CategoryName.set -> void
OpenTelemetry.Logs.LogRecord.EventId.set -> void OpenTelemetry.Logs.LogRecord.EventId.set -> void
OpenTelemetry.Logs.LogRecord.Exception.set -> void OpenTelemetry.Logs.LogRecord.Exception.set -> void
@ -14,27 +12,30 @@ OpenTelemetry.Metrics.HistogramConfiguration
OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void
OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool
OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void
OpenTelemetry.Metrics.MeterProviderBuilderBase.ConfigureBuilder(System.Action<System.IServiceProvider!, OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
OpenTelemetry.Metrics.MeterProviderBuilderBase.ConfigureServices(System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMinMaxValues(out double min, out double max) -> bool OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMinMaxValues(out double min, out double max) -> bool
OpenTelemetry.OpenTelemetryBuilder
OpenTelemetry.OpenTelemetryBuilder.ConfigureResource(System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.Services.get -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
OpenTelemetry.OpenTelemetryBuilder.WithMetrics() -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithMetrics(System.Action<OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithTracing() -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithTracing(System.Action<OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.Resources.ResourceBuilder.AddDetector(System.Func<System.IServiceProvider?, OpenTelemetry.Resources.IResourceDetector!>! resourceDetectorFactory) -> OpenTelemetry.Resources.ResourceBuilder! OpenTelemetry.Resources.ResourceBuilder.AddDetector(System.Func<System.IServiceProvider?, OpenTelemetry.Resources.IResourceDetector!>! resourceDetectorFactory) -> OpenTelemetry.Resources.ResourceBuilder!
static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! OpenTelemetry.Trace.TracerProviderBuilderBase.ConfigureBuilder(System.Action<System.IServiceProvider!, OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action<OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! OpenTelemetry.Trace.TracerProviderBuilderBase.ConfigureServices(System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! OpenTelemetry.OpenTelemetryServiceCollectionExtensions
static OpenTelemetry.OpenTelemetryServiceCollectionExtensions.AddOpenTelemetry(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> OpenTelemetry.OpenTelemetryBuilder!
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader<T>(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader<T>(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action<System.IServiceProvider!, OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
OpenTelemetry.Trace.SamplingResult.TraceStateString.get -> string? 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, string! traceStateString) -> void
OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string!, object!>>? attributes, string? traceStateString) -> void OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string!, object!>>? attributes, string? traceStateString) -> void
*REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action<OpenTelemetry.Logs.OpenTelemetryLoggerOptions!>? configure = null) -> Microsoft.Extensions.Logging.ILoggingBuilder! *REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action<OpenTelemetry.Logs.OpenTelemetryLoggerOptions!>? 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) -> Microsoft.Extensions.Logging.ILoggingBuilder!
static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action<OpenTelemetry.Logs.OpenTelemetryLoggerOptions!>? configure) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action<OpenTelemetry.Logs.OpenTelemetryLoggerOptions!>? configure) -> Microsoft.Extensions.Logging.ILoggingBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddProcessor<T>(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddProcessor<T>(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action<System.IServiceProvider!, OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.SetSampler<T>(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.SetSampler<T>(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<OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
OpenTelemetry.Metrics.MetricType.LongSumNonMonotonic = 138 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.LongSumNonMonotonic = 138 -> OpenTelemetry.Metrics.MetricType

View File

@ -1,5 +1,3 @@
Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions
Microsoft.Extensions.DependencyInjection.TracerProviderBuilderServiceCollectionExtensions
OpenTelemetry.Logs.LogRecord.CategoryName.set -> void OpenTelemetry.Logs.LogRecord.CategoryName.set -> void
OpenTelemetry.Logs.LogRecord.EventId.set -> void OpenTelemetry.Logs.LogRecord.EventId.set -> void
OpenTelemetry.Logs.LogRecord.Exception.set -> void OpenTelemetry.Logs.LogRecord.Exception.set -> void
@ -14,27 +12,30 @@ OpenTelemetry.Metrics.HistogramConfiguration
OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void
OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool
OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void
OpenTelemetry.Metrics.MeterProviderBuilderBase.ConfigureBuilder(System.Action<System.IServiceProvider!, OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
OpenTelemetry.Metrics.MeterProviderBuilderBase.ConfigureServices(System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMinMaxValues(out double min, out double max) -> bool OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMinMaxValues(out double min, out double max) -> bool
OpenTelemetry.OpenTelemetryBuilder
OpenTelemetry.OpenTelemetryBuilder.ConfigureResource(System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.Services.get -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
OpenTelemetry.OpenTelemetryBuilder.WithMetrics() -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithMetrics(System.Action<OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithTracing() -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.OpenTelemetryBuilder.WithTracing(System.Action<OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> OpenTelemetry.OpenTelemetryBuilder!
OpenTelemetry.Resources.ResourceBuilder.AddDetector(System.Func<System.IServiceProvider?, OpenTelemetry.Resources.IResourceDetector!>! resourceDetectorFactory) -> OpenTelemetry.Resources.ResourceBuilder! OpenTelemetry.Resources.ResourceBuilder.AddDetector(System.Func<System.IServiceProvider?, OpenTelemetry.Resources.IResourceDetector!>! resourceDetectorFactory) -> OpenTelemetry.Resources.ResourceBuilder!
static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! OpenTelemetry.Trace.TracerProviderBuilderBase.ConfigureBuilder(System.Action<System.IServiceProvider!, OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action<OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! OpenTelemetry.Trace.TracerProviderBuilderBase.ConfigureServices(System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! OpenTelemetry.OpenTelemetryServiceCollectionExtensions
static OpenTelemetry.OpenTelemetryServiceCollectionExtensions.AddOpenTelemetry(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> OpenTelemetry.OpenTelemetryBuilder!
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader<T>(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader<T>(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action<System.IServiceProvider!, OpenTelemetry.Metrics.MeterProviderBuilder!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
OpenTelemetry.Trace.SamplingResult.TraceStateString.get -> string? 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, string! traceStateString) -> void
OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string!, object!>>? attributes, string? traceStateString) -> void OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string!, object!>>? attributes, string? traceStateString) -> void
*REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action<OpenTelemetry.Logs.OpenTelemetryLoggerOptions!>? configure = null) -> Microsoft.Extensions.Logging.ILoggingBuilder! *REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action<OpenTelemetry.Logs.OpenTelemetryLoggerOptions!>? 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) -> Microsoft.Extensions.Logging.ILoggingBuilder!
static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action<OpenTelemetry.Logs.OpenTelemetryLoggerOptions!>? configure) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action<OpenTelemetry.Logs.OpenTelemetryLoggerOptions!>? configure) -> Microsoft.Extensions.Logging.ILoggingBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddInstrumentation<T>(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddProcessor<T>(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddProcessor<T>(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureBuilder(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action<System.IServiceProvider!, OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureServices(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.SetSampler<T>(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.SetSampler<T>(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<OpenTelemetry.Trace.TracerProviderBuilder!>! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder! static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Action<OpenTelemetry.Resources.ResourceBuilder!>! configure) -> OpenTelemetry.Trace.TracerProviderBuilder!
OpenTelemetry.Metrics.MetricType.LongSumNonMonotonic = 138 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.LongSumNonMonotonic = 138 -> OpenTelemetry.Metrics.MetricType

View File

@ -21,6 +21,5 @@ using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus.AspNetCore" + AssemblyInfo.PublicKey)] [assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus.AspNetCore" + AssemblyInfo.PublicKey)]
[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests" + AssemblyInfo.PublicKey)] [assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests" + AssemblyInfo.PublicKey)]
[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus.HttpListener.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("DynamicProxyGenAssembly2" + AssemblyInfo.MoqPublicKey)]
[assembly: InternalsVisibleTo("Benchmarks" + AssemblyInfo.PublicKey)] [assembly: InternalsVisibleTo("Benchmarks" + AssemblyInfo.PublicKey)]

View File

@ -7,6 +7,11 @@
`AddEnvironmentVariableDetector` extension (Logs) `AddEnvironmentVariableDetector` extension (Logs)
([#3889](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3889)) ([#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 ## 1.4.0-beta.3
Released 2022-Nov-07 Released 2022-Nov-07

View File

@ -1,82 +0,0 @@
// <copyright file="ProviderBuilderServiceCollectionCallbackHelper.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
#nullable enable
using System.Diagnostics;
using Microsoft.Extensions.DependencyInjection;
namespace OpenTelemetry;
internal static class ProviderBuilderServiceCollectionCallbackHelper<TBuilder, TProvider, TState>
where TState : ProviderBuilderState<TBuilder, TProvider>
{
public static IServiceCollection RegisterConfigureBuilderCallback(
IServiceCollection services,
Action<IServiceProvider, TBuilder> configure)
{
Debug.Assert(configure != null, "configure was null");
return RegisterConfigureStateCallback(
services,
(sp, state) => configure!(sp, state.Builder));
}
public static IServiceCollection RegisterConfigureStateCallback(
IServiceCollection services,
Action<IServiceProvider, TState> 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<ConfigureProviderBuilderStateCallbackRegistration>();
foreach (var callbackRegistration in callbackRegistrations)
{
callbackRegistration.Configure(serviceProvider!, state!);
}
}
private sealed class ConfigureProviderBuilderStateCallbackRegistration
{
private readonly Action<IServiceProvider, TState> configure;
public ConfigureProviderBuilderStateCallbackRegistration(
Action<IServiceProvider, TState> 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!);
}
}
}

View File

@ -19,6 +19,7 @@
using System.Diagnostics; using System.Diagnostics;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.DependencyInjection.Extensions;
using OpenTelemetry;
using OpenTelemetry.Internal; using OpenTelemetry.Internal;
using OpenTelemetry.Metrics; using OpenTelemetry.Metrics;
using OpenTelemetry.Trace; using OpenTelemetry.Trace;
@ -29,28 +30,32 @@ internal static class ProviderBuilderServiceCollectionExtensions
{ {
public static IServiceCollection AddOpenTelemetryMeterProviderBuilderServices(this IServiceCollection services) public static IServiceCollection AddOpenTelemetryMeterProviderBuilderServices(this IServiceCollection services)
{ {
services.AddOpenTelemetryProviderBuilderServices(); Debug.Assert(services != null, "services was null");
services.TryAddSingleton<MeterProviderBuilderState>(); services!.TryAddSingleton<MeterProviderBuilderSdk>();
services.RegisterOptionsFactory(configuration => new MetricReaderOptions(configuration)); services!.RegisterOptionsFactory(configuration => new MetricReaderOptions(configuration));
return services; return services!;
} }
public static IServiceCollection AddOpenTelemetryTracerProviderBuilderServices(this IServiceCollection services) public static IServiceCollection AddOpenTelemetryTracerProviderBuilderServices(this IServiceCollection services)
{ {
services.AddOpenTelemetryProviderBuilderServices(); Debug.Assert(services != null, "services was null");
services.TryAddSingleton<TracerProviderBuilderState>(); services!.TryAddSingleton<TracerProviderBuilderSdk>();
services.RegisterOptionsFactory(configuration => new BatchExportActivityProcessorOptions(configuration)); 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"); 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(); services.AddOptions();
// Note: When using a host builder IConfiguration is automatically // Note: When using a host builder IConfiguration is automatically
@ -58,7 +63,8 @@ internal static class ProviderBuilderServiceCollectionExtensions
// Sdk.Create* style or when manually creating a ServiceCollection. The // Sdk.Create* style or when manually creating a ServiceCollection. The
// point of this registration is to make IConfiguration available in // point of this registration is to make IConfiguration available in
// those cases. // those cases.
services!.TryAddSingleton<IConfiguration>(sp => new ConfigurationBuilder().AddEnvironmentVariables().Build()); services!.TryAddSingleton<IConfiguration>(
sp => new ConfigurationBuilder().AddEnvironmentVariables().Build());
return services!; return services!;
} }

View File

@ -1,105 +0,0 @@
// <copyright file="ProviderBuilderState.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
#nullable enable
using System.Diagnostics;
using OpenTelemetry.Resources;
namespace OpenTelemetry;
internal abstract class ProviderBuilderState<TBuilder, TProvider>
{
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<InstrumentationRegistration> 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<ResourceBuilder> 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;
}
}
}

View File

@ -16,299 +16,147 @@
#nullable enable #nullable enable
using System.Diagnostics;
using System.Diagnostics.Metrics;
using System.Text.RegularExpressions;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.DependencyInjection.Extensions;
using OpenTelemetry.Internal; using OpenTelemetry.Internal;
using OpenTelemetry.Resources;
using CallbackHelper = OpenTelemetry.ProviderBuilderServiceCollectionCallbackHelper< namespace OpenTelemetry.Metrics;
OpenTelemetry.Metrics.MeterProviderBuilderSdk,
OpenTelemetry.Metrics.MeterProviderSdk,
OpenTelemetry.Metrics.MeterProviderBuilderState>;
namespace OpenTelemetry.Metrics /// <summary>
/// Contains methods for building <see cref="MeterProvider"/> instances.
/// </summary>
public class MeterProviderBuilderBase : MeterProviderBuilder, IMeterProviderBuilder
{ {
/// <summary> private readonly bool allowBuild;
/// Contains methods for building <see cref="MeterProvider"/> instances. private IServiceCollection? services;
/// </summary>
public abstract class MeterProviderBuilderBase : MeterProviderBuilder, IDeferredMeterProviderBuilder public MeterProviderBuilderBase()
{ {
internal readonly MeterProviderBuilderState? State; var services = new ServiceCollection();
private const string DefaultInstrumentationVersion = "1.0.0.0";
private readonly bool ownsServices; services
private IServiceCollection? services; .AddOpenTelemetrySharedProviderBuilderServices()
.AddOpenTelemetryMeterProviderBuilderServices()
.TryAddSingleton<MeterProvider>(
sp => throw new NotSupportedException("Self-contained MeterProvider cannot be accessed using the application IServiceProvider call Build instead."));
// This ctor is for a builder created from MeterProviderBuilderState which services.ConfigureOpenTelemetryMeterProvider((sp, builder) => this.services = null);
// happens after the service provider has been created.
internal MeterProviderBuilderBase(MeterProviderBuilderState state) this.services = services;
this.allowBuild = true;
}
internal MeterProviderBuilderBase(IServiceCollection services)
{
Guard.ThrowIfNull(services);
services
.AddOpenTelemetryMeterProviderBuilderServices()
.TryAddSingleton<MeterProvider>(sp => new MeterProviderSdk(sp, ownsServiceProvider: false));
services.ConfigureOpenTelemetryMeterProvider((sp, builder) => this.services = null);
this.services = services;
this.allowBuild = false;
}
/// <inheritdoc />
MeterProvider? IMeterProviderBuilder.Provider => null;
/// <inheritdoc />
public override MeterProviderBuilder AddInstrumentation<TInstrumentation>(Func<TInstrumentation> instrumentationFactory)
{
Guard.ThrowIfNull(instrumentationFactory);
this.ConfigureBuilder((sp, builder) =>
{ {
Debug.Assert(state != null, "state was null"); builder.AddInstrumentation(instrumentationFactory);
});
this.State = state; return this;
}
/// <inheritdoc />
public override MeterProviderBuilder AddMeter(params string[] names)
{
Guard.ThrowIfNull(names);
this.ConfigureBuilder((sp, builder) =>
{
builder.AddMeter(names);
});
return this;
}
/// <inheritdoc />
public MeterProviderBuilder ConfigureBuilder(Action<IServiceProvider, MeterProviderBuilder> configure)
{
var services = this.services;
if (services == null)
{
throw new NotSupportedException("Builder cannot be configured during MeterProvider construction.");
} }
// This ctor is for ConfigureOpenTelemetryMetrics + services.ConfigureOpenTelemetryMeterProvider(configure);
// AddOpenTelemetryMetrics scenarios where the builder is bound to an
// external service collection. return this;
internal MeterProviderBuilderBase(IServiceCollection services) }
/// <inheritdoc />
public MeterProviderBuilder ConfigureServices(Action<IServiceCollection> configure)
{
Guard.ThrowIfNull(configure);
var services = this.services;
if (services == null)
{ {
Guard.ThrowIfNull(services); throw new NotSupportedException("Services cannot be configured during MeterProvider construction.");
services.AddOpenTelemetryMeterProviderBuilderServices();
services.TryAddSingleton<MeterProvider>(sp => new MeterProviderSdk(sp, ownsServiceProvider: false));
this.services = services;
this.ownsServices = false;
} }
// This ctor is for Sdk.CreateMeterProviderBuilder where the builder configure(services);
// owns its services and service provider.
protected MeterProviderBuilderBase() return this;
}
/// <inheritdoc />
MeterProviderBuilder IDeferredMeterProviderBuilder.Configure(Action<IServiceProvider, MeterProviderBuilder> configure)
=> this.ConfigureBuilder(configure);
internal MeterProvider InvokeBuild()
=> this.Build();
/// <summary>
/// Run the configured actions to initialize the <see cref="MeterProvider"/>.
/// </summary>
/// <returns><see cref="MeterProvider"/>.</returns>
protected MeterProvider Build()
{
if (!this.allowBuild)
{ {
var services = new ServiceCollection(); throw new NotSupportedException("A MeterProviderBuilder bound to external service cannot be built directly. Access the MeterProvider using the application IServiceProvider instead.");
services.AddOpenTelemetryMeterProviderBuilderServices();
services.AddSingleton<MeterProvider>(
sp => throw new NotSupportedException("External MeterProvider created through Sdk.CreateMeterProviderBuilder cannot be accessed using service provider."));
this.services = services;
this.ownsServices = true;
} }
/// <inheritdoc /> var services = this.services;
public override MeterProviderBuilder AddInstrumentation<TInstrumentation>(Func<TInstrumentation> instrumentationFactory)
{
Guard.ThrowIfNull(instrumentationFactory);
return this.AddInstrumentation((sp) => instrumentationFactory()); if (services == null)
{
throw new NotSupportedException("MeterProviderBuilder build method cannot be called multiple times.");
} }
/// <inheritdoc /> this.services = null;
public override MeterProviderBuilder AddMeter(params string[] names)
{
Guard.ThrowIfNull(names);
return this.ConfigureState((sp, state) => state.AddMeter(names));
}
/// <inheritdoc />
MeterProviderBuilder IDeferredMeterProviderBuilder.Configure(
Action<IServiceProvider, MeterProviderBuilder> configure)
{
Guard.ThrowIfNull(configure);
if (this.State != null)
{
configure(this.State.ServiceProvider, this);
}
else
{
this.ConfigureServices(services
=> CallbackHelper.RegisterConfigureBuilderCallback(services, configure));
}
return this;
}
internal MeterProviderBuilder AddInstrumentation<T>()
where T : class
{
this.TryAddSingleton<T>();
this.AddInstrumentation((sp) => sp.GetRequiredService<T>());
return this;
}
internal MeterProviderBuilder AddReader<T>()
where T : MetricReader
{
this.TryAddSingleton<T>();
this.ConfigureState((sp, state) => state.AddReader(sp.GetRequiredService<T>()));
return this;
}
internal MeterProviderBuilder AddReader(MetricReader reader)
{
Guard.ThrowIfNull(reader);
return this.ConfigureState((sp, state) => state.AddReader(reader));
}
internal MeterProviderBuilder AddView(string instrumentName, string name)
{
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,
});
}
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);
}
}
internal MeterProviderBuilder AddView(Func<Instrument, MetricStreamConfiguration?> viewConfig)
{
Guard.ThrowIfNull(viewConfig);
this.ConfigureState((sp, state) => state.AddView(viewConfig));
return this;
}
internal MeterProviderBuilder ConfigureResource(Action<ResourceBuilder> configure)
{
Guard.ThrowIfNull(configure);
return this.ConfigureState((sp, state) => state.ConfigureResource(configure));
}
internal MeterProviderBuilder ConfigureServices(Action<IServiceCollection> configure)
{
Guard.ThrowIfNull(configure);
var services = this.services;
if (services == null)
{
throw new NotSupportedException("Services cannot be configured after ServiceProvider has been created.");
}
configure(services);
return this;
}
internal MeterProvider InvokeBuild()
=> this.Build();
internal MeterProviderBuilder SetMaxMetricStreams(int maxMetricStreams)
{
Guard.ThrowIfOutOfRange(maxMetricStreams, min: 1);
return this.ConfigureState((sp, state) => state.MaxMetricStreams = maxMetricStreams);
}
internal MeterProviderBuilder SetMaxMetricPointsPerMetricStream(int maxMetricPointsPerMetricStream)
{
Guard.ThrowIfOutOfRange(maxMetricPointsPerMetricStream, min: 1);
return this.ConfigureState((sp, state) => state.MaxMetricPointsPerMetricStream = maxMetricPointsPerMetricStream);
}
internal MeterProviderBuilder SetResourceBuilder(ResourceBuilder resourceBuilder)
{
Guard.ThrowIfNull(resourceBuilder);
return this.ConfigureState((sp, state) => state.SetResourceBuilder(resourceBuilder));
}
/// <summary>
/// Run the configured actions to initialize the <see cref="MeterProvider"/>.
/// </summary>
/// <returns><see cref="MeterProvider"/>.</returns>
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;
#if DEBUG #if DEBUG
bool validateScopes = true; bool validateScopes = true;
#else #else
bool validateScopes = false; bool validateScopes = false;
#endif #endif
var serviceProvider = services.BuildServiceProvider(validateScopes); var serviceProvider = services.BuildServiceProvider(validateScopes);
return new MeterProviderSdk(serviceProvider, ownsServiceProvider: true); return new MeterProviderSdk(serviceProvider, ownsServiceProvider: true);
}
private MeterProviderBuilder AddInstrumentation<T>(Func<IServiceProvider, T> 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 MeterProviderBuilder ConfigureState(Action<IServiceProvider, MeterProviderBuilderState> 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<T>()
where T : class
{
var services = this.services;
services?.TryAddSingleton<T>();
}
} }
} }

View File

@ -17,7 +17,10 @@
#nullable enable #nullable enable
using System.Diagnostics.Metrics; using System.Diagnostics.Metrics;
using System.Text.RegularExpressions;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using OpenTelemetry.Internal;
using OpenTelemetry.Resources; using OpenTelemetry.Resources;
namespace OpenTelemetry.Metrics namespace OpenTelemetry.Metrics
@ -27,27 +30,6 @@ namespace OpenTelemetry.Metrics
/// </summary> /// </summary>
public static class MeterProviderBuilderExtensions public static class MeterProviderBuilderExtensions
{ {
/// <summary>
/// Adds instrumentation to the provider.
/// </summary>
/// <remarks>
/// Note: The type specified by <typeparamref name="T"/> will be
/// registered as a singleton service into application services.
/// </remarks>
/// <typeparam name="T">Instrumentation type.</typeparam>
/// <param name="meterProviderBuilder"><see cref="MeterProviderBuilder"/>.</param>
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
public static MeterProviderBuilder AddInstrumentation<T>(this MeterProviderBuilder meterProviderBuilder)
where T : class
{
if (meterProviderBuilder is MeterProviderBuilderBase meterProviderBuilderBase)
{
meterProviderBuilderBase.AddInstrumentation<T>();
}
return meterProviderBuilder;
}
/// <summary> /// <summary>
/// Adds a reader to the provider. /// Adds a reader to the provider.
/// </summary> /// </summary>
@ -56,10 +38,15 @@ namespace OpenTelemetry.Metrics
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns> /// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
public static MeterProviderBuilder AddReader(this MeterProviderBuilder meterProviderBuilder, MetricReader reader) 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; return meterProviderBuilder;
} }
@ -77,10 +64,15 @@ namespace OpenTelemetry.Metrics
public static MeterProviderBuilder AddReader<T>(this MeterProviderBuilder meterProviderBuilder) public static MeterProviderBuilder AddReader<T>(this MeterProviderBuilder meterProviderBuilder)
where T : MetricReader where T : MetricReader
{ {
if (meterProviderBuilder is MeterProviderBuilderBase meterProviderBuilderBase) meterProviderBuilder.ConfigureServices(services => services.TryAddSingleton<T>());
meterProviderBuilder.ConfigureBuilder((sp, builder) =>
{ {
meterProviderBuilderBase.AddReader<T>(); if (builder is MeterProviderBuilderSdk meterProviderBuilderSdk)
} {
meterProviderBuilderSdk.AddReader(sp.GetRequiredService<T>());
}
});
return meterProviderBuilder; return meterProviderBuilder;
} }
@ -96,11 +88,22 @@ namespace OpenTelemetry.Metrics
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns> /// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
public static MeterProviderBuilder AddView(this MeterProviderBuilder meterProviderBuilder, string instrumentName, string name) 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; return meterProviderBuilder;
} }
@ -115,11 +118,35 @@ namespace OpenTelemetry.Metrics
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns> /// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
public static MeterProviderBuilder AddView(this MeterProviderBuilder meterProviderBuilder, string instrumentName, MetricStreamConfiguration metricStreamConfiguration) 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; return meterProviderBuilder;
} }
@ -141,10 +168,15 @@ namespace OpenTelemetry.Metrics
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns> /// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
public static MeterProviderBuilder AddView(this MeterProviderBuilder meterProviderBuilder, Func<Instrument, MetricStreamConfiguration?> viewConfig) public static MeterProviderBuilder AddView(this MeterProviderBuilder meterProviderBuilder, Func<Instrument, MetricStreamConfiguration?> 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; return meterProviderBuilder;
} }
@ -165,10 +197,15 @@ namespace OpenTelemetry.Metrics
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns> /// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
public static MeterProviderBuilder SetMaxMetricStreams(this MeterProviderBuilder meterProviderBuilder, int maxMetricStreams) 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; return meterProviderBuilder;
} }
@ -188,10 +225,15 @@ namespace OpenTelemetry.Metrics
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns> /// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
public static MeterProviderBuilder SetMaxMetricPointsPerMetricStream(this MeterProviderBuilder meterProviderBuilder, int maxMetricPointsPerMetricStream) 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; return meterProviderBuilder;
} }
@ -207,10 +249,13 @@ namespace OpenTelemetry.Metrics
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns> /// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
public static MeterProviderBuilder SetResourceBuilder(this MeterProviderBuilder meterProviderBuilder, ResourceBuilder resourceBuilder) 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; return meterProviderBuilder;
} }
@ -224,53 +269,13 @@ namespace OpenTelemetry.Metrics
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns> /// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
public static MeterProviderBuilder ConfigureResource(this MeterProviderBuilder meterProviderBuilder, Action<ResourceBuilder> configure) public static MeterProviderBuilder ConfigureResource(this MeterProviderBuilder meterProviderBuilder, Action<ResourceBuilder> configure)
{ {
if (meterProviderBuilder is MeterProviderBuilderBase meterProviderBuilderBase) meterProviderBuilder.ConfigureBuilder((sp, builder) =>
{ {
meterProviderBuilderBase.ConfigureResource(configure); if (builder is MeterProviderBuilderSdk meterProviderBuilderSdk)
} {
meterProviderBuilderSdk.ConfigureResource(configure);
return meterProviderBuilder; }
} });
/// <summary>
/// Register a callback action to configure the <see
/// cref="IServiceCollection"/> where metric services are configured.
/// </summary>
/// <remarks>
/// Note: Metric services are only available during the application
/// configuration phase.
/// </remarks>
/// <param name="meterProviderBuilder"><see cref="MeterProviderBuilder"/>.</param>
/// <param name="configure">Configuration callback.</param>
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
public static MeterProviderBuilder ConfigureServices(
this MeterProviderBuilder meterProviderBuilder,
Action<IServiceCollection> configure)
{
if (meterProviderBuilder is MeterProviderBuilderBase meterProviderBuilderBase)
{
meterProviderBuilderBase.ConfigureServices(configure);
}
return meterProviderBuilder;
}
/// <summary>
/// Register a callback action to configure the <see
/// cref="MeterProviderBuilder"/> once the application <see
/// cref="IServiceProvider"/> is available.
/// </summary>
/// <param name="meterProviderBuilder"><see cref="MeterProviderBuilder"/>.</param>
/// <param name="configure">Configuration callback.</param>
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
public static MeterProviderBuilder ConfigureBuilder(
this MeterProviderBuilder meterProviderBuilder,
Action<IServiceProvider, MeterProviderBuilder> configure)
{
if (meterProviderBuilder is IDeferredMeterProviderBuilder deferredMeterProviderBuilder)
{
deferredMeterProviderBuilder.Configure(configure);
}
return meterProviderBuilder; return meterProviderBuilder;
} }

View File

@ -16,29 +16,50 @@
#nullable enable #nullable enable
using System.Diagnostics;
using System.Diagnostics.Metrics;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry.Internal;
using OpenTelemetry.Resources;
namespace OpenTelemetry.Metrics namespace OpenTelemetry.Metrics
{ {
internal sealed class MeterProviderBuilderSdk : MeterProviderBuilderBase /// <summary>
/// Stores state used to build a <see cref="MeterProvider"/>.
/// </summary>
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( private static readonly Regex InstrumentNameRegex = new(
@"^[a-z][a-z0-9-._]{0,62}$", RegexOptions.IgnoreCase | RegexOptions.Compiled); @"^[a-z][a-z0-9-._]{0,62}$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
public MeterProviderBuilderSdk() private readonly IServiceProvider serviceProvider;
private MeterProviderSdk? meterProvider;
public MeterProviderBuilderSdk(IServiceProvider serviceProvider)
{ {
this.serviceProvider = serviceProvider;
} }
public MeterProviderBuilderSdk(IServiceCollection services) public List<InstrumentationRegistration> Instrumentation { get; } = new();
: base(services)
{
}
public MeterProviderBuilderSdk(MeterProviderBuilderState state) public ResourceBuilder? ResourceBuilder { get; private set; }
: base(state)
{ public MeterProvider? Provider => this.meterProvider;
}
public List<MetricReader> Readers { get; } = new();
public List<string> MeterSources { get; } = new();
public List<Func<Instrument, MetricStreamConfiguration?>> ViewConfigs { get; } = new();
public int MaxMetricStreams { get; private set; } = MaxMetricsDefault;
public int MaxMetricPointsPerMetricStream { get; private set; } = MaxMetricPointsPerMetricDefault;
/// <summary> /// <summary>
/// Returns whether the given instrument name is valid according to the specification. /// Returns whether the given instrument name is valid according to the specification.
@ -72,5 +93,143 @@ namespace OpenTelemetry.Metrics
return InstrumentNameRegex.IsMatch(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<TInstrumentation>(
Func<TInstrumentation> 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<ResourceBuilder> 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<Instrument, MetricStreamConfiguration?> 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<IServiceProvider, MeterProviderBuilder> configure)
{
Debug.Assert(configure != null, "configure was null");
configure!(this.serviceProvider, this);
return this;
}
public MeterProviderBuilder ConfigureServices(Action<IServiceCollection> configure)
{
throw new NotSupportedException("Services cannot be configured after ServiceProvider has been created.");
}
MeterProviderBuilder IDeferredMeterProviderBuilder.Configure(Action<IServiceProvider, MeterProviderBuilder> 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;
}
}
} }
} }

View File

@ -1,76 +0,0 @@
// <copyright file="MeterProviderBuilderServiceCollectionExtensions.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
#nullable enable
using OpenTelemetry;
using OpenTelemetry.Internal;
using OpenTelemetry.Metrics;
namespace Microsoft.Extensions.DependencyInjection;
/// <summary>
/// Extension methods for setting up OpenTelemetry Metrics services in an <see cref="IServiceCollection" />.
/// </summary>
public static class MeterProviderBuilderServiceCollectionExtensions
{
/// <summary>
/// Configures OpenTelemetry Metrics services in the supplied <see cref="IServiceCollection" />.
/// </summary>
/// <remarks>
/// Notes:
/// <list type="bullet">
/// <item>A <see cref="MeterProvider"/> will not be created automatically
/// using this method. Either use the
/// <c>IServiceCollection.AddOpenTelemetryMetrics</c> extension in the
/// <c>OpenTelemetry.Extensions.Hosting</c> package or access the <see
/// cref="MeterProvider"/> through the application <see
/// cref="IServiceProvider"/> to begin collecting traces.</item>
/// <item>This is safe to be called multiple times and by library authors.
/// Only a single <see cref="MeterProvider"/> will be created for a given
/// <see cref="IServiceCollection"/>.</item>
/// </list>
/// </remarks>
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
/// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns>
public static IServiceCollection ConfigureOpenTelemetryMetrics(this IServiceCollection services)
=> ConfigureOpenTelemetryMetrics(services, (b) => { });
/// <summary>
/// Configures OpenTelemetry Metrics services in the supplied <see cref="IServiceCollection" />.
/// </summary>
/// <remarks><inheritdoc cref="ConfigureOpenTelemetryMetrics(IServiceCollection)" path="/remarks"/></remarks>
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
/// <param name="configure">Callback action to configure the <see cref="MeterProviderBuilder"/>.</param>
/// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns>
public static IServiceCollection ConfigureOpenTelemetryMetrics(this IServiceCollection services, Action<MeterProviderBuilder> 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;
}
}

View File

@ -1,79 +0,0 @@
// <copyright file="MeterProviderBuilderState.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
#nullable enable
using System.Diagnostics;
using System.Diagnostics.Metrics;
using OpenTelemetry.Internal;
namespace OpenTelemetry.Metrics
{
/// <summary>
/// Stores state used to build a <see cref="MeterProvider"/>.
/// </summary>
internal sealed class MeterProviderBuilderState : ProviderBuilderState<MeterProviderBuilderSdk, MeterProviderSdk>
{
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<MetricReader> Readers { get; } = new();
public List<string> MeterSources { get; } = new();
public List<Func<Instrument, MetricStreamConfiguration?>> 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<Instrument, MetricStreamConfiguration?> viewConfig)
{
Debug.Assert(viewConfig != null, "viewConfig was null");
this.ViewConfigs.Add(viewConfig!);
}
}
}

View File

@ -23,11 +23,6 @@ using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry.Internal; using OpenTelemetry.Internal;
using OpenTelemetry.Resources; using OpenTelemetry.Resources;
using CallbackHelper = OpenTelemetry.ProviderBuilderServiceCollectionCallbackHelper<
OpenTelemetry.Metrics.MeterProviderBuilderSdk,
OpenTelemetry.Metrics.MeterProviderSdk,
OpenTelemetry.Metrics.MeterProviderBuilderState>;
namespace OpenTelemetry.Metrics namespace OpenTelemetry.Metrics
{ {
internal sealed class MeterProviderSdk : MeterProvider internal sealed class MeterProviderSdk : MeterProvider
@ -50,8 +45,8 @@ namespace OpenTelemetry.Metrics
{ {
Debug.Assert(serviceProvider != null, "serviceProvider was null"); Debug.Assert(serviceProvider != null, "serviceProvider was null");
var state = serviceProvider!.GetRequiredService<MeterProviderBuilderState>(); var state = serviceProvider!.GetRequiredService<MeterProviderBuilderSdk>();
state.RegisterProvider(nameof(MeterProvider), this); state.RegisterProvider(this);
this.ServiceProvider = serviceProvider!; this.ServiceProvider = serviceProvider!;
@ -63,9 +58,11 @@ namespace OpenTelemetry.Metrics
OpenTelemetrySdkEventSource.Log.MeterProviderSdkEvent("Building MeterProvider."); OpenTelemetrySdkEventSource.Log.MeterProviderSdkEvent("Building MeterProvider.");
CallbackHelper.InvokeRegisteredConfigureStateCallbacks( var configureProviderBuilders = serviceProvider!.GetServices<IConfigureMeterProviderBuilder>();
serviceProvider!, foreach (var configureProviderBuilder in configureProviderBuilders)
state); {
configureProviderBuilder.ConfigureBuilder(serviceProvider!, state);
}
StringBuilder exportersAdded = new StringBuilder(); StringBuilder exportersAdded = new StringBuilder();
StringBuilder instrumentationFactoriesAdded = new StringBuilder(); StringBuilder instrumentationFactoriesAdded = new StringBuilder();

View File

@ -27,7 +27,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Api\OpenTelemetry.Api.csproj" /> <ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Extensions.DependencyInjection\OpenTelemetry.Extensions.DependencyInjection.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,154 @@
// <copyright file="OpenTelemetryBuilder.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
#nullable enable
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry.Internal;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
namespace OpenTelemetry;
/// <summary>
/// Contains methods for configuring the OpenTelemetry SDK inside an <see
/// cref="IServiceCollection"/>.
/// </summary>
public class OpenTelemetryBuilder
{
internal OpenTelemetryBuilder(IServiceCollection services)
{
Guard.ThrowIfNull(services);
services.AddOpenTelemetrySharedProviderBuilderServices();
this.Services = services;
}
/// <summary>
/// Gets the <see cref="IServiceCollection"/> behind the builder.
/// </summary>
public IServiceCollection Services { get; }
/// <summary>
/// Registers an action to configure the <see cref="ResourceBuilder"/>s used
/// by tracing and metrics.
/// </summary>
/// <remarks>
/// Note: This is safe to be called multiple times and by library authors.
/// Each registered configuration action will be applied sequentially.
/// </remarks>
/// <param name="configure"><see cref="ResourceBuilder"/> configuration
/// action.</param>
/// <returns>The supplied <see cref="OpenTelemetryBuilder"/> for chaining
/// calls.</returns>
public OpenTelemetryBuilder ConfigureResource(
Action<ResourceBuilder> configure)
{
Guard.ThrowIfNull(configure);
this.Services.ConfigureOpenTelemetryMeterProvider(
(sp, builder) => builder.ConfigureResource(configure));
this.Services.ConfigureOpenTelemetryTracerProvider(
(sp, builder) => builder.ConfigureResource(configure));
return this;
}
/// <summary>
/// Adds metric services into the builder.
/// </summary>
/// <remarks>
/// Notes:
/// <list type="bullet">
/// <item>A <see cref="MeterProvider"/> will not be created automatically
/// using this method. To begin collecting metrics either use the
/// <c>OpenTelemetryBuilder.StartWithHost</c> extension in the
/// <c>OpenTelemetry.Extensions.Hosting</c> package or access the <see
/// cref="MeterProvider"/> through the application <see
/// cref="IServiceProvider"/>.</item>
/// <item>This is safe to be called multiple times and by library authors.
/// Only a single <see cref="MeterProvider"/> will be created for a given
/// <see cref="IServiceCollection"/>.</item>
/// </list>
/// </remarks>
/// <returns>The supplied <see cref="OpenTelemetryBuilder"/> for chaining
/// calls.</returns>
public OpenTelemetryBuilder WithMetrics()
=> this.WithMetrics(b => { });
/// <summary>
/// Adds metric services into the builder.
/// </summary>
/// <remarks><inheritdoc cref="WithMetrics()" path="/remarks"/></remarks>
/// <param name="configure"><see cref="MeterProviderBuilder"/>
/// configuration callback.</param>
/// <returns>The supplied <see cref="OpenTelemetryBuilder"/> for chaining
/// calls.</returns>
public OpenTelemetryBuilder WithMetrics(Action<MeterProviderBuilder> configure)
{
Guard.ThrowIfNull(configure);
var builder = new MeterProviderBuilderBase(this.Services);
configure(builder);
return this;
}
/// <summary>
/// Adds tracing services into the builder.
/// </summary>
/// <remarks>
/// Notes:
/// <list type="bullet">
/// <item>A <see cref="TracerProvider"/> will not be created automatically
/// using this method. To begin collecting traces either use the
/// <c>OpenTelemetryBuilder.StartWithHost</c> extension in the
/// <c>OpenTelemetry.Extensions.Hosting</c> package or access the <see
/// cref="TracerProvider"/> through the application <see
/// cref="IServiceProvider"/>.</item>
/// <item>This is safe to be called multiple times and by library authors.
/// Only a single <see cref="TracerProvider"/> will be created for a given
/// <see cref="IServiceCollection"/>.</item>
/// </list>
/// </remarks>
/// <returns>The supplied <see cref="OpenTelemetryBuilder"/> for chaining
/// calls.</returns>
public OpenTelemetryBuilder WithTracing()
=> this.WithTracing(b => { });
/// <summary>
/// Adds tracing services into the builder.
/// </summary>
/// <remarks><inheritdoc cref="WithTracing()" path="/remarks"/></remarks>
/// <param name="configure"><see cref="TracerProviderBuilder"/>
/// configuration callback.</param>
/// <returns>The supplied <see cref="OpenTelemetryBuilder"/> for chaining
/// calls.</returns>
public OpenTelemetryBuilder WithTracing(Action<TracerProviderBuilder> configure)
{
Guard.ThrowIfNull(configure);
var builder = new TracerProviderBuilderBase(this.Services);
configure(builder);
return this;
}
}

View File

@ -0,0 +1,55 @@
// <copyright file="OpenTelemetryServiceCollectionExtensions.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
#nullable enable
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
namespace OpenTelemetry;
/// <summary>
/// Contains <see cref="IServiceCollection"/> extension methods for registering OpenTelemetry SDK artifacts.
/// </summary>
public static class OpenTelemetryServiceCollectionExtensions
{
/// <summary>
/// Adds OpenTelemetry SDK services into the supplied <see
/// cref="IServiceCollection"/>.
/// </summary>
/// <remarks>
/// Notes:
/// <list type="bullet">
/// <item>A <see cref="TracerProvider"/> and/or <see cref="MeterProvider"/>
/// will not be created automatically using this method. To begin collecting
/// traces and/or metrics either use the
/// <c>OpenTelemetryBuilder.StartWithHost</c> extension in the
/// <c>OpenTelemetry.Extensions.Hosting</c> package or access the <see
/// cref="TracerProvider"/> and/or <see cref="MeterProvider"/> through the
/// application <see cref="IServiceProvider"/>.</item>
/// <item>This is safe to be called multiple times and by library authors.
/// Only a single <see cref="TracerProvider"/> and/or <see
/// cref="MeterProvider"/> will be created for a given <see
/// cref="IServiceCollection"/>.</item>
/// </list>
/// </remarks>
/// <param name="services"><see cref="IServiceCollection"/>.</param>
/// <returns>The supplied <see cref="OpenTelemetryBuilder"/> for chaining
/// calls.</returns>
public static OpenTelemetryBuilder AddOpenTelemetry(this IServiceCollection services)
=> new(services);
}

View File

@ -68,7 +68,7 @@ namespace OpenTelemetry
/// <returns><see cref="MeterProviderBuilder"/> instance, which is used to build a <see cref="MeterProvider"/>.</returns> /// <returns><see cref="MeterProviderBuilder"/> instance, which is used to build a <see cref="MeterProvider"/>.</returns>
public static MeterProviderBuilder CreateMeterProviderBuilder() public static MeterProviderBuilder CreateMeterProviderBuilder()
{ {
return new MeterProviderBuilderSdk(); return new MeterProviderBuilderBase();
} }
/// <summary> /// <summary>
@ -81,7 +81,7 @@ namespace OpenTelemetry
/// <returns><see cref="TracerProviderBuilder"/> instance, which is used to build a <see cref="TracerProvider"/>.</returns> /// <returns><see cref="TracerProviderBuilder"/> instance, which is used to build a <see cref="TracerProvider"/>.</returns>
public static TracerProviderBuilder CreateTracerProviderBuilder() public static TracerProviderBuilder CreateTracerProviderBuilder()
{ {
return new TracerProviderBuilderSdk(); return new TracerProviderBuilderBase();
} }
} }
} }

View File

@ -16,279 +16,191 @@
#nullable enable #nullable enable
using System.Diagnostics;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.DependencyInjection.Extensions;
using OpenTelemetry.Internal; using OpenTelemetry.Internal;
using OpenTelemetry.Resources;
using CallbackHelper = OpenTelemetry.ProviderBuilderServiceCollectionCallbackHelper< namespace OpenTelemetry.Trace;
OpenTelemetry.Trace.TracerProviderBuilderSdk,
OpenTelemetry.Trace.TracerProviderSdk,
OpenTelemetry.Trace.TracerProviderBuilderState>;
namespace OpenTelemetry.Trace /// <summary>
/// Contains methods for building <see cref="TracerProvider"/> instances.
/// </summary>
public class TracerProviderBuilderBase : TracerProviderBuilder, ITracerProviderBuilder
{ {
private readonly bool allowBuild;
private IServiceCollection? services;
/// <summary> /// <summary>
/// Contains methods for building <see cref="TracerProvider"/> instances. /// Initializes a new instance of the <see cref="TracerProviderBuilderBase"/> class.
/// </summary> /// </summary>
public abstract class TracerProviderBuilderBase : TracerProviderBuilder, IDeferredTracerProviderBuilder public TracerProviderBuilderBase()
{ {
internal readonly TracerProviderBuilderState? State; var services = new ServiceCollection();
private const string DefaultInstrumentationVersion = "1.0.0.0";
private readonly bool ownsServices; services
private IServiceCollection? services; .AddOpenTelemetrySharedProviderBuilderServices()
.AddOpenTelemetryTracerProviderBuilderServices()
.TryAddSingleton<TracerProvider>(
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 services.ConfigureOpenTelemetryTracerProvider((sp, builder) => this.services = null);
// happens after the service provider has been created.
internal TracerProviderBuilderBase(TracerProviderBuilderState state) this.services = services;
this.allowBuild = true;
}
internal TracerProviderBuilderBase(IServiceCollection services)
{
Guard.ThrowIfNull(services);
services
.AddOpenTelemetryTracerProviderBuilderServices()
.TryAddSingleton<TracerProvider>(sp => new TracerProviderSdk(sp, ownsServiceProvider: false));
services.ConfigureOpenTelemetryTracerProvider((sp, builder) => this.services = null);
this.services = services;
this.allowBuild = false;
}
/// <inheritdoc />
TracerProvider? ITracerProviderBuilder.Provider => null;
/// <inheritdoc />
public override TracerProviderBuilder AddInstrumentation<TInstrumentation>(Func<TInstrumentation> instrumentationFactory)
{
Guard.ThrowIfNull(instrumentationFactory);
this.ConfigureBuilder((sp, builder) =>
{ {
Debug.Assert(state != null, "state was null"); builder.AddInstrumentation(instrumentationFactory);
});
this.State = state; return this;
}
/// <inheritdoc />
public override TracerProviderBuilder AddSource(params string[] names)
{
Guard.ThrowIfNull(names);
this.ConfigureBuilder((sp, builder) =>
{
builder.AddSource(names);
});
return this;
}
/// <inheritdoc />
public override TracerProviderBuilder AddLegacySource(string operationName)
{
Guard.ThrowIfNullOrWhitespace(operationName);
this.ConfigureBuilder((sp, builder) =>
{
builder.AddLegacySource(operationName);
});
return this;
}
/// <inheritdoc />
public TracerProviderBuilder ConfigureBuilder(Action<IServiceProvider, TracerProviderBuilder> configure)
{
var services = this.services;
if (services == null)
{
throw new NotSupportedException("Builder cannot be configured during TracerProvider construction.");
} }
// This ctor is for ConfigureOpenTelemetryTracing + services.ConfigureOpenTelemetryTracerProvider(configure);
// AddOpenTelemetryTracing scenarios where the builder is bound to an
// external service collection. return this;
internal TracerProviderBuilderBase(IServiceCollection services) }
/// <inheritdoc />
public TracerProviderBuilder ConfigureServices(Action<IServiceCollection> configure)
{
Guard.ThrowIfNull(configure);
var services = this.services;
if (services == null)
{ {
Guard.ThrowIfNull(services); throw new NotSupportedException("Services cannot be configured during TracerProvider construction.");
services.AddOpenTelemetryTracerProviderBuilderServices();
services.TryAddSingleton<TracerProvider>(sp => new TracerProviderSdk(sp, ownsServiceProvider: false));
this.services = services;
this.ownsServices = false;
} }
// This ctor is for Sdk.CreateTracerProviderBuilder where the builder configure(services);
// owns its services and service provider.
protected TracerProviderBuilderBase() return this;
}
/// <inheritdoc />
TracerProviderBuilder IDeferredTracerProviderBuilder.Configure(Action<IServiceProvider, TracerProviderBuilder> configure)
=> this.ConfigureBuilder(configure);
internal TracerProvider InvokeBuild()
=> this.Build();
/// <summary>
/// Adds instrumentation to the provider.
/// </summary>d
/// <param name="instrumentationName">Instrumentation name.</param>
/// <param name="instrumentationVersion">Instrumentation version.</param>
/// <param name="instrumentationFactory">Function that builds instrumentation.</param>
/// <returns>Returns <see cref="TracerProviderBuilder"/> for chaining.</returns>
protected TracerProviderBuilder AddInstrumentation(
string instrumentationName,
string instrumentationVersion,
Func<object> instrumentationFactory)
{
Guard.ThrowIfNullOrWhitespace(instrumentationName);
Guard.ThrowIfNullOrWhitespace(instrumentationVersion);
Guard.ThrowIfNull(instrumentationFactory);
return this.ConfigureBuilder((sp, builder) =>
{ {
var services = new ServiceCollection(); if (builder is TracerProviderBuilderSdk tracerProviderBuilderState)
services.AddOpenTelemetryTracerProviderBuilderServices();
services.AddSingleton<TracerProvider>(
sp => throw new NotSupportedException("External TracerProvider created through Sdk.CreateTracerProviderBuilder cannot be accessed using service provider."));
this.services = services;
this.ownsServices = true;
}
/// <inheritdoc />
public override TracerProviderBuilder AddInstrumentation<TInstrumentation>(
Func<TInstrumentation> instrumentationFactory)
where TInstrumentation : class
{
Guard.ThrowIfNull(instrumentationFactory);
return this.AddInstrumentation((sp) => instrumentationFactory());
}
/// <inheritdoc />
public override TracerProviderBuilder AddSource(params string[] names)
{
Guard.ThrowIfNull(names);
return this.ConfigureState((sp, state) => state.AddSource(names));
}
/// <inheritdoc />
public override TracerProviderBuilder AddLegacySource(string operationName)
{
Guard.ThrowIfNullOrWhitespace(operationName);
return this.ConfigureState((sp, state) => state.AddLegacySource(operationName));
}
/// <inheritdoc />
TracerProviderBuilder IDeferredTracerProviderBuilder.Configure(
Action<IServiceProvider, TracerProviderBuilder> configure)
{
Guard.ThrowIfNull(configure);
if (this.State != null)
{ {
configure(this.State.ServiceProvider, this); tracerProviderBuilderState.AddInstrumentation(
}
else
{
this.ConfigureServices(services
=> CallbackHelper.RegisterConfigureBuilderCallback(services, configure));
}
return this;
}
internal TracerProviderBuilder AddInstrumentation<T>()
where T : class
{
this.TryAddSingleton<T>();
this.AddInstrumentation((sp) => sp.GetRequiredService<T>());
return this;
}
internal TracerProviderBuilder AddProcessor<T>()
where T : BaseProcessor<Activity>
{
this.TryAddSingleton<T>();
this.ConfigureState((sp, state) => state.AddProcessor(sp.GetRequiredService<T>()));
return this;
}
internal TracerProviderBuilder AddProcessor(BaseProcessor<Activity> processor)
{
Guard.ThrowIfNull(processor);
return this.ConfigureState((sp, state) => state.AddProcessor(processor));
}
internal TracerProviderBuilder ConfigureResource(Action<ResourceBuilder> configure)
{
Guard.ThrowIfNull(configure);
return this.ConfigureState((sp, state) => state.ConfigureResource(configure));
}
internal TracerProviderBuilder ConfigureServices(Action<IServiceCollection> configure)
{
Guard.ThrowIfNull(configure);
var services = this.services;
if (services == null)
{
throw new NotSupportedException("Services cannot be configured after ServiceProvider has been created.");
}
configure(services);
return this;
}
internal TracerProvider InvokeBuild()
=> this.Build();
internal TracerProviderBuilder SetErrorStatusOnException(bool enabled)
{
return this.ConfigureState((sp, state) => state.SetErrorStatusOnException = enabled);
}
internal TracerProviderBuilder SetResourceBuilder(ResourceBuilder resourceBuilder)
{
Guard.ThrowIfNull(resourceBuilder);
return this.ConfigureState((sp, state) => state.SetResourceBuilder(resourceBuilder));
}
internal TracerProviderBuilder SetSampler<T>()
where T : Sampler
{
this.TryAddSingleton<T>();
this.ConfigureState((sp, state) => state.SetSampler(sp.GetRequiredService<T>()));
return this;
}
internal TracerProviderBuilder SetSampler(Sampler sampler)
{
Guard.ThrowIfNull(sampler);
return this.ConfigureState((sp, state) => state.SetSampler(sampler));
}
/// <summary>
/// Adds instrumentation to the provider.
/// </summary>d
/// <param name="instrumentationName">Instrumentation name.</param>
/// <param name="instrumentationVersion">Instrumentation version.</param>
/// <param name="instrumentationFactory">Function that builds instrumentation.</param>
/// <returns>Returns <see cref="TracerProviderBuilder"/> for chaining.</returns>
protected TracerProviderBuilder AddInstrumentation(
string instrumentationName,
string instrumentationVersion,
Func<object> instrumentationFactory)
{
Guard.ThrowIfNullOrWhitespace(instrumentationName);
Guard.ThrowIfNullOrWhitespace(instrumentationVersion);
Guard.ThrowIfNull(instrumentationFactory);
return this.ConfigureState((sp, state)
=> state.AddInstrumentation(
instrumentationName, instrumentationName,
instrumentationVersion, instrumentationVersion,
instrumentationFactory())); instrumentationFactory);
}
});
}
/// <summary>
/// Run the configured actions to initialize the <see cref="TracerProvider"/>.
/// </summary>
/// <returns><see cref="TracerProvider"/>.</returns>
protected TracerProvider Build()
{
if (!this.allowBuild)
{
throw new NotSupportedException("A TracerProviderBuilder bound to external service cannot be built directly. Access the TracerProvider using the application IServiceProvider instead.");
} }
/// <summary> var services = this.services;
/// Run the configured actions to initialize the <see cref="TracerProvider"/>.
/// </summary> if (services == null)
/// <returns><see cref="TracerProvider"/>.</returns>
protected TracerProvider Build()
{ {
if (!this.ownsServices || this.State != null) throw new NotSupportedException("TracerProviderBuilder build method cannot be called multiple times.");
{ }
throw new NotSupportedException("Build cannot be called directly on TracerProviderBuilder tied to external services.");
}
var services = this.services; this.services = null;
if (services == null)
{
throw new NotSupportedException("TracerProviderBuilder build method cannot be called multiple times.");
}
this.services = null;
#if DEBUG #if DEBUG
bool validateScopes = true; bool validateScopes = true;
#else #else
bool validateScopes = false; bool validateScopes = false;
#endif #endif
var serviceProvider = services.BuildServiceProvider(validateScopes); var serviceProvider = services.BuildServiceProvider(validateScopes);
return new TracerProviderSdk(serviceProvider, ownsServiceProvider: true); return new TracerProviderSdk(serviceProvider, ownsServiceProvider: true);
}
private TracerProviderBuilder AddInstrumentation<T>(Func<IServiceProvider, T> 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<IServiceProvider, TracerProviderBuilderState> 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<T>()
where T : class
{
var services = this.services;
services?.TryAddSingleton<T>();
}
} }
} }

View File

@ -18,6 +18,8 @@
using System.Diagnostics; using System.Diagnostics;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using OpenTelemetry.Internal;
using OpenTelemetry.Resources; using OpenTelemetry.Resources;
namespace OpenTelemetry.Trace namespace OpenTelemetry.Trace
@ -36,10 +38,13 @@ namespace OpenTelemetry.Trace
/// <returns>Returns <see cref="TracerProviderBuilder"/> for chaining.</returns> /// <returns>Returns <see cref="TracerProviderBuilder"/> for chaining.</returns>
public static TracerProviderBuilder SetErrorStatusOnException(this TracerProviderBuilder tracerProviderBuilder, bool enabled = true) 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; return tracerProviderBuilder;
} }
@ -52,10 +57,15 @@ namespace OpenTelemetry.Trace
/// <returns>Returns <see cref="TracerProviderBuilder"/> for chaining.</returns> /// <returns>Returns <see cref="TracerProviderBuilder"/> for chaining.</returns>
public static TracerProviderBuilder SetSampler(this TracerProviderBuilder tracerProviderBuilder, Sampler sampler) 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; return tracerProviderBuilder;
} }
@ -73,10 +83,15 @@ namespace OpenTelemetry.Trace
public static TracerProviderBuilder SetSampler<T>(this TracerProviderBuilder tracerProviderBuilder) public static TracerProviderBuilder SetSampler<T>(this TracerProviderBuilder tracerProviderBuilder)
where T : Sampler where T : Sampler
{ {
if (tracerProviderBuilder is TracerProviderBuilderBase tracerProviderBuilderBase) tracerProviderBuilder.ConfigureServices(services => services.TryAddSingleton<T>());
tracerProviderBuilder.ConfigureBuilder((sp, builder) =>
{ {
tracerProviderBuilderBase.SetSampler<T>(); if (builder is TracerProviderBuilderSdk tracerProviderBuilderSdk)
} {
tracerProviderBuilderSdk.SetSampler(sp.GetRequiredService<T>());
}
});
return tracerProviderBuilder; return tracerProviderBuilder;
} }
@ -92,10 +107,15 @@ namespace OpenTelemetry.Trace
/// <returns>Returns <see cref="TracerProviderBuilder"/> for chaining.</returns> /// <returns>Returns <see cref="TracerProviderBuilder"/> for chaining.</returns>
public static TracerProviderBuilder SetResourceBuilder(this TracerProviderBuilder tracerProviderBuilder, ResourceBuilder resourceBuilder) 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; return tracerProviderBuilder;
} }
@ -109,10 +129,15 @@ namespace OpenTelemetry.Trace
/// <returns>Returns <see cref="TracerProviderBuilder"/> for chaining.</returns> /// <returns>Returns <see cref="TracerProviderBuilder"/> for chaining.</returns>
public static TracerProviderBuilder ConfigureResource(this TracerProviderBuilder tracerProviderBuilder, Action<ResourceBuilder> configure) public static TracerProviderBuilder ConfigureResource(this TracerProviderBuilder tracerProviderBuilder, Action<ResourceBuilder> 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; return tracerProviderBuilder;
} }
@ -125,10 +150,15 @@ namespace OpenTelemetry.Trace
/// <returns>Returns <see cref="TracerProviderBuilder"/> for chaining.</returns> /// <returns>Returns <see cref="TracerProviderBuilder"/> for chaining.</returns>
public static TracerProviderBuilder AddProcessor(this TracerProviderBuilder tracerProviderBuilder, BaseProcessor<Activity> processor) public static TracerProviderBuilder AddProcessor(this TracerProviderBuilder tracerProviderBuilder, BaseProcessor<Activity> 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; return tracerProviderBuilder;
} }
@ -146,74 +176,15 @@ namespace OpenTelemetry.Trace
public static TracerProviderBuilder AddProcessor<T>(this TracerProviderBuilder tracerProviderBuilder) public static TracerProviderBuilder AddProcessor<T>(this TracerProviderBuilder tracerProviderBuilder)
where T : BaseProcessor<Activity> where T : BaseProcessor<Activity>
{ {
if (tracerProviderBuilder is TracerProviderBuilderBase tracerProviderBuilderBase) tracerProviderBuilder.ConfigureServices(services => services.TryAddSingleton<T>());
tracerProviderBuilder.ConfigureBuilder((sp, builder) =>
{ {
tracerProviderBuilderBase.AddProcessor<T>(); if (builder is TracerProviderBuilderSdk tracerProviderBuilderSdk)
} {
tracerProviderBuilderSdk.AddProcessor(sp.GetRequiredService<T>());
return tracerProviderBuilder; }
} });
/// <summary>
/// Adds instrumentation to the provider.
/// </summary>
/// <remarks>
/// Note: The type specified by <typeparamref name="T"/> will be
/// registered as a singleton service into application services.
/// </remarks>
/// <typeparam name="T">Instrumentation type.</typeparam>
/// <param name="tracerProviderBuilder"><see cref="TracerProviderBuilder"/>.</param>
/// <returns>The supplied <see cref="TracerProviderBuilder"/> for chaining.</returns>
public static TracerProviderBuilder AddInstrumentation<T>(this TracerProviderBuilder tracerProviderBuilder)
where T : class
{
if (tracerProviderBuilder is TracerProviderBuilderBase tracerProviderBuilderBase)
{
tracerProviderBuilderBase.AddInstrumentation<T>();
}
return tracerProviderBuilder;
}
/// <summary>
/// Register a callback action to configure the <see
/// cref="IServiceCollection"/> where tracing services are configured.
/// </summary>
/// <remarks>
/// Note: Tracing services are only available during the application
/// configuration phase.
/// </remarks>
/// <param name="tracerProviderBuilder"><see cref="TracerProviderBuilder"/>.</param>
/// <param name="configure">Configuration callback.</param>
/// <returns>The supplied <see cref="TracerProviderBuilder"/> for chaining.</returns>
public static TracerProviderBuilder ConfigureServices(
this TracerProviderBuilder tracerProviderBuilder,
Action<IServiceCollection> configure)
{
if (tracerProviderBuilder is TracerProviderBuilderBase tracerProviderBuilderBase)
{
tracerProviderBuilderBase.ConfigureServices(configure);
}
return tracerProviderBuilder;
}
/// <summary>
/// Register a callback action to configure the <see
/// cref="TracerProviderBuilder"/> once the application <see
/// cref="IServiceProvider"/> is available.
/// </summary>
/// <param name="tracerProviderBuilder"><see cref="TracerProviderBuilder"/>.</param>
/// <param name="configure">Configuration callback.</param>
/// <returns>The supplied <see cref="TracerProviderBuilder"/> for chaining.</returns>
public static TracerProviderBuilder ConfigureBuilder(
this TracerProviderBuilder tracerProviderBuilder,
Action<IServiceProvider, TracerProviderBuilder> configure)
{
if (tracerProviderBuilder is IDeferredTracerProviderBuilder deferredTracerProviderBuilder)
{
deferredTracerProviderBuilder.Configure(configure);
}
return tracerProviderBuilder; return tracerProviderBuilder;
} }

View File

@ -16,24 +16,199 @@
#nullable enable #nullable enable
using System.Diagnostics;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry.Internal;
using OpenTelemetry.Resources;
namespace OpenTelemetry.Trace namespace OpenTelemetry.Trace
{ {
internal sealed class TracerProviderBuilderSdk : TracerProviderBuilderBase /// <summary>
/// Stores state used to build a <see cref="TracerProvider"/>.
/// </summary>
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 TracerProviderBuilderSdk(IServiceCollection services) public List<InstrumentationRegistration> Instrumentation { get; } = new();
: base(services)
public ResourceBuilder? ResourceBuilder { get; private set; }
public TracerProvider? Provider => this.tracerProvider;
public List<BaseProcessor<Activity>> Processors { get; } = new();
public List<string> Sources { get; } = new();
public HashSet<string> 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 TracerProviderBuilderSdk(TracerProviderBuilderState state) public override TracerProviderBuilder AddInstrumentation<TInstrumentation>(
: base(state) Func<TInstrumentation> 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<ResourceBuilder> 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<Activity> processor)
{
Debug.Assert(processor != null, "processor was null");
this.Processors.Add(processor!);
return this;
}
public TracerProviderBuilder SetSampler(Sampler sampler)
{
Debug.Assert(sampler != null, "sampler was null");
this.Sampler = sampler;
return this;
}
public TracerProviderBuilder SetErrorStatusOnException(bool enabled)
{
this.ExceptionProcessorEnabled = enabled;
return this;
}
public TracerProviderBuilder ConfigureBuilder(Action<IServiceProvider, TracerProviderBuilder> configure)
{
Debug.Assert(configure != null, "configure was null");
configure!(this.serviceProvider, this);
return this;
}
public TracerProviderBuilder ConfigureServices(Action<IServiceCollection> 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<IServiceProvider, TracerProviderBuilder> 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;
}
} }
} }
} }

View File

@ -1,76 +0,0 @@
// <copyright file="TracerProviderBuilderServiceCollectionExtensions.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
#nullable enable
using OpenTelemetry;
using OpenTelemetry.Internal;
using OpenTelemetry.Trace;
namespace Microsoft.Extensions.DependencyInjection;
/// <summary>
/// Extension methods for setting up OpenTelemetry tracing services in an <see cref="IServiceCollection" />.
/// </summary>
public static class TracerProviderBuilderServiceCollectionExtensions
{
/// <summary>
/// Configures OpenTelemetry tracing services in the supplied <see cref="IServiceCollection" />.
/// </summary>
/// <remarks>
/// Notes:
/// <list type="bullet">
/// <item>A <see cref="TracerProvider"/> will not be created automatically
/// using this method. Either use the
/// <c>IServiceCollection.AddOpenTelemetryTracing</c> extension in the
/// <c>OpenTelemetry.Extensions.Hosting</c> package or access the <see
/// cref="TracerProvider"/> through the application <see
/// cref="IServiceProvider"/> to begin collecting traces.</item>
/// <item>This is safe to be called multiple times and by library authors.
/// Only a single <see cref="TracerProvider"/> will be created for a given
/// <see cref="IServiceCollection"/>.</item>
/// </list>
/// </remarks>
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
/// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns>
public static IServiceCollection ConfigureOpenTelemetryTracing(this IServiceCollection services)
=> ConfigureOpenTelemetryTracing(services, (b) => { });
/// <summary>
/// Configures OpenTelemetry tracing services in the supplied <see cref="IServiceCollection" />.
/// </summary>
/// <remarks><inheritdoc cref="ConfigureOpenTelemetryTracing(IServiceCollection)" path="/remarks"/></remarks>
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
/// <param name="configure">Callback action to configure the <see cref="TracerProviderBuilder"/>.</param>
/// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns>
public static IServiceCollection ConfigureOpenTelemetryTracing(this IServiceCollection services, Action<TracerProviderBuilder> 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;
}
}

View File

@ -1,96 +0,0 @@
// <copyright file="TracerProviderBuilderState.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
#nullable enable
using System.Diagnostics;
using OpenTelemetry.Internal;
namespace OpenTelemetry.Trace
{
/// <summary>
/// Stores state used to build a <see cref="TracerProvider"/>.
/// </summary>
internal sealed class TracerProviderBuilderState : ProviderBuilderState<TracerProviderBuilderSdk, TracerProviderSdk>
{
private TracerProviderBuilderSdk? builder;
public TracerProviderBuilderState(IServiceProvider serviceProvider)
: base(serviceProvider)
{
}
public override TracerProviderBuilderSdk Builder
=> this.builder ??= new TracerProviderBuilderSdk(this);
public List<BaseProcessor<Activity>> Processors { get; } = new();
public List<string> Sources { get; } = new();
public HashSet<string> 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<Activity> 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);
}
}
}
}

View File

@ -21,8 +21,17 @@ using OpenTelemetry.Internal;
namespace OpenTelemetry.Trace namespace OpenTelemetry.Trace
{ {
/// <summary>
/// Contains extension methods for the <see cref="TracerProvider"/> class.
/// </summary>
public static class TracerProviderExtensions public static class TracerProviderExtensions
{ {
/// <summary>
/// Add a processor to the provider.
/// </summary>
/// <param name="provider"><see cref="TracerProvider"/>.</param>
/// <param name="processor"><see cref="BaseProcessor{T}"/>.</param>
/// <returns>The supplied <see cref="TracerProvider"/> instance for call chaining.</returns>
public static TracerProvider AddProcessor(this TracerProvider provider, BaseProcessor<Activity> processor) public static TracerProvider AddProcessor(this TracerProvider provider, BaseProcessor<Activity> processor)
{ {
Guard.ThrowIfNull(provider); Guard.ThrowIfNull(provider);

View File

@ -23,11 +23,6 @@ using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry.Internal; using OpenTelemetry.Internal;
using OpenTelemetry.Resources; using OpenTelemetry.Resources;
using CallbackHelper = OpenTelemetry.ProviderBuilderServiceCollectionCallbackHelper<
OpenTelemetry.Trace.TracerProviderBuilderSdk,
OpenTelemetry.Trace.TracerProviderSdk,
OpenTelemetry.Trace.TracerProviderBuilderState>;
namespace OpenTelemetry.Trace namespace OpenTelemetry.Trace
{ {
internal sealed class TracerProviderSdk : TracerProvider internal sealed class TracerProviderSdk : TracerProvider
@ -50,8 +45,8 @@ namespace OpenTelemetry.Trace
{ {
Debug.Assert(serviceProvider != null, "serviceProvider was null"); Debug.Assert(serviceProvider != null, "serviceProvider was null");
var state = serviceProvider!.GetRequiredService<TracerProviderBuilderState>(); var state = serviceProvider!.GetRequiredService<TracerProviderBuilderSdk>();
state.RegisterProvider(nameof(TracerProvider), this); state.RegisterProvider(this);
this.ServiceProvider = serviceProvider!; this.ServiceProvider = serviceProvider!;
@ -63,17 +58,16 @@ namespace OpenTelemetry.Trace
OpenTelemetrySdkEventSource.Log.TracerProviderSdkEvent("Building TracerProvider."); OpenTelemetrySdkEventSource.Log.TracerProviderSdkEvent("Building TracerProvider.");
CallbackHelper.InvokeRegisteredConfigureStateCallbacks( var configureProviderBuilders = serviceProvider!.GetServices<IConfigureTracerProviderBuilder>();
serviceProvider!, foreach (var configureProviderBuilder in configureProviderBuilders)
state); {
configureProviderBuilder.ConfigureBuilder(serviceProvider!, state);
}
StringBuilder processorsAdded = new StringBuilder(); StringBuilder processorsAdded = new StringBuilder();
StringBuilder instrumentationFactoriesAdded = new StringBuilder(); StringBuilder instrumentationFactoriesAdded = new StringBuilder();
if (state.SetErrorStatusOnException) state.AddExceptionProcessorIfEnabled();
{
state.EnableErrorStatusOnException();
}
var resourceBuilder = state.ResourceBuilder ?? ResourceBuilder.CreateDefault(); var resourceBuilder = state.ResourceBuilder ?? ResourceBuilder.CreateDefault();
resourceBuilder.ServiceProvider = serviceProvider; resourceBuilder.ServiceProvider = serviceProvider;

View File

@ -124,8 +124,8 @@ namespace OpenTelemetry.Exporter.Jaeger.Tests
services.AddHttpClient("JaegerExporter", configureClient: (client) => invocations++); services.AddHttpClient("JaegerExporter", configureClient: (client) => invocations++);
services.AddOpenTelemetryTracing(builder => builder.AddJaegerExporter( services.AddOpenTelemetry().WithTracing(builder => builder
o => o.Protocol = JaegerExportProtocol.HttpBinaryThrift)); .AddJaegerExporter(o => o.Protocol = JaegerExportProtocol.HttpBinaryThrift));
using var serviceProvider = services.BuildServiceProvider(); using var serviceProvider = services.BuildServiceProvider();

View File

@ -161,8 +161,8 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests
services.AddHttpClient("OtlpMetricExporter", configureClient: (client) => invocations++); services.AddHttpClient("OtlpMetricExporter", configureClient: (client) => invocations++);
services.AddOpenTelemetryMetrics(builder => builder.AddOtlpExporter( services.AddOpenTelemetry().WithMetrics(builder => builder
o => o.Protocol = OtlpExportProtocol.HttpProtobuf)); .AddOtlpExporter(o => o.Protocol = OtlpExportProtocol.HttpProtobuf));
using var serviceProvider = services.BuildServiceProvider(); using var serviceProvider = services.BuildServiceProvider();

View File

@ -136,8 +136,8 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests
services.AddHttpClient("OtlpTraceExporter", configureClient: (client) => invocations++); services.AddHttpClient("OtlpTraceExporter", configureClient: (client) => invocations++);
services.AddOpenTelemetryTracing(builder => builder.AddOtlpExporter( services.AddOpenTelemetry().WithTracing(builder => builder
o => o.Protocol = OtlpExportProtocol.HttpProtobuf)); .AddOtlpExporter(o => o.Protocol = OtlpExportProtocol.HttpProtobuf));
using var serviceProvider = services.BuildServiceProvider(); using var serviceProvider = services.BuildServiceProvider();

View File

@ -258,7 +258,7 @@ namespace OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests
{ {
if (registerMeterProvider) if (registerMeterProvider)
{ {
services.AddOpenTelemetryMetrics(builder => builder services.AddOpenTelemetry().WithMetrics(builder => builder
.AddMeter(MeterName) .AddMeter(MeterName)
.AddPrometheusExporter(o => .AddPrometheusExporter(o =>
{ {

View File

@ -283,7 +283,8 @@ namespace OpenTelemetry.Exporter.Zipkin.Tests
services.AddHttpClient("ZipkinExporter", configureClient: (client) => invocations++); services.AddHttpClient("ZipkinExporter", configureClient: (client) => invocations++);
services.AddOpenTelemetryTracing(builder => builder.AddZipkinExporter()); services.AddOpenTelemetry().WithTracing(builder => builder
.AddZipkinExporter());
using var serviceProvider = services.BuildServiceProvider(); using var serviceProvider = services.BuildServiceProvider();

View File

@ -0,0 +1,144 @@
// <copyright file="MeterProviderBuilderExtensionsTests.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using OpenTelemetry.Metrics;
using Xunit;
namespace OpenTelemetry.Extensions.DependencyInjection.Tests;
public class MeterProviderBuilderExtensionsTests
{
[Fact]
public void AddInstrumentationFromServiceProviderTest()
{
using var builder = new TestMeterProviderBuilder();
builder.AddInstrumentation<TestInstrumentation>();
var serviceProvider = builder.BuildServiceProvider();
var instrumentation = serviceProvider.GetRequiredService<TestInstrumentation>();
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<TestInstrumentation>());
var serviceProvider = builder.BuildServiceProvider();
serviceProvider.GetRequiredService<TestInstrumentation>();
}
[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
{
}
}

View File

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Unit test project for OpenTelemetry .NET dependency injection extensions</Description>
<!-- OmniSharp/VS Code requires TargetFrameworks to be in descending order for IntelliSense and analysis. -->
<TargetFrameworks>net7.0;net6.0</TargetFrameworks>
<TargetFrameworks Condition="$(OS) == 'Windows_NT'">$(TargetFrameworks);net462</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Extensions.DependencyInjection\OpenTelemetry.Extensions.DependencyInjection.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPkgVer)" />
<PackageReference Include="xunit" Version="$(XUnitPkgVer)" />
<PackageReference Include="xunit.runner.visualstudio" Version="$(XUnitRunnerVisualStudioPkgVer)">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="$(MicrosoftExtensionsDependencyInjectionAbstractionsPkgVer)" />
<DotNetCliToolReference Include="dotnet-xunit" Version="$(DotNetXUnitCliVer)" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,81 @@
// <copyright file="ServiceCollectionExtensionsTests.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
using Microsoft.Extensions.DependencyInjection;
using 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<IConfigureTracerProviderBuilder>();
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<IConfigureMeterProviderBuilder>();
foreach (var registration in registrations)
{
registration.ConfigureBuilder(serviceProvider, null!);
}
Assert.Equal(invocations, registrations.Count());
Assert.Equal(numberOfCalls, registrations.Count());
}
}

View File

@ -0,0 +1,140 @@
// <copyright file="TestMeterProviderBuilder.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
using Microsoft.Extensions.DependencyInjection;
using 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<string> Meters { get; } = new();
public List<object> Instrumentation { get; } = new();
public MeterProvider? Provider { get; private set; }
public override MeterProviderBuilder AddInstrumentation<TInstrumentation>(Func<TInstrumentation> 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<IServiceProvider, MeterProviderBuilder> 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<IServiceCollection> 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<IConfigureMeterProviderBuilder>();
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<IServiceProvider, MeterProviderBuilder> configure)
=> this.ConfigureBuilder(configure);
private sealed class NoopMeterProvider : MeterProvider
{
}
}

View File

@ -0,0 +1,156 @@
// <copyright file="TestTracerProviderBuilder.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
using Microsoft.Extensions.DependencyInjection;
using 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<string> Sources { get; } = new();
public List<string> LegacySources { get; } = new();
public List<object> Instrumentation { get; } = new();
public TracerProvider? Provider { get; private set; }
public override TracerProviderBuilder AddInstrumentation<TInstrumentation>(Func<TInstrumentation> 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<IServiceProvider, TracerProviderBuilder> 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<IServiceCollection> 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<IConfigureTracerProviderBuilder>();
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<IServiceProvider, TracerProviderBuilder> configure)
=> this.ConfigureBuilder(configure);
private sealed class NoopTracerProvider : TracerProvider
{
}
}

View File

@ -0,0 +1,144 @@
// <copyright file="TracerProviderBuilderExtensionsTests.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using OpenTelemetry.Trace;
using Xunit;
namespace OpenTelemetry.Extensions.DependencyInjection.Tests;
public class TracerProviderBuilderExtensionsTests
{
[Fact]
public void AddInstrumentationFromServiceProviderTest()
{
using var builder = new TestTracerProviderBuilder();
builder.AddInstrumentation<TestInstrumentation>();
var serviceProvider = builder.BuildServiceProvider();
var instrumentation = serviceProvider.GetRequiredService<TestInstrumentation>();
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<TestInstrumentation>());
var serviceProvider = builder.BuildServiceProvider();
serviceProvider.GetRequiredService<TestInstrumentation>();
}
[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
{
}
}

View File

@ -14,9 +14,7 @@
// limitations under the License. // limitations under the License.
// </copyright> // </copyright>
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -29,175 +27,41 @@ namespace OpenTelemetry.Extensions.Hosting.Tests
public class HostingMeterExtensionTests public class HostingMeterExtensionTests
{ {
[Fact] [Fact]
public async Task AddOpenTelemetryMeterProviderInstrumentationCreationAndDisposal() public async Task AddOpenTelemetry_StartWithHost_CreationAndDisposal()
{ {
var testInstrumentation = new TestInstrumentation();
var callbackRun = false; var callbackRun = false;
var builder = new HostBuilder().ConfigureServices(services => var builder = new HostBuilder().ConfigureServices(services =>
{ {
services.AddOpenTelemetryMetrics(builder => services.AddOpenTelemetry()
{ .WithMetrics(builder => builder
builder.AddInstrumentation(() => .AddInstrumentation(() =>
{ {
callbackRun = true; callbackRun = true;
return testInstrumentation; return new object();
}); }))
}); .StartWithHost();
}); });
var host = builder.Build(); var host = builder.Build();
Assert.False(callbackRun); Assert.False(callbackRun);
Assert.False(testInstrumentation.Disposed);
await host.StartAsync(); await host.StartAsync();
Assert.True(callbackRun); Assert.True(callbackRun);
Assert.False(testInstrumentation.Disposed);
await host.StopAsync(); await host.StopAsync();
Assert.True(callbackRun); Assert.True(callbackRun);
Assert.False(testInstrumentation.Disposed);
host.Dispose(); host.Dispose();
Assert.True(callbackRun); Assert.True(callbackRun);
Assert.True(testInstrumentation.Disposed);
} }
[Fact] [Fact]
public void AddOpenTelemetryMeterProvider_HostBuilt_OpenTelemetrySdk_RegisteredAsSingleton() public async Task AddOpenTelemetry_StartWithHost_HostConfigurationHonoredTest()
{
var builder = new HostBuilder().ConfigureServices(services =>
{
services.AddOpenTelemetryMetrics();
});
var host = builder.Build();
var meterProvider1 = host.Services.GetRequiredService<MeterProvider>();
var meterProvider2 = host.Services.GetRequiredService<MeterProvider>();
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<TestInstrumentation>()));
});
var serviceProvider = services.BuildServiceProvider();
var meterFactory = serviceProvider.GetRequiredService<MeterProvider>();
Assert.NotNull(meterFactory);
Assert.False(testInstrumentation.Disposed);
serviceProvider.Dispose();
Assert.True(testInstrumentation.Disposed);
}
[Fact]
public void AddOpenTelemetryMeterProvider_BadArgs_NullServiceCollection()
{
ServiceCollection services = null;
Assert.Throws<ArgumentNullException>(() => services.AddOpenTelemetryMetrics(null));
Assert.Throws<ArgumentNullException>(() =>
services.AddOpenTelemetryMetrics(builder =>
{
builder.ConfigureBuilder(
(sp, b) => b.AddInstrumentation(() => sp.GetRequiredService<TestInstrumentation>()));
}));
}
[Fact]
public void AddOpenTelemetryMeterProvider_GetServicesExtension()
{
var services = new ServiceCollection();
services.AddOpenTelemetryMetrics(builder => AddMyFeature(builder));
using var serviceProvider = services.BuildServiceProvider();
var meterProvider = (MeterProviderSdk)serviceProvider.GetRequiredService<MeterProvider>();
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<MeterProvider>();
Assert.Equal(2, configureCalls);
}
[Fact]
public void AddOpenTelemetryMeterProvider_ConfigureCallbacksUsingExtensions()
{
var services = new ServiceCollection();
services.AddSingleton<TestInstrumentation>();
services.AddSingleton<TestReader>();
services.AddOpenTelemetryMetrics(builder => builder
.ConfigureBuilder((sp1, builder1) =>
{
builder1
.AddInstrumentation<TestInstrumentation>()
.AddReader<TestReader>();
}));
using var serviceProvider = services.BuildServiceProvider();
var meterProvider = (MeterProviderSdk)serviceProvider.GetRequiredService<MeterProvider>();
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<MeterProvider>();
Assert.Single(providers);
}
[Fact]
public async Task AddOpenTelemetryMetrics_HostConfigurationHonoredTest()
{ {
bool configureBuilderCalled = false; bool configureBuilderCalled = false;
@ -211,19 +75,19 @@ namespace OpenTelemetry.Extensions.Hosting.Tests
}) })
.ConfigureServices(services => .ConfigureServices(services =>
{ {
services.AddOpenTelemetryMetrics(builder => services.AddOpenTelemetry()
{ .WithMetrics(builder => builder
builder.ConfigureBuilder((sp, builder) => .ConfigureBuilder((sp, builder) =>
{ {
configureBuilderCalled = true; configureBuilderCalled = true;
var configuration = sp.GetRequiredService<IConfiguration>(); var configuration = sp.GetRequiredService<IConfiguration>();
var testKeyValue = configuration.GetValue<string>("TEST_KEY", null); var testKeyValue = configuration.GetValue<string>("TEST_KEY", null);
Assert.Equal("TEST_KEY_VALUE", testKeyValue); Assert.Equal("TEST_KEY_VALUE", testKeyValue);
}); }))
}); .StartWithHost();
}); });
var host = builder.Build(); var host = builder.Build();
@ -238,26 +102,5 @@ namespace OpenTelemetry.Extensions.Hosting.Tests
host.Dispose(); host.Dispose();
} }
private static MeterProviderBuilder AddMyFeature(MeterProviderBuilder meterProviderBuilder)
{
meterProviderBuilder.ConfigureServices(services => services.AddSingleton<TestReader>());
return meterProviderBuilder.AddReader<TestReader>();
}
internal class TestInstrumentation : IDisposable
{
public bool Disposed { get; private set; }
public void Dispose()
{
this.Disposed = true;
}
}
internal class TestReader : MetricReader
{
}
} }
} }

View File

@ -14,10 +14,7 @@
// limitations under the License. // limitations under the License.
// </copyright> // </copyright>
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -30,178 +27,41 @@ namespace OpenTelemetry.Extensions.Hosting.Tests
public class HostingTracerExtensionTests public class HostingTracerExtensionTests
{ {
[Fact] [Fact]
public async Task AddOpenTelemetryTracerProviderInstrumentationCreationAndDisposal() public async Task AddOpenTelemetry_StartWithHost_CreationAndDisposal()
{ {
var testInstrumentation = new TestInstrumentation();
var callbackRun = false; var callbackRun = false;
var builder = new HostBuilder().ConfigureServices(services => var builder = new HostBuilder().ConfigureServices(services =>
{ {
services.AddOpenTelemetryTracing(builder => services.AddOpenTelemetry()
{ .WithTracing(builder => builder
builder.AddInstrumentation(() => .AddInstrumentation(() =>
{ {
callbackRun = true; callbackRun = true;
return testInstrumentation; return new object();
}); }))
}); .StartWithHost();
}); });
var host = builder.Build(); var host = builder.Build();
Assert.False(callbackRun); Assert.False(callbackRun);
Assert.False(testInstrumentation.Disposed);
await host.StartAsync(); await host.StartAsync();
Assert.True(callbackRun); Assert.True(callbackRun);
Assert.False(testInstrumentation.Disposed);
await host.StopAsync(); await host.StopAsync();
Assert.True(callbackRun); Assert.True(callbackRun);
Assert.False(testInstrumentation.Disposed);
host.Dispose(); host.Dispose();
Assert.True(callbackRun); Assert.True(callbackRun);
Assert.True(testInstrumentation.Disposed);
} }
[Fact] [Fact]
public void AddOpenTelemetryTracerProvider_HostBuilt_OpenTelemetrySdk_RegisteredAsSingleton() public async Task AddOpenTelemetry_StartWithHost_HostConfigurationHonoredTest()
{
var builder = new HostBuilder().ConfigureServices(services =>
{
services.AddOpenTelemetryTracing();
});
var host = builder.Build();
var tracerProvider1 = host.Services.GetRequiredService<TracerProvider>();
var tracerProvider2 = host.Services.GetRequiredService<TracerProvider>();
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<TestInstrumentation>()));
});
var serviceProvider = services.BuildServiceProvider();
var tracerFactory = serviceProvider.GetRequiredService<TracerProvider>();
Assert.NotNull(tracerFactory);
Assert.False(testInstrumentation.Disposed);
serviceProvider.Dispose();
Assert.True(testInstrumentation.Disposed);
}
[Fact]
public void AddOpenTelemetryTracerProvider_BadArgs_NullServiceCollection()
{
ServiceCollection services = null;
Assert.Throws<ArgumentNullException>(() => services.AddOpenTelemetryTracing(null));
Assert.Throws<ArgumentNullException>(() =>
services.AddOpenTelemetryTracing(builder =>
{
builder.ConfigureBuilder(
(sp, b) => b.AddInstrumentation(() => sp.GetRequiredService<TestInstrumentation>()));
}));
}
[Fact]
public void AddOpenTelemetryTracerProvider_GetServicesExtension()
{
var services = new ServiceCollection();
services.AddOpenTelemetryTracing(builder => AddMyFeature(builder));
using var serviceProvider = services.BuildServiceProvider();
var tracerProvider = (TracerProviderSdk)serviceProvider.GetRequiredService<TracerProvider>();
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<TracerProvider>();
Assert.Equal(2, configureCalls);
}
[Fact]
public void AddOpenTelemetryTracerProvider_ConfigureCallbacksUsingExtensions()
{
var services = new ServiceCollection();
services.AddSingleton<TestInstrumentation>();
services.AddSingleton<TestProcessor>();
services.AddSingleton<TestSampler>();
services.AddOpenTelemetryTracing(builder => builder
.ConfigureBuilder((sp1, builder1) =>
{
builder1
.AddInstrumentation<TestInstrumentation>()
.AddProcessor<TestProcessor>()
.SetSampler<TestSampler>();
}));
using var serviceProvider = services.BuildServiceProvider();
var tracerProvider = (TracerProviderSdk)serviceProvider.GetRequiredService<TracerProvider>();
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<TracerProvider>();
Assert.Single(providers);
}
[Fact]
public async Task AddOpenTelemetryTracing_HostConfigurationHonoredTest()
{ {
bool configureBuilderCalled = false; bool configureBuilderCalled = false;
@ -215,19 +75,19 @@ namespace OpenTelemetry.Extensions.Hosting.Tests
}) })
.ConfigureServices(services => .ConfigureServices(services =>
{ {
services.AddOpenTelemetryTracing(builder => services.AddOpenTelemetry()
{ .WithTracing(builder => builder
builder.ConfigureBuilder((sp, builder) => .ConfigureBuilder((sp, builder) =>
{ {
configureBuilderCalled = true; configureBuilderCalled = true;
var configuration = sp.GetRequiredService<IConfiguration>(); var configuration = sp.GetRequiredService<IConfiguration>();
var testKeyValue = configuration.GetValue<string>("TEST_KEY", null); var testKeyValue = configuration.GetValue<string>("TEST_KEY", null);
Assert.Equal("TEST_KEY_VALUE", testKeyValue); Assert.Equal("TEST_KEY_VALUE", testKeyValue);
}); }))
}); .StartWithHost();
}); });
var host = builder.Build(); var host = builder.Build();
@ -242,34 +102,5 @@ namespace OpenTelemetry.Extensions.Hosting.Tests
host.Dispose(); host.Dispose();
} }
private static TracerProviderBuilder AddMyFeature(TracerProviderBuilder tracerProviderBuilder)
{
tracerProviderBuilder.ConfigureServices(services => services.AddSingleton<TestSampler>());
return tracerProviderBuilder.SetSampler<TestSampler>();
}
internal class TestInstrumentation : IDisposable
{
public bool Disposed { get; private set; }
public void Dispose()
{
this.Disposed = true;
}
}
internal class TestProcessor : BaseProcessor<Activity>
{
}
internal class TestSampler : Sampler
{
public override SamplingResult ShouldSample(in SamplingParameters samplingParameters)
{
return new SamplingResult(SamplingDecision.RecordAndSample);
}
}
} }
} }

View File

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

View File

@ -655,9 +655,12 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Tests
builder.ConfigureTestServices((IServiceCollection services) => builder.ConfigureTestServices((IServiceCollection services) =>
{ {
services.AddSingleton<ActivityMiddleware.ActivityMiddlewareImpl>(new TestNullHostActivityMiddlewareImpl(activitySourceName, activityName)); services.AddSingleton<ActivityMiddleware.ActivityMiddlewareImpl>(new TestNullHostActivityMiddlewareImpl(activitySourceName, activityName));
services.AddOpenTelemetryTracing((builder) => builder.AddAspNetCoreInstrumentation() services.AddOpenTelemetry()
.AddSource(activitySourceName) .WithTracing(builder => builder
.AddInMemoryExporter(exportedItems)); .AddAspNetCoreInstrumentation()
.AddSource(activitySourceName)
.AddInMemoryExporter(exportedItems))
.StartWithHost();
}); });
builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders()); builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders());
}) })
@ -692,11 +695,11 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Tests
var exportedItems = new List<Activity>(); var exportedItems = new List<Activity>();
void ConfigureTestServices(IServiceCollection services) void ConfigureTestServices(IServiceCollection services)
{ {
services.AddOpenTelemetryTracing(options => services.AddOpenTelemetry()
{ .WithTracing(builder => builder
options.AddAspNetCoreInstrumentation() .AddAspNetCoreInstrumentation()
.AddInMemoryExporter(exportedItems); .AddInMemoryExporter(exportedItems))
}); .StartWithHost();
// Register ActivitySource here so that it will be used // Register ActivitySource here so that it will be used
// by ASP.NET Core to create activities // by ASP.NET Core to create activities

View File

@ -44,8 +44,10 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Tests
bool optionsPickedFromDI = false; bool optionsPickedFromDI = false;
void ConfigureTestServices(IServiceCollection services) void ConfigureTestServices(IServiceCollection services)
{ {
services.AddOpenTelemetryTracing( services.AddOpenTelemetry()
builder => builder.AddAspNetCoreInstrumentation(name, configureAspNetCoreInstrumentationOptions: null)); .WithTracing(builder => builder
.AddAspNetCoreInstrumentation(name, configureAspNetCoreInstrumentationOptions: null))
.StartWithHost();
services.Configure<AspNetCoreInstrumentationOptions>(name, options => services.Configure<AspNetCoreInstrumentationOptions>(name, options =>
{ {
@ -74,8 +76,10 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Tests
bool optionsPickedFromDI = false; bool optionsPickedFromDI = false;
void ConfigureTestServices(IServiceCollection services) void ConfigureTestServices(IServiceCollection services)
{ {
services.AddOpenTelemetryMetrics( services.AddOpenTelemetry()
builder => builder.AddAspNetCoreInstrumentation(name, configureAspNetCoreInstrumentationOptions: null)); .WithMetrics(builder => builder
.AddAspNetCoreInstrumentation(name, configureAspNetCoreInstrumentationOptions: null))
.StartWithHost();
services.Configure<AspNetCoreMetricsInstrumentationOptions>(name, options => services.Configure<AspNetCoreMetricsInstrumentationOptions>(name, options =>
{ {
@ -85,9 +89,9 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Tests
// Arrange // Arrange
using (var client = this.factory using (var client = this.factory
.WithWebHostBuilder(builder => .WithWebHostBuilder(builder =>
builder.ConfigureTestServices(ConfigureTestServices)) builder.ConfigureTestServices(ConfigureTestServices))
.CreateClient()) .CreateClient())
{ {
} }

View File

@ -64,8 +64,11 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Tests
builder.ConfigureTestServices((IServiceCollection services) => builder.ConfigureTestServices((IServiceCollection services) =>
{ {
services.AddSingleton<CallbackMiddleware.CallbackMiddlewareImpl>(new TestCallbackMiddlewareImpl(statusCode, reasonPhrase)); services.AddSingleton<CallbackMiddleware.CallbackMiddlewareImpl>(new TestCallbackMiddlewareImpl(statusCode, reasonPhrase));
services.AddOpenTelemetryTracing((builder) => builder.AddAspNetCoreInstrumentation(options => options.RecordException = recordException) services.AddOpenTelemetry()
.AddInMemoryExporter(exportedItems)); .WithTracing(builder => builder
.AddAspNetCoreInstrumentation(options => options.RecordException = recordException)
.AddInMemoryExporter(exportedItems))
.StartWithHost();
}); });
builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders()); builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders());
}) })

View File

@ -32,8 +32,6 @@ namespace OpenTelemetry.Metrics.Tests
{ {
var builder = Sdk.CreateMeterProviderBuilder(); var builder = Sdk.CreateMeterProviderBuilder();
builder.ConfigureServices(services => services.AddSingleton<MyInstrumentation>());
MyInstrumentation myInstrumentation = null; MyInstrumentation myInstrumentation = null;
RunBuilderServiceLifecycleTest( RunBuilderServiceLifecycleTest(
@ -71,7 +69,7 @@ namespace OpenTelemetry.Metrics.Tests
ServiceProvider serviceProvider = null; ServiceProvider serviceProvider = null;
MeterProviderSdk provider = null; MeterProviderSdk provider = null;
services.ConfigureOpenTelemetryMetrics(builder => services.AddOpenTelemetry().WithMetrics(builder =>
{ {
testRun = true; testRun = true;
@ -111,12 +109,12 @@ namespace OpenTelemetry.Metrics.Tests
{ {
var services = new ServiceCollection(); var services = new ServiceCollection();
services.ConfigureOpenTelemetryMetrics(builder => services.AddOpenTelemetry().WithMetrics(builder =>
{ {
builder.AddInstrumentation<MyInstrumentation>(() => new()); builder.AddInstrumentation<MyInstrumentation>(() => new());
}); });
services.ConfigureOpenTelemetryMetrics(builder => services.AddOpenTelemetry().WithMetrics(builder =>
{ {
builder.AddInstrumentation<MyInstrumentation>(() => new()); builder.AddInstrumentation<MyInstrumentation>(() => new());
}); });
@ -273,7 +271,7 @@ namespace OpenTelemetry.Metrics.Tests
{ {
if (callNestedConfigure) if (callNestedConfigure)
{ {
services.ConfigureOpenTelemetryMetrics(); services.AddOpenTelemetry().WithMetrics(builder => { });
} }
}) })
.ConfigureBuilder((sp, builder) => .ConfigureBuilder((sp, builder) =>
@ -293,9 +291,9 @@ namespace OpenTelemetry.Metrics.Tests
{ {
bool innerTestExecuted = false; bool innerTestExecuted = false;
var serviceCollection = new ServiceCollection(); var services = new ServiceCollection();
serviceCollection.ConfigureOpenTelemetryMetrics(builder => services.AddOpenTelemetry().WithMetrics(builder =>
{ {
builder.ConfigureBuilder((sp, builder) => builder.ConfigureBuilder((sp, builder) =>
{ {
@ -304,7 +302,7 @@ namespace OpenTelemetry.Metrics.Tests
}); });
}); });
using var serviceProvider = serviceCollection.BuildServiceProvider(); using var serviceProvider = services.BuildServiceProvider();
var resolvedProvider = serviceProvider.GetRequiredService<MeterProvider>(); var resolvedProvider = serviceProvider.GetRequiredService<MeterProvider>();
@ -317,7 +315,6 @@ namespace OpenTelemetry.Metrics.Tests
Action<MeterProviderSdk> postAction) Action<MeterProviderSdk> postAction)
{ {
var baseBuilder = builder as MeterProviderBuilderBase; var baseBuilder = builder as MeterProviderBuilderBase;
Assert.Null(baseBuilder.State);
builder.AddMeter("TestSource"); builder.AddMeter("TestSource");
@ -328,12 +325,15 @@ namespace OpenTelemetry.Metrics.Tests
Assert.NotNull(services); Assert.NotNull(services);
services.TryAddSingleton<MyInstrumentation>();
services.TryAddSingleton<MyReader>(); services.TryAddSingleton<MyReader>();
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 Assert.Throws<NotSupportedException>(() => b.ConfigureServices(services => { }));
b.AddInstrumentation<MyInstrumentation>();
b.AddInstrumentation(sp.GetRequiredService<MyInstrumentation>());
}); });
}); });
@ -342,13 +342,13 @@ namespace OpenTelemetry.Metrics.Tests
{ {
configureBuilderInvocations++; configureBuilderInvocations++;
var baseBuilder = builder as MeterProviderBuilderBase; var sdkBuilder = builder as MeterProviderBuilderSdk;
Assert.NotNull(baseBuilder?.State); Assert.NotNull(sdkBuilder);
builder.AddMeter("TestSource2"); builder.AddMeter("TestSource2");
Assert.Contains(baseBuilder.State.MeterSources, s => s == "TestSource"); Assert.Contains(sdkBuilder.MeterSources, s => s == "TestSource");
Assert.Contains(baseBuilder.State.MeterSources, s => s == "TestSource2"); Assert.Contains(sdkBuilder.MeterSources, s => s == "TestSource2");
// Note: Services can't be configured at this stage // Note: Services can't be configured at this stage
Assert.Throws<NotSupportedException>( Assert.Throws<NotSupportedException>(

View File

@ -1356,26 +1356,26 @@ namespace OpenTelemetry.Metrics.Tests
// for no tag point! // for no tag point!
// This may be changed later. // This may be changed later.
counterLong.Add(10); 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<string, object>("key", "value" + i)); counterLong.Add(10, new KeyValuePair<string, object>("key", "value" + i));
} }
meterProvider.ForceFlush(MaxTimeToAllowForFlush); meterProvider.ForceFlush(MaxTimeToAllowForFlush);
Assert.Equal(MeterProviderBuilderState.MaxMetricPointsPerMetricDefault, MetricPointCount()); Assert.Equal(MeterProviderBuilderSdk.MaxMetricPointsPerMetricDefault, MetricPointCount());
exportedItems.Clear(); exportedItems.Clear();
counterLong.Add(10); 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<string, object>("key", "value" + i)); counterLong.Add(10, new KeyValuePair<string, object>("key", "value" + i));
} }
meterProvider.ForceFlush(MaxTimeToAllowForFlush); meterProvider.ForceFlush(MaxTimeToAllowForFlush);
Assert.Equal(MeterProviderBuilderState.MaxMetricPointsPerMetricDefault, MetricPointCount()); Assert.Equal(MeterProviderBuilderSdk.MaxMetricPointsPerMetricDefault, MetricPointCount());
counterLong.Add(10); 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<string, object>("key", "value" + i)); counterLong.Add(10, new KeyValuePair<string, object>("key", "value" + i));
} }
@ -1386,7 +1386,7 @@ namespace OpenTelemetry.Metrics.Tests
counterLong.Add(10, new KeyValuePair<string, object>("key", "valueC")); counterLong.Add(10, new KeyValuePair<string, object>("key", "valueC"));
exportedItems.Clear(); exportedItems.Clear();
meterProvider.ForceFlush(MaxTimeToAllowForFlush); meterProvider.ForceFlush(MaxTimeToAllowForFlush);
Assert.Equal(MeterProviderBuilderState.MaxMetricPointsPerMetricDefault, MetricPointCount()); Assert.Equal(MeterProviderBuilderSdk.MaxMetricPointsPerMetricDefault, MetricPointCount());
} }
[Fact] [Fact]

View File

@ -118,8 +118,6 @@ namespace OpenTelemetry.Trace.Tests
{ {
var builder = Sdk.CreateTracerProviderBuilder(); var builder = Sdk.CreateTracerProviderBuilder();
builder.ConfigureServices(services => services.AddSingleton<MyInstrumentation>());
MyInstrumentation myInstrumentation = null; MyInstrumentation myInstrumentation = null;
RunBuilderServiceLifecycleTest( RunBuilderServiceLifecycleTest(
@ -157,7 +155,7 @@ namespace OpenTelemetry.Trace.Tests
ServiceProvider serviceProvider = null; ServiceProvider serviceProvider = null;
TracerProviderSdk provider = null; TracerProviderSdk provider = null;
services.ConfigureOpenTelemetryTracing(builder => services.AddOpenTelemetry().WithTracing(builder =>
{ {
testRun = true; testRun = true;
@ -197,12 +195,12 @@ namespace OpenTelemetry.Trace.Tests
{ {
var services = new ServiceCollection(); var services = new ServiceCollection();
services.ConfigureOpenTelemetryTracing(builder => services.AddOpenTelemetry().WithTracing(builder =>
{ {
builder.AddInstrumentation<MyInstrumentation>(() => new()); builder.AddInstrumentation<MyInstrumentation>(() => new());
}); });
services.ConfigureOpenTelemetryTracing(builder => services.AddOpenTelemetry().WithTracing(builder =>
{ {
builder.AddInstrumentation<MyInstrumentation>(() => new()); builder.AddInstrumentation<MyInstrumentation>(() => new());
}); });
@ -359,7 +357,7 @@ namespace OpenTelemetry.Trace.Tests
{ {
if (callNestedConfigure) if (callNestedConfigure)
{ {
services.ConfigureOpenTelemetryTracing(); services.AddOpenTelemetry().WithTracing(builder => { });
} }
}) })
.ConfigureBuilder((sp, builder) => .ConfigureBuilder((sp, builder) =>
@ -379,9 +377,9 @@ namespace OpenTelemetry.Trace.Tests
{ {
bool innerTestExecuted = false; bool innerTestExecuted = false;
var serviceCollection = new ServiceCollection(); var services = new ServiceCollection();
serviceCollection.ConfigureOpenTelemetryTracing(builder => services.AddOpenTelemetry().WithTracing(builder =>
{ {
builder.ConfigureBuilder((sp, builder) => builder.ConfigureBuilder((sp, builder) =>
{ {
@ -390,7 +388,7 @@ namespace OpenTelemetry.Trace.Tests
}); });
}); });
using var serviceProvider = serviceCollection.BuildServiceProvider(); using var serviceProvider = services.BuildServiceProvider();
var resolvedProvider = serviceProvider.GetRequiredService<TracerProvider>(); var resolvedProvider = serviceProvider.GetRequiredService<TracerProvider>();
@ -403,7 +401,6 @@ namespace OpenTelemetry.Trace.Tests
Action<TracerProviderSdk> postAction) Action<TracerProviderSdk> postAction)
{ {
var baseBuilder = builder as TracerProviderBuilderBase; var baseBuilder = builder as TracerProviderBuilderBase;
Assert.Null(baseBuilder.State);
builder builder
.AddSource("TestSource") .AddSource("TestSource")
@ -417,12 +414,15 @@ namespace OpenTelemetry.Trace.Tests
Assert.NotNull(services); Assert.NotNull(services);
services.TryAddSingleton<MyInstrumentation>();
services.TryAddSingleton<MyProcessor>(); services.TryAddSingleton<MyProcessor>();
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 Assert.Throws<NotSupportedException>(() => b.ConfigureServices(services => { }));
b.AddInstrumentation<MyInstrumentation>();
b.AddInstrumentation(sp.GetRequiredService<MyInstrumentation>());
}); });
}); });
@ -431,17 +431,17 @@ namespace OpenTelemetry.Trace.Tests
{ {
configureBuilderInvocations++; configureBuilderInvocations++;
var baseBuilder = builder as TracerProviderBuilderBase; var sdkBuilder = builder as TracerProviderBuilderSdk;
Assert.NotNull(baseBuilder?.State); Assert.NotNull(sdkBuilder);
builder builder
.AddSource("TestSource2") .AddSource("TestSource2")
.AddLegacySource("TestLegacySource2"); .AddLegacySource("TestLegacySource2");
Assert.Contains(baseBuilder.State.Sources, s => s == "TestSource"); Assert.Contains(sdkBuilder.Sources, s => s == "TestSource");
Assert.Contains(baseBuilder.State.Sources, s => s == "TestSource2"); Assert.Contains(sdkBuilder.Sources, s => s == "TestSource2");
Assert.Contains(baseBuilder.State.LegacyActivityOperationNames, s => s == "TestLegacySource"); Assert.Contains(sdkBuilder.LegacyActivityOperationNames, s => s == "TestLegacySource");
Assert.Contains(baseBuilder.State.LegacyActivityOperationNames, s => s == "TestLegacySource2"); Assert.Contains(sdkBuilder.LegacyActivityOperationNames, s => s == "TestLegacySource2");
// Note: Services can't be configured at this stage // Note: Services can't be configured at this stage
Assert.Throws<NotSupportedException>( Assert.Throws<NotSupportedException>(