Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.tracelit.io/llms.txt

Use this file to discover all available pages before exploring further.

Requirements: .NET 8+

Installation

dotnet add package Tracelit

Quick start


Configuration reference

OptionEnv variableDefaultDescription
ApiKeyTRACELIT_API_KEYnullRequired. Your Tracelit ingest API key
ServiceNameTRACELIT_SERVICE_NAMEnullRequired. Service name shown in Tracelit
EnvironmentTRACELIT_ENVIRONMENT"production"Deployment environment tag
EndpointTRACELIT_ENDPOINThttps://ingest.tracelit.appOverride only when self-hosting
SampleRateTRACELIT_SAMPLE_RATE1.0Head-based sampling ratio 0.01.0. Errors always export.
EnabledTRACELIT_ENABLEDtrueSet false to disable all telemetry
ResourceAttributes{}Extra Dictionary<string, string> on every span, metric, and log

Custom resource attributes

builder.Services.AddTracelit(config =>
{
    config.ApiKey      = Environment.GetEnvironmentVariable("TRACELIT_API_KEY");
    config.ServiceName = "orders-api";
    config.ResourceAttributes = new()
    {
        ["deployment.region"] = "us-east-1",
        ["team"]              = "platform",
    };
});

Tracing

Manual spans

Use the static façade — works in both DI and non-DI apps after Start() is called:
using var span = TracelitClient.Tracer.StartActiveSpan("process_payment");
span?.SetTag("payment.id", payment.Id.ToString());
span?.SetTag("payment.amount", amount.ToString());
span?.SetTag("payment.currency", currency);

try
{
    var result = ProcessPayment(payment);
    span?.SetTag("payment.status", result.Status);
    return result;
}
catch (Exception ex)
{
    span?.RecordException(ex);
    span?.SetStatus(Status.Error.WithDescription(ex.Message));
    throw;
}

In ASP.NET Core (DI-injected ActivitySource)

public class OrdersController : ControllerBase
{
    private static readonly ActivitySource _source = new("OrdersService");

    [HttpPost]
    public async Task<IActionResult> CreateOrder([FromBody] CreateOrderRequest req)
    {
        using var activity = _source.StartActivity("create-order");
        activity?.SetTag("order.channel", req.Channel);

        var order = await _orderService.CreateAsync(req);
        activity?.SetTag("order.id", order.Id);

        return Created($"/orders/{order.Id}", order);
    }
}

Automatic instrumentation

LibraryWhat is captured
ASP.NET CoreHTTP request traces, request duration/count/error metrics
HttpClientOutbound HTTP call traces
SqlClientSQL query traces
.NET runtimeGC, thread pool, lock contention metrics

Metrics

Counter

var counter = TracelitClient.Metrics.Counter(
    "orders.placed",
    description: "Total orders placed",
    unit: "{orders}");

counter.Add(1,
    new KeyValuePair<string, object?>("currency", "USD"),
    new KeyValuePair<string, object?>("channel", "web"));

Histogram

var histogram = TracelitClient.Metrics.Histogram(
    "external.api.duration",
    description: "External API call duration",
    unit: "ms");

var sw = Stopwatch.StartNew();
await CallExternalApiAsync();
histogram.Record(sw.Elapsed.TotalMilliseconds,
    new KeyValuePair<string, object?>("service", "stripe"));

Gauge

var gauge = TracelitClient.Metrics.Gauge(
    "job_queue.depth",
    () => (double)JobQueue.PendingCount,
    description: "Number of pending background jobs",
    unit: "{jobs}");

Automatic metrics collection

MetricTypeDescription
http.server.request.durationHistogramHTTP request duration
http.server.active_requestsUpDownCounterIn-flight requests
http.client.request.durationHistogramOutbound HTTP duration
dotnet.gc.*VariousGC collections, heap size, pause time
dotnet.thread_pool.*VariousThread pool queue length, worker threads
process.memory.rssGaugeProcess working set in MB (polled every 60 s)

Log forwarding

When using AddTracelit(), all ILogger output is forwarded to the Tracelit logs table via OTLP. Log records are automatically correlated to the active span via trace_id + span_id.
public class OrdersService
{
    private readonly ILogger<OrdersService> _logger;

    public OrdersService(ILogger<OrdersService> logger)
    {
        _logger = logger;
    }

    public async Task<Order> CreateAsync(CreateOrderRequest req)
    {
        // This log automatically includes trace_id/span_id from the current Activity
        _logger.LogInformation("Processing order for {Channel}", req.Channel);

        var order = await _repository.InsertAsync(req);

        _logger.LogInformation("Order {OrderId} created in {ElapsedMs}ms",
            order.Id, sw.ElapsedMilliseconds);

        return order;
    }
}

Sampling and error guarantee

config.SampleRate = 0.1; // keep 10% of traces
Error spans are always exported, even when the parent trace falls outside the sample ratio. The SDK uses a custom ErrorAlwaysOnSampler + ErrorSpanProcessor pair — no configuration required.

Disabling in tests

// In test setup or appsettings.Testing.json
config.Enabled = false;
// or: TRACELIT_ENABLED=false

GitHub

Source code and issue tracker: github.com/Tracelit-AI/tracelit-dotnet