Migrating Traces
Overview
This section walks you through migrating distributed traces from Tempo to OpenObserve. You will:
- Assess how traces currently reach Tempo
- Identify the migration path for each source type
- Update configs to point at OpenObserve
- Validate that traces are flowing correctly
Trace migration is typically the easiest signal to migrate. Most modern setups already use OTLP to send traces to Tempo, so migration is often just changing the endpoint URL.
Step 1: Assess Your Current Trace Sources
Check how traces currently reach Tempo. Common setups:
- OTel Collector forwarding OTLP spans to Tempo
- Application SDKs (OpenTelemetry SDK for Go, Java, Python, Node.js, etc.) sending directly via OTLP
- Jaeger Agent or Jaeger Collector → Tempo
- Zipkin → Tempo via the OTel Collector
To see what's sending traces, query Tempo or look at your collector config for exporters pointing to port 4317 (OTLP gRPC) or 4318 (OTLP HTTP).
Step 2: Categorize Your Sources
| Source Type | Migration Path |
|---|---|
OTel Collector with otlp exporter to Tempo |
Update OTLP exporter endpoint |
| Application SDK sending OTLP directly to Tempo | Update SDK endpoint config |
| Jaeger Agent / Jaeger Collector | See dedicated guide |
| Zipkin | See dedicated guide |
Step 3: Migrate Each Source
From OTel Collector
This is the most common setup. The OTel Collector receives traces and forwards them to Tempo using the otlp exporter.
Current config:
Copy the exact updated configuration from the Data Sources UI in OpenObserve.

Send all signals through one exporter
If you're already migrating metrics or logs, you can consolidate all signals (metrics, logs, traces) into a single otlphttp/openobserve exporter — one endpoint, one auth header, all signals.
From Application SDKs
If your application sends traces directly to Tempo using an OpenTelemetry SDK, only the endpoint URL needs to change — no code changes required. See the dedicated guides for complete configuration examples per language:
- Go traces ingestion guide
- Node.js traces ingestion guide
- Python traces ingestion guide
- Rust traces ingestion guide
From Jaeger
For detailed steps on migrating from Jaeger to OpenObserve, see the dedicated guide:
Dedicated guide: Jaeger → OpenObserve
From Zipkin
If applications use older Zipkin SDKs, use the OTel Collector as a protocol translation layer - no application code changes needed:
receivers:
zipkin:
endpoint: 0.0.0.0:9411
exporters:
otlphttp/openobserve:
endpoint: http://openobserve:5080/api/default
headers:
Authorization: "Basic <base64-creds>"
service:
pipelines:
traces:
receivers: [zipkin]
processors: [batch]
exporters: [otlphttp/openobserve]
When you're ready, consider switching the SDKs themselves to OpenTelemetry - the Jaeger project itself recommends this.
Step 4: How to Verify
Check in the UI
- Open the OpenObserve UI → Traces in the left sidebar.
- Select a trace stream and set a time range
- Filter by
service.nameto find your services. - Click into a trace to verify spans, durations, and attributes are intact.
OpenObserve Traces Explorer — verify traces are flowing after migration
OpenObserve trace detail view showing spans and timing
Troubleshooting
- No traces visible: Check that the OTel Collector is running and the exporter shows no errors in its logs. Confirm the endpoint URL and auth header are correct.
- Spans missing attributes: If you switched from gRPC to HTTP, confirm you're using the correct port (
5081for gRPC,5080for HTTP). - Service not appearing: Ensure your spans have the
service.nameresource attribute set — this is required for traces to appear in the service list. - Auth errors (401): Regenerate the Base64 credential string.
Next Steps
- Migrating Logs — migrate your log sources next
- OpenObserve Traces Documentation — exploring traces, filtering spans, and configuring trace settings in the UI
Back to Overview | Previous: Migrating Metrics | Next: Migrating Logs