674 lines
28 KiB
Markdown
674 lines
28 KiB
Markdown
# Customizing OpenTelemetry .NET SDK for Tracing
|
|
|
|
## TracerProvider
|
|
|
|
As shown in the [getting-started](../getting-started/README.md) doc, a valid
|
|
[`TracerProvider`](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#tracer-provider)
|
|
must be configured and built to collect traces with OpenTelemetry .NET Sdk.
|
|
`TracerProvider` holds all the configuration for tracing like samplers,
|
|
processors, etc. Naturally, almost all the customizations must be done on the
|
|
`TracerProvider`.
|
|
|
|
## Building a TracerProvider
|
|
|
|
Building a `TracerProvider` is done using `TracerProviderBuilder` which must be
|
|
obtained by calling `Sdk.CreateTracerProviderBuilder()`. `TracerProviderBuilder`
|
|
exposes various methods which configures the provider it is going to build.
|
|
These includes methods like `SetSampler`, `AddProcessor` etc, and are explained
|
|
in subsequent sections of this document. Once configuration is done, calling
|
|
`Build()` on the `TracerProviderBuilder` builds the `TracerProvider` instance.
|
|
Once built, changes to its configuration is not allowed, with the exception of
|
|
adding more processors. In most cases, a single `TracerProvider` is created at
|
|
the application startup, and is disposed when application shuts down.
|
|
|
|
The snippet below shows how to build a basic `TracerProvider` and dispose it at
|
|
the end of the application. This will create a provider with default
|
|
configuration, and is not particularly useful. The subsequent sections shows how
|
|
to build a more useful provider.
|
|
|
|
```csharp
|
|
using OpenTelemetry;
|
|
using OpenTelemetry.Trace;
|
|
|
|
var tracerProvider = Sdk.CreateTracerProviderBuilder().Build();
|
|
// ....
|
|
|
|
// Dispose at application shutdown
|
|
tracerProvider.Dispose()
|
|
```
|
|
|
|
**Note:** The `Sdk.CreateTracerProviderBuilder()` API is available for all
|
|
runtimes. Additionally, for `ASP.NET Core` and [.NET Generic
|
|
Host](https://learn.microsoft.com/dotnet/core/extensions/generic-host) users,
|
|
helper extensions are provided in the
|
|
[OpenTelemetry.Extensions.Hosting](../../../src/OpenTelemetry.Extensions.Hosting/README.md)
|
|
package to simplify configuration and management of the `TracerProvider`.
|
|
|
|
In a typical application, a single `TracerProvider` is created at application
|
|
startup and disposed at application shutdown. It is important to ensure that the
|
|
provider is not disposed too early. Actual mechanism depends on the application
|
|
type. For example, in a typical ASP.NET application, `TracerProvider` is created
|
|
in `Application_Start`, and disposed in `Application_End` (both methods are a
|
|
part of the Global.asax.cs file) as shown
|
|
[here](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/blob/main/examples/AspNet/Global.asax.cs).
|
|
In a typical ASP.NET Core application, `TracerProvider` lifetime is managed by
|
|
leveraging the built-in Dependency Injection container as shown
|
|
[here](../../../examples/AspNetCore/Program.cs).
|
|
|
|
## TracerProvider configuration
|
|
|
|
`TracerProvider` holds the tracing configuration, which includes the following:
|
|
|
|
1. The list of `ActivitySource`s (aka `Tracer`s) from which traces are collected.
|
|
2. The list of instrumentations enabled via
|
|
[InstrumentationLibrary](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/glossary.md#instrumentation-library).
|
|
3. The list of
|
|
[Processors](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#span-processor),
|
|
including exporting processors which exports traces to
|
|
[Exporters](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#span-exporter)
|
|
4. The
|
|
[Resource](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/sdk.md)
|
|
associated with the traces.
|
|
5. The
|
|
[Sampler](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#sampler)
|
|
to be used.
|
|
|
|
### Activity Source
|
|
|
|
`ActivitySource` denotes a
|
|
[`Tracer`](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#tracer),
|
|
which is used to create activities. The SDK follows an explicit opt-in model for
|
|
listening to activity sources. i.e, by default, it listens to no sources. Every
|
|
activity source which produce telemetry must be explicitly added to the tracer
|
|
provider to start collecting traces from them.
|
|
|
|
`AddSource` method on `TracerProviderBuilder` can be used to add a
|
|
`ActivitySource` to the provider. The name of the `ActivitySource`
|
|
(case-insensitive) must be the argument to this method. Multiple `AddSource` can
|
|
be called to add more than one source. It also supports wildcard subscription
|
|
model as well.
|
|
|
|
It is not possible to add sources *after* the provider is built, by calling the
|
|
`Build()` method on the `TracerProviderBuilder`.
|
|
|
|
The snippet below shows how to add activity sources to the provider.
|
|
|
|
```csharp
|
|
using OpenTelemetry;
|
|
using OpenTelemetry.Trace;
|
|
|
|
var tracerProvider = Sdk.CreateTracerProviderBuilder()
|
|
// The following subscribes to activities from Activity Source
|
|
// named "MyCompany.MyProduct.MyLibrary" only.
|
|
.AddSource("MyCompany.MyProduct.MyLibrary")
|
|
// The following subscribes to activities from all Activity Sources
|
|
// whose name starts with "AbcCompany.XyzProduct.".
|
|
.AddSource("AbcCompany.XyzProduct.*")
|
|
.Build();
|
|
```
|
|
|
|
See [Program.cs](./Program.cs) for complete example.
|
|
|
|
**Note:** A common mistake while configuring `TracerProvider` is forgetting to
|
|
add all `ActivitySources` to the provider. It is recommended to leverage the
|
|
wild card subscription model where it makes sense. For example, if your
|
|
application is expecting to enable tracing from a number of libraries from a
|
|
company "Abc", the you can use `AddSource("Abc.*")` to enable all sources whose
|
|
name starts with "Abc.".
|
|
|
|
### Instrumentation
|
|
|
|
While the OpenTelemetry API can be used to instrument any library manually,
|
|
[Instrumentation
|
|
Libraries](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/overview.md#instrumentation-libraries)
|
|
are available for a lot of commonly used libraries. Such instrumentations can be
|
|
added to the `TracerProvider`. It is not required to attach the instrumentation
|
|
to the provider, unless the life cycle of the instrumentation must be managed by
|
|
the provider. If the instrumentation must be activated/shutdown/disposed along
|
|
with the provider, then the instrumentation must be added to the provider.
|
|
|
|
Typically, the instrumentation libraries provide extension methods on
|
|
`TracerProviderBuilder` to allow adding them to the `TracerProvider`. Please
|
|
refer to corresponding documentation of the instrumentation library to know the
|
|
exact method name.
|
|
|
|
Follow [this](../extending-the-sdk/README.md#instrumentation-library) document
|
|
to learn about the instrumentation libraries shipped from this repo and writing
|
|
custom instrumentation libraries.
|
|
|
|
### Processors & Exporters
|
|
|
|
[Processors](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#span-processor)
|
|
expose hooks for start and end processing of `Activity` instances. If no
|
|
processors are configured then traces are simply dropped by the SDK. The
|
|
`AddProcessor` method on `TracerProviderBuilder` is provided to add a processor
|
|
to the SDK pipeline. There can be any number of processors added to the provider
|
|
and they are invoked in the same order as they are added. Unlike `Sampler` and
|
|
`Resource`, processors can be added to the provider even *after* it is built.
|
|
|
|
[Exporters](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#span-exporter)
|
|
expose hooks for exporting batches of completed `Activity` instances (a batch
|
|
may contain a single or many records) and are called by processors. Two base
|
|
processor classes `SimpleExportProcessor` & `BatchExportProcessor` are provided
|
|
to support invoking exporters through the processor pipeline and implement the
|
|
standard behaviors prescribed by the OpenTelemetry specification.
|
|
|
|
**Note:** The SDK only ever invokes processors and has no direct knowledge of
|
|
any registered exporters.
|
|
|
|
#### Processor Configuration
|
|
|
|
The snippet below shows how to add processors to the provider before and after
|
|
it is built.
|
|
|
|
```csharp
|
|
using OpenTelemetry;
|
|
using OpenTelemetry.Trace;
|
|
|
|
var tracerProvider = Sdk.CreateTracerProviderBuilder()
|
|
.AddProcessor(new MyProcessor1())
|
|
.AddProcessor(new MyProcessor2()))
|
|
.Build();
|
|
|
|
// Processors can be added to provider even after it is built.
|
|
// Only those traces which are emitted after this line, will be sent to it.
|
|
tracerProvider.AddProcessor(new MyProcessor3());
|
|
```
|
|
|
|
**Note:** A `TracerProvider` assumes ownership of **all** processors added to
|
|
it. This means that the provider will call the `Shutdown` method on all
|
|
registered processors when it is shutting down and call the `Dispose` method on
|
|
all registered processors when it is disposed. If multiple providers are being
|
|
set up in an application then separate instances of processors **MUST** be
|
|
registered on each provider. Otherwise shutting down one provider will cause the
|
|
shared processor(s) in other providers to be shut down as well which may lead to
|
|
undesired results.
|
|
|
|
Processors can be used for enriching. exporting, and/or filtering telemetry.
|
|
|
|
To enrich telemetry, users may write custom processors overriding the `OnStart`
|
|
and/or `OnEnd` methods (as needed) to implement custom logic to change the data
|
|
before it is passed to the next processor in the pipeline.
|
|
|
|
For exporting purposes, the SDK provides the following built-in processors:
|
|
|
|
* [BatchExportProcessor<T>](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#batching-processor)
|
|
: This is an exporting processor which batches the telemetry before sending to
|
|
the configured exporter.
|
|
|
|
The following environment variables can be used to override the default
|
|
values of the `BatchExportActivityProcessorOptions`.
|
|
|
|
| Environment variable | `BatchExportActivityProcessorOptions` property |
|
|
| -------------------------------- | ---------------------------------------------- |
|
|
| `OTEL_BSP_SCHEDULE_DELAY` | `ScheduledDelayMilliseconds` |
|
|
| `OTEL_BSP_EXPORT_TIMEOUT` | `ExporterTimeoutMilliseconds` |
|
|
| `OTEL_BSP_MAX_QUEUE_SIZE` | `MaxQueueSize` |
|
|
| `OTEL_BSP_MAX_EXPORT_BATCH_SIZE` | `MaxExportBatchSizeEnvVarKey` |
|
|
|
|
`FormatException` is thrown in case of an invalid value for any of the
|
|
supported environment variables.
|
|
|
|
* [SimpleExportProcessor<T>](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#simple-processor)
|
|
: This is an exporting processor which passes telemetry to the configured
|
|
exporter immediately without any batching.
|
|
|
|
**Note:** A special processor
|
|
[CompositeProcessor<T>](../../../src/OpenTelemetry/CompositeProcessor.cs)
|
|
is used by the SDK to chain multiple processors together and may be used as
|
|
needed by users to define sub-pipelines.
|
|
|
|
**Note:** The processors shipped from this SDK are generic implementations and
|
|
support tracing and logging by implementing `Activity` and `LogRecord`
|
|
respectively.
|
|
|
|
Follow [this](../extending-the-sdk/README.md#processor) document to learn about
|
|
writing custom processors.
|
|
|
|
#### Exporter Configuration
|
|
|
|
The snippet below shows how to add export processors to the provider before it
|
|
is built.
|
|
|
|
```csharp
|
|
using OpenTelemetry;
|
|
using OpenTelemetry.Trace;
|
|
|
|
var tracerProvider = Sdk.CreateTracerProviderBuilder()
|
|
.AddProcessor(new BatchActivityExportProcessor(new MyExporter1()))
|
|
.AddProcessor(new SimpleActivityExportProcessor(new MyExporter2()))
|
|
.Build();
|
|
```
|
|
|
|
To make exporter registration easier an `AddExporter` extension is also provided
|
|
(as of 1.4.0). The snippet below shows how to add an export processor using
|
|
`AddExporter` to the provider before it is built.
|
|
|
|
```csharp
|
|
using OpenTelemetry;
|
|
using OpenTelemetry.Trace;
|
|
|
|
var tracerProvider = Sdk.CreateTracerProviderBuilder()
|
|
.AddExporter<MyExporter>(ExportProcessorType.Batch)
|
|
.Build();
|
|
```
|
|
|
|
It is also common for exporters to provide their own extensions to simplify
|
|
registration. The snippet below shows how to add the
|
|
[JaegerExporter](../../../src/OpenTelemetry.Exporter.Jaeger/README.md) to the
|
|
provider before it is built.
|
|
|
|
```csharp
|
|
using OpenTelemetry;
|
|
using OpenTelemetry.Trace;
|
|
|
|
var tracerProvider = Sdk.CreateTracerProviderBuilder()
|
|
.AddJaegerExporter()
|
|
.Build();
|
|
```
|
|
|
|
Follow [this](../extending-the-sdk/README.md#exporter) document to learn about
|
|
writing custom exporters.
|
|
|
|
### Resource
|
|
|
|
[Resource](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/sdk.md)
|
|
is the immutable representation of the entity producing the telemetry. If no
|
|
`Resource` is explicitly configured, the
|
|
[default](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/README.md#semantic-attributes-with-sdk-provided-default-value)
|
|
resource is used to indicate the
|
|
[Service](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/README.md#service).
|
|
The `ConfigureResource` method on `TracerProviderBuilder` can be used to
|
|
configure the resource on the provider. `ConfigureResource` accepts an `Action`
|
|
to configure the `ResourceBuilder`. Multiple calls to `ConfigureResource` can be
|
|
made. When the provider is built, it builds the final `Resource` combining all
|
|
the `ConfigureResource` calls. There can only be a single `Resource` associated
|
|
with a provider. It is not possible to change the resource builder *after* the
|
|
provider is built, by calling the `Build()` method on the
|
|
`TracerProviderBuilder`.
|
|
|
|
`ResourceBuilder` offers various methods to construct resource comprising of
|
|
multiple attributes from various sources. Examples include `AddTelemetrySdk()`
|
|
which adds [Telemetry
|
|
Sdk](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/README.md#telemetry-sdk)
|
|
resource, and `AddService()` which adds
|
|
[Service](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/README.md#service)
|
|
resource. It also allows adding `ResourceDetector`s.
|
|
|
|
Follow [this](../extending-the-sdk/README.md#resource-detector) document
|
|
to learn about writing custom resource detectors.
|
|
|
|
The snippet below shows configuring the `Resource` associated with the provider.
|
|
|
|
```csharp
|
|
using OpenTelemetry;
|
|
using OpenTelemetry.Resources;
|
|
using OpenTelemetry.Trace;
|
|
|
|
var tracerProvider = Sdk.CreateTracerProviderBuilder()
|
|
.ConfigureResource(resourceBuilder => resourceBuilder.AddTelemetrySdk())
|
|
.ConfigureResource(resourceBuilder => resourceBuilder.AddService("service-name"))
|
|
.Build();
|
|
```
|
|
|
|
It is also possible to configure the `Resource` by using following
|
|
environmental variables:
|
|
|
|
| Environment variable | Description |
|
|
| -------------------------- | -------------------------------------------------- |
|
|
| `OTEL_RESOURCE_ATTRIBUTES` | Key-value pairs to be used as resource attributes. See the [Resource SDK specification](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.5.0/specification/resource/sdk.md#specifying-resource-information-via-an-environment-variable) for more details. |
|
|
| `OTEL_SERVICE_NAME` | Sets the value of the `service.name` resource attribute. If `service.name` is also provided in `OTEL_RESOURCE_ATTRIBUTES`, then `OTEL_SERVICE_NAME` takes precedence. |
|
|
|
|
### Samplers
|
|
|
|
[Samplers](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#sampler)
|
|
are used to control the noise and overhead introduced by OpenTelemetry by
|
|
reducing the number of samples of traces collected and sent to the processors.
|
|
If no sampler is explicitly configured, the default is to use
|
|
`ParentBased(root=AlwaysOn)`. `SetSampler` method on `TracerProviderBuilder` can
|
|
be used to set sampler. Only one sampler can be associated with a provider. If
|
|
multiple `SetSampler` is called, the last one wins. Also, it is not possible to
|
|
change the sampler *after* the provider is built, by calling the `Build()`
|
|
method on the `TracerProviderBuilder`.
|
|
|
|
The snippet below shows configuring a custom sampler to the provider.
|
|
|
|
```csharp
|
|
using OpenTelemetry;
|
|
using OpenTelemetry.Trace;
|
|
|
|
var tracerProvider = Sdk.CreateTracerProviderBuilder()
|
|
.SetSampler(new TraceIdRatioBasedSampler(0.25))
|
|
.Build();
|
|
```
|
|
|
|
Follow [this](../extending-the-sdk/README.md#sampler) document
|
|
to learn about writing custom samplers.
|
|
|
|
## Context Propagation
|
|
|
|
The OpenTelemetry API exposes a method to obtain the default propagator which is
|
|
no-op, by default. This SDK replaces the no-op with a [composite
|
|
propagator](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/context/api-propagators.md#composite-propagator)
|
|
containing the Baggage Propagator and TraceContext propagator. This default
|
|
propagator can be overridden with the below snippet.
|
|
|
|
```csharp
|
|
using OpenTelemetry;
|
|
|
|
Sdk.SetDefaultTextMapPropagator(new MyCustomPropagator());
|
|
```
|
|
|
|
## Dependency injection support
|
|
|
|
**Note:** This information applies to the OpenTelemetry SDK version 1.4.0 and
|
|
newer only.
|
|
|
|
The SDK implementation of `TracerProviderBuilder` is backed by an
|
|
`IServiceCollection` and supports a wide range of APIs to enable what is
|
|
generally known as [dependency
|
|
injection](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection).
|
|
|
|
### Dependency injection examples
|
|
|
|
For the below examples imagine an exporter with this constructor:
|
|
|
|
```csharp
|
|
public class MyCustomExporter : BaseExporter<Activity>
|
|
{
|
|
public MyCustomExporter(MyCustomService myCustomService)
|
|
{
|
|
// Implementation not important
|
|
}
|
|
}
|
|
```
|
|
|
|
We want to inject `MyCustomService` dependency into our `MyCustomExporter`
|
|
instance.
|
|
|
|
#### Using Sdk.CreateTracerProviderBuilder()
|
|
|
|
To register `MyCustomExporter` and `MyCustomService` we can use the
|
|
`ConfigureServices` and `AddExporter` methods:
|
|
|
|
```csharp
|
|
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
|
|
.ConfigureServices(services =>
|
|
{
|
|
services.AddSingleton<MyCustomService>();
|
|
})
|
|
.AddExporter<MyCustomExporter>(ExportProcessorType.Batch)
|
|
.Build();
|
|
```
|
|
|
|
When using the `Sdk.CreateTracerProviderBuilder` method the `TracerProvider`
|
|
owns its own `IServiceCollection`. It will only be able to see services
|
|
registered into that collection.
|
|
|
|
**Note:** It is important to correctly manage the lifecycle of the
|
|
`TracerProvider`. See [Building a TracerProvider](#building-a-tracerprovider)
|
|
for details.
|
|
|
|
#### Using the OpenTelemetry.Extensions.Hosting package
|
|
|
|
**Note:** If you are authoring an ASP.NET Core application or using the [.NET
|
|
Generic Host](https://learn.microsoft.com/dotnet/core/extensions/generic-host)
|
|
the
|
|
[OpenTelemetry.Extensions.Hosting](../../../src/OpenTelemetry.Extensions.Hosting/README.md)
|
|
package is the recommended mechanism.
|
|
|
|
```csharp
|
|
var appBuilder = WebApplication.CreateBuilder(args);
|
|
|
|
appBuilder.Services.AddSingleton<MyCustomService>();
|
|
|
|
appBuilder.Services.AddOpenTelemetryTracing(builder => builder
|
|
.AddExporter<MyCustomExporter>(ExportProcessorType.Batch));
|
|
```
|
|
|
|
When using the `AddOpenTelemetryTracing` method the `TracerProvider` does not
|
|
own its `IServiceCollection` and instead registers into an existing collection
|
|
(typically the collection used is the one managed by the application host). The
|
|
`TracerProviderBuilder` will be able to access all services registered into that
|
|
collection. For lifecycle management, an [IHostedService
|
|
](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.ihostedservice)
|
|
is used to automatically start the `TracerProvider` when the host starts and the
|
|
host will automatically shutdown and dispose the `TracerProvider` when it is
|
|
shutdown.
|
|
|
|
**Note:** Multiple calls to `AddOpenTelemetryTracing` will configure the same
|
|
`TracerProvider`. Only a single `TraceProvider` may exist in an
|
|
`IServiceCollection` \ `IServiceProvider`.
|
|
|
|
### Dependency injection `TracerProviderBuilder` extension method reference
|
|
|
|
* `AddExporter<T>`: Adds an export processor for the type `T` (must derive from
|
|
`BaseExporter<Activity>`) into the `TracerProvider`.
|
|
|
|
* `AddInstrumentation<T>`: Adds instrumentation of type `T` into the
|
|
`TracerProvider`.
|
|
|
|
* `AddProcessor<T>`: Adds a processor of type `T` (must derive from
|
|
`BaseProcessor<Activity>`) into the `TracerProvider`.
|
|
|
|
* `SetSampler<T>`: Register type `T` (must derive from `Sampler`) as the sampler
|
|
for the `TracerProvider`.
|
|
|
|
* `ConfigureServices`: Registers a callback function for configuring the
|
|
`IServiceCollection` used by the `TracerProviderBuilder`. **Note:**
|
|
`ConfigureServices` may only be called before the `IServiceProvider` has been
|
|
created after which point service can no longer be added.
|
|
|
|
* `ConfigureBuilder`: Registers a callback function for configuring the
|
|
`TracerProviderBuilder` once the `IServiceProvider` is available.
|
|
|
|
```csharp
|
|
var appBuilder = WebApplication.CreateBuilder(args);
|
|
|
|
appBuilder.Services.AddOpenTelemetryTracing(builder => builder
|
|
.ConfigureBuilder((sp, builder) =>
|
|
{
|
|
builder.AddProcessor(
|
|
new MyCustomProcessor(
|
|
// Note: This example uses the final IServiceProvider once it is available.
|
|
sp.GetRequiredService<MyCustomService>(),
|
|
sp.GetRequiredService<IOptions<MyOptions>>().Value));
|
|
}));
|
|
```
|
|
|
|
**Note:** `ConfigureBuilder` is an advanced API and is expected to be used
|
|
primarily by library authors. Services may NOT be added to the
|
|
`IServiceCollection` during `ConfigureBuilder` because the `IServiceProvider`
|
|
has already been created.
|
|
|
|
## Configuration files and environment variables
|
|
|
|
**Note:** This information applies to the OpenTelemetry SDK version 1.4.0 and
|
|
newer only.
|
|
|
|
The OpenTelemetry .NET SDK integrates with the standard
|
|
[configuration](https://learn.microsoft.com/dotnet/core/extensions/configuration)
|
|
and [options](https://learn.microsoft.com/dotnet/core/extensions/options)
|
|
patterns provided by .NET. The configuration pattern supports building a
|
|
composited view of settings from external sources and the options pattern helps
|
|
use those settings to configure features by binding to simple classes.
|
|
|
|
### How to set up configuration
|
|
|
|
The following sections describe how to set up configuration based on the host
|
|
and OpenTelemetry API being used.
|
|
|
|
#### Using .NET hosts with the OpenTelemetry.Extensions.Hosting package
|
|
|
|
`ASP.NET Core` and [.NET Generic
|
|
Host](https://learn.microsoft.com/dotnet/core/extensions/generic-host) users
|
|
using the
|
|
[OpenTelemetry.Extensions.Hosting](../../../src/OpenTelemetry.Extensions.Hosting/README.md)
|
|
package do not need to do anything extra to enable `IConfiguration` support. The
|
|
OpenTelemetry SDK will automatically use whatever `IConfiguration` has been
|
|
supplied by the host. The host by default will load environment variables,
|
|
command-line arguments, and config files. See [Configuration in
|
|
.NET](https://learn.microsoft.com/dotnet/core/extensions/configuration) for
|
|
details.
|
|
|
|
#### Using Sdk.CreateTracerProviderBuilder directly
|
|
|
|
By default the `Sdk.CreateTracerProviderBuilder` API will create an
|
|
`IConfiguration` from environment variables. The following example shows how to
|
|
customize the `IConfiguration` used by `Sdk.CreateTracerProviderBuilder` for
|
|
cases where additional sources beyond environment variables are required.
|
|
|
|
```csharp
|
|
// Build configuration from sources. Order is important.
|
|
var configuration = new ConfigurationBuilder()
|
|
.AddJsonFile("./myOTelSettings.json")
|
|
.AddEnvironmentVariables()
|
|
.AddCommandLine(args)
|
|
.Build();
|
|
|
|
// Set up a TracerProvider using the configuration.
|
|
var provider = Sdk.CreateTracerProviderBuilder()
|
|
.ConfigureServices(services => services.AddSingleton<IConfiguration>(configuration))
|
|
.Build();
|
|
```
|
|
|
|
### OpenTelemetry Specification environment variables
|
|
|
|
The [OpenTelemetry
|
|
Specification](https://github.com/open-telemetry/opentelemetry-specification)
|
|
defines [specific environment
|
|
variables](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md)
|
|
which may be used to configure SDK implementations.
|
|
|
|
The OpenTelemetry .NET SDK will look for the environment variables defined in
|
|
the specification using `IConfiguration` which means in addition to environment
|
|
variables users may also manage these settings via the command-line,
|
|
configuration files, or any other source registered with the .NET configuration
|
|
engine. This provides greater flexibility than what the specification defines.
|
|
|
|
**Note:** Not all of the environment variables defined in the specification are
|
|
supported. Consult the individual project README files for details on specific
|
|
environment variable support.
|
|
|
|
As an example the OpenTelemetry Specification defines the `OTEL_SERVICE_NAME`
|
|
environment variable which may be used to configure the service name emitted on
|
|
telemetry by the SDK.
|
|
|
|
A traditional environment variable is set using a command like `set
|
|
OTEL_SERVICE_NAME=MyService` on Windows or `export OTEL_SERVICE_NAME=MyService`
|
|
on Linux.
|
|
|
|
That works as expected but the OpenTelemetry .NET SDK is actually looking for
|
|
the `OTEL_SERVICE_NAME` key in `IConfiguration` which means it may also be
|
|
configured in any configuration source registered with the
|
|
`IConfigurationBuilder` used to create the final configuration for the host.
|
|
|
|
Below are two examples of configuring the `OTEL_SERVICE_NAME` setting beyond
|
|
environment variables.
|
|
|
|
* Using appsettings.json:
|
|
|
|
```json
|
|
{
|
|
"OTEL_SERVICE_NAME": "MyService"
|
|
}
|
|
```
|
|
|
|
* Using command-line:
|
|
|
|
```sh
|
|
dotnet run --OTEL_SERVICE_NAME "MyService"
|
|
```
|
|
|
|
**Note:** The [.NET
|
|
Configuration](https://learn.microsoft.com/dotnet/core/extensions/configuration)
|
|
pattern is hierarchical meaning the order of registered configuration sources
|
|
controls which value will seen by the SDK when it is defined in multiple
|
|
sources.
|
|
|
|
### Using the .NET Options pattern to configure the SDK
|
|
|
|
Options are typically simple classes containing only properties with public
|
|
"getters" and "setters" (aka POCOs) and have "Options" at the end of the class
|
|
name. These options classes are primarily used when interacting with the
|
|
`TracerProviderBuilder` to control settings and features of the different SDK
|
|
components.
|
|
|
|
Options classes can always be configured through code but users typically want to
|
|
control key settings through configuration.
|
|
|
|
The following example shows how to configure `JaegerExporterOptions` by binding
|
|
to an `IConfiguration` section.
|
|
|
|
Json config file (usually appsettings.json):
|
|
|
|
```json
|
|
{
|
|
"OpenTelemetry": {
|
|
"Jaeger": {
|
|
"Protocol": "UdpCompactThrift"
|
|
"AgentHost": "localhost",
|
|
"AgentPort": 6831,
|
|
"BatchExportProcessorOptions": {
|
|
"ScheduledDelayMilliseconds": 5000
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Code:
|
|
|
|
```csharp
|
|
var appBuilder = WebApplication.CreateBuilder(args);
|
|
|
|
appBuilder.Services.Configure<JaegerExporterOptions>(
|
|
appBuilder.Configuration.GetSection("OpenTelemetry:Jaeger"));
|
|
|
|
appBuilder.Services.AddOpenTelemetryTracing(
|
|
builder => builder.AddJaegerExporter());
|
|
```
|
|
|
|
The OpenTelemetry .NET SDK supports running multiple `TracerProvider`s inside
|
|
the same application and it also supports registering multiple similar
|
|
components such as exporters into a single `TracerProvider`. In order to allow
|
|
users to target configuration at specific components a "name" parameter is
|
|
typically supported on configuration extensions to control the options instance
|
|
used for the component being registered.
|
|
|
|
The below example shows how to configure two `JaegerExporter` instances inside a
|
|
single `TracerProvider` sending to different ports.
|
|
|
|
Json config file (usually appsettings.json):
|
|
|
|
```json
|
|
{
|
|
"OpenTelemetry": {
|
|
"JaegerPrimary": {
|
|
"AgentPort": 1818
|
|
},
|
|
"JaegerSecondary": {
|
|
"AgentPort": 8818
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Code:
|
|
|
|
```csharp
|
|
var appBuilder = WebApplication.CreateBuilder(args);
|
|
|
|
appBuilder.Services.Configure<JaegerExporterOptions>(
|
|
"JaegerPrimary",
|
|
appBuilder.Configuration.GetSection("OpenTelemetry:JaegerPrimary"));
|
|
|
|
appBuilder.Services.Configure<JaegerExporterOptions>(
|
|
"JaegerSecondary",
|
|
appBuilder.Configuration.GetSection("OpenTelemetry:JaegerSecondary"));
|
|
|
|
appBuilder.Services.AddOpenTelemetryTracing(builder => builder
|
|
.AddJaegerExporter(name: "JaegerPrimary", configure: null)
|
|
.AddJaegerExporter(name: "JaegerSecondary", configure: null));
|
|
```
|