ASP.NET Core OpenTelemetry instrumentation
This guide adds the OpenTelemetry .NET SDK to an ASP.NET Core service and configures it to send traces, metrics, and logs to Osuite. It uses OpenTelemetry.Extensions.Hosting to register instrumentation in Program.cs and the OTLP exporter to ship the data.
Prerequisites
Section titled “Prerequisites”- .NET 8.0 or later and an ASP.NET Core project with a
Program.cs. - An Osuite ingest endpoint and token for your region.
- Outbound network access to
ingest.<region>.osuite.ioon port443.
Instrument the service
Section titled “Instrument the service”-
Install the OpenTelemetry packages.
Terminal window dotnet add package OpenTelemetry.Extensions.Hostingdotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocoldotnet add package OpenTelemetry.Instrumentation.AspNetCoredotnet add package OpenTelemetry.Instrumentation.Httpdotnet add package OpenTelemetry.Instrumentation.Runtime -
Configure OpenTelemetry in
Program.cs. Register tracing and metrics throughAddOpenTelemetry(), add logging throughbuilder.Logging, and attach the OTLP exporter to each signal. The exporter reads its endpoint and headers from the environment variables set in the next step.using OpenTelemetry.Logs;using OpenTelemetry.Metrics;using OpenTelemetry.Trace;var builder = WebApplication.CreateBuilder(args);builder.Services.AddOpenTelemetry().WithTracing(tracing => tracing.AddAspNetCoreInstrumentation().AddHttpClientInstrumentation().AddOtlpExporter()).WithMetrics(metrics => metrics.AddAspNetCoreInstrumentation().AddHttpClientInstrumentation().AddRuntimeInstrumentation().AddOtlpExporter());builder.Logging.AddOpenTelemetry(logging =>{logging.IncludeScopes = true;logging.IncludeFormattedMessage = true;logging.AddOtlpExporter();});var app = builder.Build();app.MapGet("/", () => "Hello from Osuite");app.Run(); -
Set the Osuite environment variables. The OTLP exporter and the resource are configured entirely from the environment, so the same code runs in every environment.
Terminal window export OTEL_EXPORTER_OTLP_ENDPOINT=https://ingest.<region>.osuite.io:443export OTEL_EXPORTER_OTLP_HEADERS=x-osuite-ingest-token=<your-ingest-token>export OTEL_SERVICE_NAME=my-serviceexport OTEL_RESOURCE_ATTRIBUTES=service.environment=productionFROM mcr.microsoft.com/dotnet/aspnet:8.0WORKDIR /appCOPY bin/Release/net8.0/publish/ ./ENV OTEL_EXPORTER_OTLP_ENDPOINT=https://ingest.<region>.osuite.io:443ENV OTEL_EXPORTER_OTLP_HEADERS=x-osuite-ingest-token=<your-ingest-token>ENV OTEL_SERVICE_NAME=my-serviceENV OTEL_RESOURCE_ATTRIBUTES=service.environment=productionENTRYPOINT ["dotnet", "MyApp.dll"]apiVersion: apps/v1kind: Deploymentmetadata:name: my-servicespec:replicas: 1selector:matchLabels:app: my-servicetemplate:metadata:labels:app: my-servicespec:containers:- name: my-serviceimage: registry.example.com/my-service:latestenv:- name: OTEL_EXPORTER_OTLP_ENDPOINTvalue: "https://ingest.<region>.osuite.io:443"- name: OTEL_EXPORTER_OTLP_HEADERSvalueFrom:secretKeyRef:name: osuite-ingestkey: otlp-headers- name: OTEL_SERVICE_NAMEvalue: "my-service"- name: OTEL_RESOURCE_ATTRIBUTESvalue: "service.environment=production"Create the secret once, holding the full header string:
Terminal window kubectl create secret generic osuite-ingest \--from-literal=otlp-headers='x-osuite-ingest-token=<your-ingest-token>' -
Run the service and send it some traffic.
Terminal window dotnet run
Framework gotchas
Section titled “Framework gotchas”Instrumentation covers both minimal APIs and controller-based apps with no additional configuration. AddHttpClientInstrumentation traces outbound HttpClient calls so requests to downstream services join the same trace.
Verify in Osuite
Section titled “Verify in Osuite”What you should see
The service appears in APM within a minute of receiving traffic, emitting request-rate, latency, and error-rate metrics. Open a trace to see the ASP.NET Core server span with any outbound HttpClient spans nested beneath it, and confirm application logs appear in Logs correlated to the same trace.
Troubleshooting
Section titled “Troubleshooting”No data in Osuite after a few minutes? Work through these checks.
- Endpoint — confirm the exporter targets exactly
ingest.<region>.osuite.io:443for your region, over TLS. - Token — confirm the ingest header carries a valid
<your-ingest-token>and has not been rotated. - Pipeline — confirm the signal you expect (traces, logs, or metrics) is wired into an active pipeline with the
otlp/osuiteexporter attached. - Export errors — check the application or Collector logs for OTLP export failures (auth, DNS, TLS, connection refused).
- Network — confirm the host has outbound access to the ingest endpoint on port
443. - Timing — allow up to a minute for the first data to appear before assuming a failure.
Still stuck? Ask the Investigation Agent or contact support.
See .NET troubleshooting for issues specific to the SDK, such as missing ActivitySource registration and IIS environment variables.
Next steps
Section titled “Next steps”- Custom instrumentation — add your own spans and metrics.
- Trace correlation for logs — link logs to traces across services.