Dashboard Get started

.NET / C# Instrumentation

Attach the OpenTelemetry auto-instrumentation agent to the .NET runtime — HTTP requests, HttpClient, Entity Framework, gRPC, exceptions, and latency captured with zero code changes.

Zero-code setup (recommended)

Install the auto-instrumentation agent once per machine or container:

Windows (PowerShell)
Invoke-WebRequest -Uri https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/releases/latest/download/OpenTelemetry.DotNet.Auto.psm1 -OutFile OpenTelemetry.DotNet.Auto.psm1
Import-Module ./OpenTelemetry.DotNet.Auto.psm1
Install-OpenTelemetryCore
Register-OpenTelemetryForCurrentSession -OTelServiceName "my-dotnet-service"
Linux / macOS
curl -sSfL https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/releases/latest/download/otel-dotnet-auto-install.sh -O
sh otel-dotnet-auto-install.sh
. $HOME/.otel-dotnet-auto/instrument.sh

Point it at Lightarch and run your app:

powershell
$env:OTEL_SERVICE_NAME              = "my-dotnet-service"
$env:OTEL_EXPORTER_OTLP_ENDPOINT    = "https://la-ingest-gateway.lightarch.workers.dev"
$env:OTEL_EXPORTER_OTLP_HEADERS     = "x-la-dsn=la_live_YOUR_TOKEN_HERE"
$env:OTEL_EXPORTER_OTLP_PROTOCOL    = "http/protobuf"

dotnet run
That's the whole setup. Unhandled exceptions appear in the Errors page with full stack traces, requests show up as traces with latency, and outbound calls are correlated — no Program.cs changes.

Screenshot needed

Traces page showing .NET service spans with service='my-dotnet-service', ASP.NET Core route spans like 'GET /api/orders', durations in ms.

Verify it's working

bash
la query "SELECT service, severity, body, duration_ms FROM recent_spans WHERE service = 'my-dotnet-service' ORDER BY timestamp DESC LIMIT 10"

la logs tail --service my-dotnet-service

Code-based setup (more control)

If you prefer configuring in code, add three packages and one block to Program.cs:

bash
dotnet add package OpenTelemetry.Extensions.Hosting
dotnet add package OpenTelemetry.Instrumentation.AspNetCore
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol
Program.cs
using OpenTelemetry.Exporter;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;

builder.Services.AddOpenTelemetry()
    .ConfigureResource(r => r.AddService("my-dotnet-service"))
    .WithTracing(t => t
        .AddAspNetCoreInstrumentation()
        .AddHttpClientInstrumentation()
        .AddOtlpExporter(o => {
            o.Endpoint = new Uri("https://la-ingest-gateway.lightarch.workers.dev/v1/traces");
            // Required: the .NET exporter defaults to gRPC, which Lightarch doesn't accept
            o.Protocol = OtlpExportProtocol.HttpProtobuf;
            o.Headers  = "x-la-dsn=la_live_YOUR_TOKEN_HERE";
        }));
o.Protocol = OtlpExportProtocol.HttpProtobuf is required — the .NET OTLP exporter defaults to gRPC and will silently fail without it.

Optional: Entity Framework Core

bash
dotnet add package OpenTelemetry.Instrumentation.EntityFrameworkCore
csharp
.WithTracing(t => t
    .AddAspNetCoreInstrumentation()
    .AddHttpClientInstrumentation()
    .AddEntityFrameworkCoreInstrumentation()
    .AddOtlpExporter(/* same as above */));

Custom spans

csharp
using var tracer = TracerProvider.Default.GetTracer("my-dotnet-service");

using var span = tracer.StartActiveSpan("payment.process");
span.SetAttribute("order.id", orderId);
try
{
    var result = await ChargeCard(orderId);
    span.SetAttribute("payment.status", result.Status);
    return result;
}
catch (Exception ex)
{
    span.RecordException(ex);
    span.SetStatus(Status.Error.WithDescription(ex.Message));
    throw;
}