Skip to content

Commit

Permalink
[docs] Updates for DI tweaks (#4127)
Browse files Browse the repository at this point in the history
  • Loading branch information
CodeBlanch authored Jan 31, 2023
1 parent 3a491b1 commit 0b69b37
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 55 deletions.
56 changes: 25 additions & 31 deletions docs/trace/customizing-the-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,11 @@ var tracerProvider = Sdk.CreateTracerProviderBuilder()
tracerProvider.AddProcessor(new MyProcessor3());
```

**Note:** The order of processor registration is important. Each processor added
is invoked in order by the SDK. For example if a simple exporting processor is
added before an enrichment processor the exported data will not contain anything
added by the enrichment because it happens after the export.

**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
Expand All @@ -202,7 +207,7 @@ 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.
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
Expand Down Expand Up @@ -329,9 +334,9 @@ 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`.
`SetSampler` is called multiple times, 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.

Expand Down Expand Up @@ -446,45 +451,34 @@ it is shutdown.
`TracerProvider`. Only a single `TraceProvider` may exist in an
`IServiceCollection` \ `IServiceProvider`.

### Dependency injection `TracerProviderBuilder` extension method reference
### Dependency injection TracerProviderBuilder extension method reference

* `AddInstrumentation<T>`: Adds instrumentation of type `T` into the
`TracerProvider`.

* `AddInstrumentation<T>(Func<IServiceProvider, T> instrumentationFactory)`:
Adds instrumentation of type `T` into the
`TracerProvider` using a factory function to create the instrumentation
instance.

* `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`.
* `AddProcessor(Func<IServiceProvider, BaseProcessor<Activity>>
implementationFactory)`: Adds a processor into the `TracerProvider` using a
factory function to create the processor instance.

* `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.AddOpenTelemetry()
.WithTracing(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));
}))
.StartWithHost();
```
created after which point services can no longer be added.

* `SetSampler<T>`: Register type `T` (must derive from `Sampler`) as the sampler
for the `TracerProvider`.

**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.
* `SetSampler(Func<IServiceProvider, Sampler>
implementationFactory)`: Adds a sampler into the `TracerProvider` using a
factory function to create the sampler instance.

## Configuration files and environment variables

Expand Down
63 changes: 39 additions & 24 deletions docs/trace/extending-the-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,15 @@ register custom OpenTelemetry components into their `TracerProvider`s. These
extension methods can target either the `TracerProviderBuilder` or the
`IServiceCollection` classes. Both of these patterns are described below.

**Note:** Libraries providing SDK plugins such as exporters, resource detectors,
and/or samplers should take a dependency on the [OpenTelemetry SDK
package](https://www.nuget.org/packages/opentelemetry). Library authors
providing instrumentation should take a dependency on `OpenTelemetry.Api` or
`OpenTelemetry.Api.ProviderBuilderExtensions` package.
`OpenTelemetry.Api.ProviderBuilderExtensions` exposes interfaces for accessing
the `IServiceCollection` which is a requirement for supporting the [.NET Options
pattern](https://learn.microsoft.com/dotnet/core/extensions/options).

When providing registration extensions:

* **DO** support the [.NET Options
Expand Down Expand Up @@ -449,7 +458,7 @@ namespace OpenTelemetry.Trace
services.TryAddSingleton<MyCustomService>();
});

builder.ConfigureBuilder((sp, builder) =>
builder.AddProcessor(serviceProvider =>
{
// Retrieve MyExporterOptions instance using name.
var exporterOptions = serviceProvider.GetRequiredService<IOptionsMonitor<MyExporterOptions>>().Get(name);
Expand All @@ -458,16 +467,15 @@ namespace OpenTelemetry.Trace
var batchOptions = serviceProvider.GetRequiredService<IOptionsMonitor<BatchExportActivityProcessorOptions>>().Get(name);

// Retrieve MyCustomService singleton.
var myCustomService = sp.GetRequiredService<MyCustomService>();

// Registers MyCustomExporter with a batch processor.
builder.AddProcessor(
new BatchActivityExportProcessor(
new MyCustomExporter(exporterOptions, myCustomService),
batchOptions.MaxQueueSize,
batchOptions.ScheduledDelayMilliseconds,
batchOptions.ExporterTimeoutMilliseconds,
batchOptions.MaxExportBatchSize));
var myCustomService = serviceProvider.GetRequiredService<MyCustomService>();

// Return a batch export processor using MyCustomExporter.
return new BatchActivityExportProcessor(
new MyCustomExporter(exporterOptions, myCustomService),
batchOptions.MaxQueueSize,
batchOptions.ScheduledDelayMilliseconds,
batchOptions.ExporterTimeoutMilliseconds,
batchOptions.MaxExportBatchSize);
});

// Return builder for call chaining.
Expand Down Expand Up @@ -519,8 +527,10 @@ When providing `TracerProviderBuilder` registration extensions:
* **DO** Use the `TracerProviderBuilder.ConfigureServices` extension method to
register dependent services.

* **DO** Use the `TracerProviderBuilder.ConfigureBuilder` extension method to
peform configuration once the final `IServiceProvider` is available.
* **DO** Use [the dependency injection extension
methods](../customizing-the-sdk/README.md#dependency-injection-tracerproviderbuilder-extension-method-reference)
utilizing factory patterns to perform configuration once the final
`IServiceProvider` is available.

### IServiceCollection extension methods

Expand All @@ -530,7 +540,8 @@ the target type for registration extension methods.

The following example shows how a library might enable tracing and metric
support using an `IServiceCollection` extension by calling
`ConfigureOpenTelemetryTracerProvider`.
`ConfigureOpenTelemetryTracerProvider` and
`ConfigureOpenTelemetryMeterProvider`.

```csharp
using Microsoft.Extensions.DependencyInjection.Extensions;
Expand All @@ -554,7 +565,7 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAddSingleton<IMyLibraryService, MyLibraryService>();

// Support named options.
name ??= Options.DefaultName;
name ??= Options.Options.DefaultName;

if (configure != null)
{
Expand All @@ -570,7 +581,7 @@ namespace Microsoft.Extensions.DependencyInjection
{
builder.AddSource("MyLibrary");
}
}));
});

// Configure OpenTelemetry metrics.
services.ConfigureOpenTelemetryMeterProvider((sp, builder) =>
Expand All @@ -580,7 +591,7 @@ namespace Microsoft.Extensions.DependencyInjection
{
builder.AddMeter("MyLibrary");
}
}));
});

return services;
}
Expand Down Expand Up @@ -614,12 +625,14 @@ single `AddMyLibrary` extension to configure the library itself and optionally
turn on OpenTelemetry integration for multiple signals (tracing & metrics in
this case).

**Note:** `ConfigureOpenTelemetryTracerProvider` does not automatically start
OpenTelemetry. The host is responsible for either calling `StartWithHost` in the
**Note:** `ConfigureOpenTelemetryTracerProvider` and
`ConfigureOpenTelemetryMeterProvider` do not automatically start OpenTelemetry.
The host is responsible for either calling `StartWithHost` in the
[OpenTelemetry.Extensions.Hosting](../../../src/OpenTelemetry.Extensions.Hosting/README.md)
package, calling `Build` when using the `Sdk.CreateTracerProviderBuilder`
method, or by accessing the `TracerProvider` from the `IServiceCollection` where
`ConfigureOpenTelemetryTracerProvider` was performed.
package, calling `Build` when using the `Sdk.CreateTracerProviderBuilder` and
`Sdk.CreateMeterProviderBuilder` methods, or by accessing the `TracerProvider`
and `MeterProvider` from the `IServiceCollection` where configuration was
performed.

When providing `IServiceCollection` registration extensions:

Expand All @@ -631,8 +644,10 @@ When providing `IServiceCollection` registration extensions:

* **DO** Use the `IServiceCollection` directly to register dependent services.

* **DO** Use the `TracerProviderBuilder.ConfigureBuilder` extension method to
peform configuration once the final `IServiceProvider` is available.
* **DO** Use [the dependency injection extension
methods](../customizing-the-sdk/README.md#dependency-injection-tracerproviderbuilder-extension-method-reference)
utilizing factory patterns to perform configuration once the final
`IServiceProvider` is available.

## References

Expand Down

0 comments on commit 0b69b37

Please sign in to comment.