---
title: Tracing
description: Distributed tracing via OpenTelemetry — export the gateway's spans to an OTLP collector behind observability.tracing.
---

# Tracing

When enabled, Octopus exports its `tracing` spans to an OpenTelemetry collector
over **OTLP** (gRPC). Tracing is **off by default**.

## Enabling

```yaml
observability:
  tracing:
    enabled: true
    jaeger_endpoint: http://localhost:4317 # an OTLP/gRPC endpoint
```

| Field | Type | Default | Effect |
| --- | --- | --- | --- |
| `observability.tracing.enabled` | boolean | `false` | When `true` (and an endpoint is set), installs a batched OTLP span exporter. |
| `observability.tracing.jaeger_endpoint` | string \| null | none | The **OTLP** endpoint to export to (gRPC, e.g. `http://localhost:4317`). |

<Callout type="warn">
  Despite the field name, `jaeger_endpoint` is treated as an **OTLP** endpoint
  (default OTLP/gRPC port `4317`), not the legacy Jaeger Thrift endpoint (`14268`).
  Modern Jaeger (≥ 1.35) accepts OTLP directly, so point this at your collector's
  OTLP receiver. If `enabled` is `true` but no endpoint is set, no exporter starts.
</Callout>

## What is exported

The gateway's internal spans and events (request handling, proxying, discovery,
lifecycle) are exported as OpenTelemetry spans through a batched OTLP exporter on
the Tokio runtime. Pending batches are flushed on graceful shutdown.

<Callout type="info">
  **W3C trace-context propagation to upstreams is not yet wired** — the gateway
  exports its own spans but does not currently inject `traceparent` headers into
  proxied requests, so upstream spans won't automatically join the gateway's trace.
</Callout>

## Related

- [Logging](/docs/octopus/observability/logging) — the same `tracing` subscriber drives both.
- [Configuration → Observability](/docs/octopus/configuration/observability) — the `tracing` block schema.
