Instrument applications with OpenTelemetry SDK and validate telemetry using Kopai. Use when setting up observability, adding tracing/logging/metrics, testing instrumentation, debugging missing telemetry data, or when traces/logs/metrics aren't appearing after setup. Also use when users say things like "my traces aren't showing up", "I don't see any data", or "how do I add observability to my app".
100
100%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Passed
No known issues
| title | impact | tags |
|---|---|---|
| .NET Instrumentation | HIGH | lang, dotnet, csharp, traces, logs, metrics |
Impact: HIGH
Set up OpenTelemetry SDK for .NET applications with traces, logs, and metrics.
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol
dotnet add package OpenTelemetry.Extensions.Hosting
dotnet add package OpenTelemetry.Instrumentation.AspNetCoreCRITICAL: The OTLP exporter defaults to gRPC. For HTTP endpoints (port 4318), you MUST set OtlpExportProtocol.HttpProtobuf and append signal paths.
using OpenTelemetry.Exporter;
// Get endpoint from environment
var endpoint = Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT")
?? "http://localhost:4318";
var serviceName = Environment.GetEnvironmentVariable("OTEL_SERVICE_NAME")
?? "my-service";Environment Variables:
| Variable | Description |
|---|---|
OTEL_EXPORTER_OTLP_ENDPOINT | OTLP endpoint (e.g., http://localhost:4318) |
OTEL_SERVICE_NAME | Service name shown in observability backend |
builder.Services.AddOpenTelemetry()
.ConfigureResource(r => r.AddService(serviceName))
.WithTracing(tracing => tracing
.AddAspNetCoreInstrumentation()
.AddOtlpExporter(opts =>
{
opts.Endpoint = new Uri($"{endpoint}/v1/traces");
opts.Protocol = OtlpExportProtocol.HttpProtobuf;
}));using OpenTelemetry.Resources;
var resourceBuilder = ResourceBuilder.CreateDefault()
.AddService(serviceName);
builder.Logging.AddOpenTelemetry(logging =>
{
logging.SetResourceBuilder(resourceBuilder);
logging.AddOtlpExporter(opts =>
{
opts.Endpoint = new Uri($"{endpoint}/v1/logs");
opts.Protocol = OtlpExportProtocol.HttpProtobuf;
});
});using System.Diagnostics.Metrics;
var meter = new Meter(serviceName);
var requestCounter = meter.CreateCounter<long>("requests", "1", "Request count");
builder.Services.AddOpenTelemetry()
.WithMetrics(metrics => metrics
.AddAspNetCoreInstrumentation()
.AddMeter(serviceName)
.AddOtlpExporter(opts =>
{
opts.Endpoint = new Uri($"{endpoint}/v1/metrics");
opts.Protocol = OtlpExportProtocol.HttpProtobuf;
}));using System.Diagnostics.Metrics;
using OpenTelemetry.Exporter;
using OpenTelemetry.Logs;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
var builder = WebApplication.CreateBuilder(args);
var endpoint = Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT")
?? "http://localhost:4318";
var serviceName = Environment.GetEnvironmentVariable("OTEL_SERVICE_NAME")
?? "my-service";
var meter = new Meter(serviceName);
var requestCounter = meter.CreateCounter<long>("requests");
var resourceBuilder = ResourceBuilder.CreateDefault().AddService(serviceName);
// Traces and Metrics
builder.Services.AddOpenTelemetry()
.ConfigureResource(r => r.AddService(serviceName))
.WithTracing(tracing => tracing
.AddAspNetCoreInstrumentation()
.AddOtlpExporter(opts =>
{
opts.Endpoint = new Uri($"{endpoint}/v1/traces");
opts.Protocol = OtlpExportProtocol.HttpProtobuf;
}))
.WithMetrics(metrics => metrics
.AddAspNetCoreInstrumentation()
.AddMeter(serviceName)
.AddOtlpExporter(opts =>
{
opts.Endpoint = new Uri($"{endpoint}/v1/metrics");
opts.Protocol = OtlpExportProtocol.HttpProtobuf;
}));
// Logs
builder.Logging.AddOpenTelemetry(logging =>
{
logging.SetResourceBuilder(resourceBuilder);
logging.AddOtlpExporter(opts =>
{
opts.Endpoint = new Uri($"{endpoint}/v1/logs");
opts.Protocol = OtlpExportProtocol.HttpProtobuf;
});
});
var app = builder.Build();
app.MapGet("/hello", (ILogger<Program> logger) =>
{
requestCounter.Add(1);
logger.LogInformation("Hello endpoint called");
return Results.Json(new { message = "Hello!" });
});
app.Run();rules