OpenTelemetry .NET SDK
ASP.NET Core and other .NET applications that use Microsoft.Extensions.Logging without Serilog can use the OpenTelemetry .NET SDK to send data. Refer to the OpenTelemetry documentation for more details.
Terminology Translation
OpenTelemetry, .NET and Seq use different names for things. The following table translates between the schemes.
OpenTelemetry | .NET | Seq | Description |
---|---|---|---|
Span | Activity | Span | An event that has a start timestamp, a duration and zero or more child spans / activities. |
Tracer | ActivitySource | - | Entity responsible for creating spans / activities. |
Attribute | Tag | Property | Value attached to an event, such as a log event or a span / activity. |
Trace (noun) | - | Trace | A set of related spans. |
Log (noun) | Log event | Log event | A timestamped value including a human-readable message and attached structured data. Seq uses 'log event' to differentiate from the log data structure in which log events are stored. |
Span event | - | Log event | A lightweight log event within a span. Seq promotes these to regular log events. |
Installing the OpenTelemetry .NET SDK
At the terminal, or in the Visual Studio Package Manager Console, type:
dotnet add package OpenTelemetry.Extensions.Hosting
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol
dotnet add package OpenTelemetry.Exporter.Console
dotnet add package OpenTelemetry.Instrumentation.AspNetCore
dotnet add package OpenTelemetry.Instrumentation.Http
dotnet add package --prerelease OpenTelemetry.Instrumentation.SqlClient
The purpose of these dependencies is explained in the following table.
Dependency | Purpose |
---|---|
OpenTelemetry.Extensions.Hosting | Provides a way to register the OpenTelemetry .NET SDK with .NET's app startup and lifetime management. |
OpenTelemetry.Exporter.OpenTelemetryProtocol | Is the connector that sends telemetry data, via the OpenTelemetry Protocol (OTLP) to a server. |
OpenTelemetry.Exporter.Console | Is the connector that sends telemetry data to the console. This is optional. |
OpenTelemetry.Instrumentation.AspNetCore | Allows the OpenTelemetry client to track ASP.NET Core activities. This is only useful for ASP.NET Core applications. |
OpenTelemetry.Instrumentation.Http | Allows the OpenTelemetry client to track information about outgoing HTTP requests made through System.Net.HttpClient and System.Net.HttpWebRequest . This is only useful for applications that make HTTP requests. |
OpenTelemetry.Instrumentation.SqlClient | Adds instrumentation to the .NET client libraries for Microsoft SQL Server and Azure SQL Database. This is only useful for applications that connect to these databases. |
Next, configure the OpenTelemetry (OTEL) client.
ASP.NET Core configuration example:
using System.Diagnostics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using OpenTelemetry.Exporter;
ActivitySource tracingSource = new("Example.Source");
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenTelemetry()
.ConfigureResource(r => r.AddService("My Service"))
.WithTracing(tracing =>
{
tracing.AddSource("Example.Source");
tracing.AddAspNetCoreInstrumentation();
tracing.AddHttpClientInstrumentation();
tracing.AddSqlClientInstrumentation();
tracing.AddConsoleExporter();
tracing.AddOtlpExporter(opt =>
{
opt.Endpoint = new Uri("http://localhost:5341/ingest/otlp/v1/traces");
opt.Protocol = OtlpExportProtocol.HttpProtobuf;
opt.Headers = "X-Seq-ApiKey=abcde12345";
});
});
var app = builder.Build();
Console application configuration example:
using System.Diagnostics;
using OpenTelemetry;
using OpenTelemetry.Exporter;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
ActivitySource tracingSource = new("Example.Source");
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
.ConfigureResource(r => r.AddService("My Service"))
.AddSource("Example.Source")
.AddHttpClientInstrumentation()
.AddSqlClientInstrumentation();
.AddConsoleExporter()
.AddOtlpExporter(opt =>
{
opt.Endpoint = new Uri("http://localhost:5341/ingest/otlp/v1/traces");
opt.Protocol = OtlpExportProtocol.HttpProtobuf;
opt.Headers = "X-Seq-ApiKey=abcde12345";
})
.Build();
Let us consider this one step at a time.
ActivitySource tracingSource = new("Example.Source");
This creates a new System.Diagnostic.ActivitySource
. It can be used to generate traces.
builder.Services.AddOpenTelemetry()
This begins the OpenTelemetry configuration for an ASP.NET Core application.
.ConfigureResource(r => r.AddService(builder.Environment.ApplicationName))
In OpenTelemetry terminology a resource is something that emits telemetry. It is conventional to ensure that all telemetry is emitted by a resource with a service name.
.WithTracing(tracing =>
Configures the OpenTelemetry SDK to emit trace data.
tracing.AddSource("Example.Source");
Tells the OTEL SDK to listen to the ActivitySource
with the name Example.Source
. This must exactly match the name of the ActivitySource
used to create activities (spans).
tracing.AddAspNetCoreInstrumentation();
tracing.AddHttpClientInstrumentation();
tracing.AddSqlClientInstrumentation();
Register the OTEL SDK to collect trace data from ASP.NET Core, HttpClient
and the SQL Server
client.
tracing.AddConsoleExporter();
Send trace telemetry to the console.
tracing.AddOtlpExporter(opt =>
{
opt.Endpoint = new Uri("http://localhost:5341/ingest/otlp/v1/traces");
opt.Protocol = OtlpExportProtocol.HttpProtobuf;
opt.Headers = "X-Seq-ApiKey=abcde12345";
});
Send trace telemetry to an OTLP server. Protocol can be OtlpExportProtocol.HttpProtobuf
or OtlpExportProtocol.Grpc
as required.
For gRPC to work:
- the connection to Seq must be served using HTTPS (TLS)
- all intermediate network infrastructure must fully supports HTTP 2.0
- Seq must be configured to use the Kestrel web server (not the default on Windows)
For these reasons it is best to start with the HttpProtobuf protocol.
For the HttpProtobuf
protocol the correct endpoint is https://seq.example.com/ingest/otlp/v1/traces
(replacing https://seq.example.com with your domain, protocol and port).
For the Grpc
protocol the correct endpoint is https://seq.example.com
(replacing https://seq.example.com with your domain, protocol and port).
If you are using an API Key for ingestion, add an X-Seq-ApiKey
header containing the API key. The expected format of the opt.Headers
string is a comma-separated list of <key>=<value>
pairs.
Generating Traces
A trace is generated by starting activities on an ActivitySource
that has been registered with the OpenTelemetry SDK.
The StartActivity
method will return null
if there are no registered listeners for the ActivitySource
, so accessing the Activity
must be protected using the null-coalescing operator (?.
). If your activities / spans are not appearing check that StartActivity
is returning a non-null value.
Activities are given a name, which may include placeholders for interpolating attached data. Key/value data can be attached using the SetTag
method.
Activities (spans) created within the scope of other activities will establish a parent-child relationship.
using (Activity activity = tracingSource.StartActivity("Hello {Name}"))
{
activity?.SetTag("Name", "world");
using (Activity child = tracingSource.StartActivity("Child activity")) {
//
}
}
Updated 9 months ago