OpenTelemetryExtension.Configuration 2.1.3

dotnet add package OpenTelemetryExtension.Configuration --version 2.1.3
                    
NuGet\Install-Package OpenTelemetryExtension.Configuration -Version 2.1.3
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="OpenTelemetryExtension.Configuration" Version="2.1.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="OpenTelemetryExtension.Configuration" Version="2.1.3" />
                    
Directory.Packages.props
<PackageReference Include="OpenTelemetryExtension.Configuration" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add OpenTelemetryExtension.Configuration --version 2.1.3
                    
#r "nuget: OpenTelemetryExtension.Configuration, 2.1.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package OpenTelemetryExtension.Configuration@2.1.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=OpenTelemetryExtension.Configuration&version=2.1.3
                    
Install as a Cake Addin
#tool nuget:?package=OpenTelemetryExtension.Configuration&version=2.1.3
                    
Install as a Cake Tool

OpenTelemetryExtension.Configuration

CI Coverage NuGet Downloads License

Drop-in OpenTelemetry setup for .NET — tracing, metrics and logging over OTLP, configured through code or configuration.

builder.Services.AddTelemetry(builder.Configuration);
{
  "Telemetry": {
    "Endpoint": "http://localhost:4318",
    "ServiceName": "my-api"
  }
}

That's the whole setup — traces, metrics and logs are exported via OTLP.


Contents


✨ Features

  • One-call setup — tracing, metrics and logging via a single AddTelemetry(), from appsettings.json or code
  • Works on any .NET — ASP.NET Core, WPF, console and more, exporting over OTLP to any compatible backend
  • Auto-instrumentationHttpClient, ASP.NET Core and .NET runtime traced and measured automatically, each toggleable
  • Extensible — add your own sources, meters and databases when you need them

✅ Requirements

Every app type works — ASP.NET Core, WPF, WinForms, console, worker services, MAUI/WinUI, UWP. The package ships three targets and NuGet picks the best match for your target framework; the app type plays no role:

Your target framework Build you get Bundles ASP.NET Core instrumentation
net10.0 — including net10.0-windows (WPF/WinForms) net10.0
net8.0, net9.0 — including their -windows variants net8.0
.NET Framework 4.6.1+, .NET Standard 2.0 consumers netstandard2.0

The last column is only about the optional ASP.NET Core instrumentation dependency, which traces incoming HTTP requests and is therefore meaningless outside a web app. It is left out of the netstandard2.0 build so .NET Framework clients don't drag in an ASP.NET Core dependency they can't use. Everything else — OTLP export, tracing, metrics, logging, HttpClient and runtime instrumentation — is identical in all three builds.

A WPF app on net10.0-windows therefore gets the full net10.0 build. Only WPF on .NET Framework falls back to netstandard2.0.

You also need an OTLP-compatible backend to receive the telemetry (collector, Jaeger, OpenObserve, SigNoz, the .NET Aspire Dashboard, …). See Running Locally with a Backend.


📦 Installation

dotnet add package OpenTelemetryExtension.Configuration

Other ways to consume it

The NuGet package is the recommended path, but it isn't the only one:

  • As source / project reference or a plain copy — the library is just two files. Either clone OpenTelemetryExtension.Configuration into your repository and add a <ProjectReference> to it, or drop the two files straight into your project (no package, no reference) and own them outright: TelemetryServiceCollectionExtensions.cs and TelemetryOptions.cs. Handy when you want to tweak the defaults or step through the setup code.
  • As a git submodule — pin the source at a specific commit and reference the project from your solution:
    git submodule add https://github.com/thorstenalpers/OpenTelemetryExtension.Configuration.git external/OpenTelemetryExtension.Configuration
    
    then add a <ProjectReference> to external/OpenTelemetryExtension.Configuration/src/OpenTelemetryExtension.Configuration/OpenTelemetryExtension.Configuration.csproj.
  • As a fork — fork the repository and adapt it to your needs. Optionally, if your changes are generally useful, open a pull request back upstream. See Contributing.

In every case the API is identical — AddTelemetry(...) works the same whether the type comes from a NuGet package or your own copy of the source.


🚀 Quick Start

1. Register

builder.Services.AddTelemetry(builder.Configuration);

2. Configure (appsettings.json)

{
  "Telemetry": {
    "Endpoint": "http://localhost:4318",
    "ServiceName": "my-api"
  }
}

That's it — tracing, metrics and logging are exported via OTLP.

You need an OTLP-compatible backend listening at Endpoint. No backend yet? See Running Locally with a Backend for one-command setups.


⚙️ Configuration

All keys live under the Telemetry section. Only Endpoint is required; everything else has a default and telemetry is on out of the box. Bind from appsettings.json or set the same properties in the AddTelemetry(o => …) callback.

Key Description Type Default Example
Endpoint OTLP endpoint for traces, metrics and logs. Uri (required) https://otel.example.com:4317
Protocol Transport protocol: HttpProtobuf (4318) or Grpc (4317). string HttpProtobuf Grpc
Headers OTLP exporter headers, e.g. for auth. Format: k1=v1,k2=v2. string "" x-otlp-api-key=secret
Enabled Master switch; false registers no OpenTelemetry at all. bool true false
ServiceName Logical service name shown in the backend. string? null orders-api
ResourceAttributes Extra resource attributes. object {} { "deployment.environment": "production" }
EnableTracing Distributed tracing. bool true false
EnableMetrics Metrics collection. bool true false
EnableLogging Log export via OTLP. bool true false
SampleRatio Trace sample fraction — 1.0 = all, 0.1 = 10% (ParentBased(TraceIdRatioBased)). double 1.0 0.1
EnableAspNetCoreInstrumentation Incoming ASP.NET Core requests (net8.0/net10.0 builds; no-op on netstandard2.0). bool true false
EnableHttpClientInstrumentation Outgoing HttpClient requests. bool true false
EnableRuntimeInstrumentation .NET runtime metrics (GC, memory, thread pool). bool true false
AdditionalTracingSources Extra ActivitySource names to collect. string[] [] [ "Npgsql", "MyApp" ]
AdditionalMeters Extra Meter names to collect. string[] [] [ "MyApp.Orders" ]
RecordExceptions Record exceptions with stack traces on spans. bool true false
ExcludedPaths Paths excluded from tracing (per-segment prefix match). string[] [ "/health" ] [ "/health", "/ready" ]
IncludeScopes Include log scopes in exported records. bool true false
IncludeFormattedMessage Include the formatted message in exported records. bool true false
ConfigureTracing Code only. Register extra tracing — see Code configuration. Action<TracerProviderBuilder> null t => t.AddSource("MyApp")
ConfigureMetrics Code only. Register extra metrics. Action<MeterProviderBuilder> null m => m.AddMeter("MyApp")
ConfigureLogging Code only. Tweak the logging pipeline. Action<ILoggingBuilder> null l => l.AddConsole()

💡 See docs/appsettings.Example.json for a complete profile with every key set to a realistic, non-default value.

Endpoint & protocol — give Endpoint the base URL, not a signal path:

  • HttpProtobuf (default, port 4318) — the per-signal path (/v1/traces, /v1/metrics, /v1/logs) is appended for you.
  • Grpc (port 4317) — every signal goes to the base endpoint as-is.

Endpoint is validated at registration and AddTelemetry() throws when it is missing. The one exception is Enabled: false: validation is skipped, nothing is registered, and the call becomes a no-op — so you can switch telemetry off in an environment without also having to supply an endpoint.

Custom section name

The section defaults to Telemetry, but you can bind any section by passing its name:

builder.Services.AddTelemetry(builder.Configuration, "MyTelemetry");
// or together with a code callback:
builder.Services.AddTelemetry(builder.Configuration, o => { /* ... */ }, "MyTelemetry");
{
  "MyTelemetry": {
    "Endpoint": "http://localhost:4318",
    "ServiceName": "my-api"
  }
}

🧩 Code Configuration

Configure entirely in code instead of appsettings.json:

builder.Services.AddTelemetry(o =>
{
    o.Endpoint        = new Uri("http://localhost:4318");
    o.ServiceName     = "my-api";
    o.ResourceAttributes = new() { ["deployment.environment"] = "production" };
    o.SampleRatio     = 0.1;

    // Code-only: register additional instrumentation
    o.ConfigureTracing = tracing => tracing.AddSource("MyApp");
    o.ConfigureMetrics = metrics => metrics.AddMeter("MyApp");
    o.ConfigureLogging = logging => logging.AddConsole();
});

Or bind appsettings.json first and layer code-only options on top — both sources are combined, and bound values can still be overridden in the callback:

builder.Services.AddTelemetry(builder.Configuration, o =>
{
    // Everything from appsettings.json is already bound here.
    o.ConfigureTracing = tracing => tracing.AddSource("MyApp");
    o.ConfigureMetrics = metrics => metrics.AddMeter("MyApp");
    o.ConfigureLogging = logging => logging.AddConsole();
});

The Configure* hooks — Sources & Meters

The three callbacks are the extension points for your own telemetry. The built-in instrumentation (ASP.NET Core, HttpClient, .NET runtime) is wired up automatically; these hooks let you add the signals your application emits itself, plus anything that needs an extra NuGet package — such as databases.

Hook Builder Used to register
ConfigureTracing TracerProviderBuilder Activity Sources via AddSource("Name")
ConfigureMetrics MeterProviderBuilder Meters via AddMeter("Name")
ConfigureLogging ILoggingBuilder extra logging providers, filters, etc.

What is a Meter? A Meter (from System.Diagnostics.Metrics) is the factory you create instruments (counters, histograms, gauges) from. Each Meter has a name, and OpenTelemetry only collects metrics from meters you have explicitly registered with AddMeter("That.Name"). Without that call, your custom metrics are never exported.

// 1. Create a Meter and an instrument somewhere in your app
private static readonly Meter Meter = new("MyApp.Orders");
private static readonly Counter<long> OrdersPlaced = Meter.CreateCounter<long>("orders.placed");

// ... later
OrdersPlaced.Add(1);

// 2. Register the meter's name so it gets exported
o.ConfigureMetrics = metrics => metrics.AddMeter("MyApp.Orders");

What is a Source? An ActivitySource is the tracing equivalent: it creates Activity objects (= spans). Register its name with AddSource("MyApp") so your custom spans are sampled and exported.

private static readonly ActivitySource Activity = new("MyApp");

using var span = Activity.StartActivity("ProcessOrder");
// ... work being traced

o.ConfigureTracing = tracing => tracing.AddSource("MyApp");

The string passed to AddMeter/AddSource must exactly match the name you gave the Meter/ActivitySource — that name is how OpenTelemetry routes the data.

Databases

Database instrumentation is not built in — it depends entirely on your driver, so it is added through the ConfigureTracing hook. This keeps the package free of database-specific dependencies; you only pull in what you use.

There are two kinds of database instrumentation:

Kind Examples How to enable
Package-based — ships an Add…Instrumentation() extension SQL Server (OpenTelemetry.Instrumentation.SqlClient), EF Core (OpenTelemetry.Instrumentation.EntityFrameworkCore) install the package + call it in ConfigureTracing
Source-based — the driver already emits an ActivitySource Npgsql (Npgsql), MySqlConnector (MySqlConnector), Oracle (Oracle.ManagedDataAccess.Core) register the source name — code or config, no extra package

ConfigureTracing is a single delegate, so chain everything in one assignment:

// dotnet add package OpenTelemetry.Instrumentation.SqlClient
// dotnet add package OpenTelemetry.Instrumentation.EntityFrameworkCore
o.ConfigureTracing = t => t
    .AddSqlClientInstrumentation()
    .AddEntityFrameworkCoreInstrumentation()
    .AddSource("Npgsql")            // PostgreSQL
    .AddSource("MySqlConnector");   // MySQL

No code for source-based drivers: the second row of the table above needs no C# at all — AdditionalTracingSources does the same job from appsettings.json:

{
  "Telemetry": {
    "Endpoint": "http://localhost:4318",
    "AdditionalTracingSources": [ "Npgsql", "MyApp" ],
    "AdditionalMeters": [ "MyApp.Orders" ]
  }
}

Package-based instrumentation (SQL Server, EF Core) still needs the one-line ConfigureTracing call above, because it requires its NuGet package — a config string alone can't pull in a dependency.

Toggling SQL instrumentation from appsettings.json

Because EnableSqlClientInstrumentation is not part of TelemetryOptions (the package is optional), you can add it as a custom key and read it in the callback:

appsettings.json:

{
  "Telemetry": {
    "Endpoint": "http://localhost:4318",
    "ServiceName": "my-api",
    "RecordExceptions": true,

    "EnableSqlClientInstrumentation": true   // custom key
  }
}

Program.cs:

builder.Services.AddTelemetry(builder.Configuration, opt =>
    opt.ConfigureTracing = tracing =>
    {
        if (builder.Configuration.GetValue<bool>("Telemetry:EnableSqlClientInstrumentation"))
        {
            // NuGet: OpenTelemetry.Instrumentation.SqlClient
            tracing.AddSqlClientInstrumentation(sql => sql.RecordException = opt.RecordExceptions);
        }
    });

This keeps the on/off switch in config while the package dependency stays explicit in code.


🖥️ Using outside the Generic Host

AddTelemetry() works with any IServiceCollection — ASP.NET Core, WPF, WinForms, console, MAUI/WinUI, UWP, worker services, etc.

With the Generic Host (recommended for desktop/console — Host.CreateApplicationBuilder()), the providers start and flush automatically:

var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddTelemetry(builder.Configuration);
using var host = builder.Build();
await host.RunAsync();   // telemetry starts here and flushes on shutdown

Without a host (e.g. a bare ServiceCollection in UWP or a minimal app), build the provider and dispose it on exit so buffered telemetry is flushed:

var services = new ServiceCollection();
services.AddTelemetry(o =>
{
    o.Endpoint    = new Uri("http://localhost:4318");
    o.ServiceName = "my-desktop-app";
});

var provider = services.BuildServiceProvider();
// ... app runs ...
provider.Dispose();      // flushes traces, metrics and logs

ASP.NET Core instrumentation is in the net8.0 and net10.0 builds only — which a desktop or console app targeting net8.0/net10.0 (or their -windows variants) does get. Only on the netstandard2.0 build (.NET Framework) is it absent, and setting EnableAspNetCoreInstrumentation there is a harmless no-op. See Requirements.


🧪 Samples

Two runnable samples live under src/:

Sample Project Demonstrates
Web API …Sample.WebApi ASP.NET Core minimal API configured from appsettings.json, ready-to-run backend profiles, EF Core and opt-in SQL instrumentation.
WPF …Sample.Wpf Desktop app wiring AddTelemetry() through the Generic Host, emitting a custom ActivitySource/Meter and an HttpClient span on a button click.

The Web API sample drives the backend walkthrough below; the WPF sample exports to http://localhost:4318 by default — point it at any of the backends here.


🔌 Running Locally with a Backend

The Web API sample ships ready-to-run configurations for several popular backends (the three below are documented in full; more start scripts live in infrastructure/). Each backend has:

  1. an infrastructure start script (Docker Compose or Helm) in infrastructure/,
  2. a launch profile that selects the matching appsettings.<env>.json,
  3. a UI where the exported traces, metrics and logs show up.

Steps

  1. Start the backend infrastructure — run the script for your backend (see table).
  2. Run the sample with the matching profile:
    cd src/OpenTelemetryExtension.Configuration.Sample.WebApi
    dotnet run --launch-profile "Start Aspire"
    
    Or pick the profile from the run dropdown in Visual Studio / Rider.
  3. Generate traffic — the app opens Swagger at https://localhost:5073/swagger; call an endpoint.
  4. Open the backend UI (see table) to inspect the telemetry.

Backend overview

Backend Start infrastructure Launch profile Backend UI
.NET Aspire Dashboard docker/docker-install-aspire-dashboard.cmd (or helm/helm-install-aspire-dashboard.cmd) Start Aspire http://localhost:31888
Jaeger docker/docker-install-jaeger.cmd Start Jaeger http://localhost:16686
OpenObserve helm/helm-install-openobserve.cmd (or docker/docker-install-openobserve.cmd) Start OpenObserve Http / Start OpenObserve Grpc http://localhost:30117 (admin@web.de/admin)
SigNoz helm/helm-install-signoz.cmd Start SigNoz http://localhost:30111 (admin@web.de)
Grafana / Loki docker/docker-install-loki.cmd Start Loki http://localhost:3000 (admin/admin)
OpenSearch Dashboards docker/docker-install-opensearch.cmd Start OpenSearch http://localhost:5601

(Paths are relative to infrastructure/. The first three are documented in full below; the rest work the same way — start the script, pick the profile.)

Tip — viewing logs in the Aspire Dashboard: after starting the app with the Start Aspire profile, open http://localhost:31888, then go to the Structured (logs), Traces or Metrics tab. Data appears as soon as you hit a Swagger endpoint.


📝 Sample Backend Configurations

These are the exact appsettings.<env>.json files used by the sample's launch profiles.

.NET Aspire Dashboard — appsettings.aspire.json

The dashboard requires an API key on the OTLP endpoint (x-otlp-api-key). The gRPC endpoint is exposed on NodePort 31889 (Helm) or host port 31889 (Docker).

{
  "Telemetry": {
    "Protocol": "Grpc",
    "Endpoint": "http://localhost:31889",
    "Headers": "x-otlp-api-key=aspire"
  }
}

Traces, metrics and logs from the sample app shown live in the Aspire Dashboard UI:

Aspire Dashboard demo

Jaeger — appsettings.jaeger.json

{
  "Telemetry": {
    "Protocol": "Grpc",
    "Endpoint": "http://localhost:4317"
  }
}

Traces from the sample app shown in the Jaeger UI:

Jaeger demo

OpenObserve — HTTP/protobuf — appsettings.openobserve-http.json

{
  "Telemetry": {
    "Protocol": "HttpProtobuf",
    "Endpoint": "http://localhost:30117/api/default",
    "Headers": "Authorization=Basic YWRtaW5Ad2ViLmRlOmFkbWlu,stream-name=default"
  }
}

The same telemetry explored in the OpenObserve UI:

OpenObserve demo


🤝 Contributing

Contributions are welcome — bug fixes, new instrumentation options, documentation improvements and ideas alike. For anything beyond a small fix, please open an issue first so we can agree on the approach before you invest time in a pull request.

The basic workflow is: fork the repo, branch off main (feature/<name> or fix/<name>), make your change, add or update tests for any public API change, run the unit tests, and open a PR against main. Build and test locally with:

dotnet build OpenTelemetryExtension.slnx -c Release
dotnet test  src/OpenTelemetryExtension.Configuration.Tests -c Release

Full details — code style, the integration-test stack, and the release process — are in CONTRIBUTING.md. Note that versioning and release notes are handled separately at release time, so you don't need to touch them in a feature PR.

🐛 Report a Bug

Found something broken or behaving unexpectedly? Please open an issue. To help reproduce it quickly, include the package version, your target framework (e.g. net10.0 or netstandard2.0), the relevant Telemetry configuration, the OTLP backend you export to, and what you expected to happen versus what actually did. A minimal repro or stack trace speeds things up a lot.

For security-sensitive reports, please follow SECURITY.md instead of opening a public issue.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.1.3 89 7/29/2026
2.1.2 110 7/1/2026
2.1.1 483 6/21/2026
2.1.0 97 6/12/2026
2.0.1 109 6/12/2026
2.0.0 114 6/10/2026
1.1.1 115 6/6/2026
1.1.0 115 6/6/2026
1.0.2 119 6/1/2026
1.0.1 116 5/28/2026
1.0.0 112 5/28/2026