Skip to content

Migrating Traces

Overview

This section walks you through migrating distributed traces from Datadog APM to OpenObserve. You will:

  1. Assess how traces currently reach Datadog
  2. Choose between keeping dd-trace SDKs (translate via OTel Collector) or switching to OpenTelemetry SDKs
  3. Update configs so traces flow into OpenObserve
  4. Validate that traces are intact

The fastest path is to keep your dd-trace-* SDKs unchanged and use the OpenTelemetry Collector's datadog receiver as a translation layer. No application redeploys, no code changes.

Step 1: Assess Your Current Trace Sources

Datadog APM traces typically reach Datadog one of two ways:

  • dd-trace-* SDK in the app sends spans to the local Datadog Agent on port 8126 (Datadog trace intake protocol). The Agent batches and forwards to Datadog SaaS.
  • OpenTelemetry SDK in the app sends OTLP spans to the Datadog Agent (Datadog has accepted OTLP since 2023) or directly to Datadog via OTLP HTTP.

Note the SDKs and instrumented services. You can usually find them by grepping deployment manifests for dd-trace-*, DD_AGENT_HOST, DD_TRACE_*, or OTEL_EXPORTER_OTLP_ENDPOINT.

Step 2: Categorize Your Sources

Source Type Migration Path
dd-trace SDK → Datadog Agent on 8126 Route Agent (or apps) at the OTel Collector datadog receiver
OpenTelemetry SDK → Datadog Agent (OTLP) Switch SDK endpoint to OpenObserve OTLP
OTel Collector with datadog exporter Swap the exporter to otlphttp

Step 3: Migrate Each Source

From dd-trace SDKs

The OpenTelemetry Collector's datadog receiver listens for Datadog APM trace payloads (the protocol that dd-trace-* SDKs and the Datadog Agent both speak) and converts them into OTLP spans.

Collector config:

receivers:
  datadog:
    endpoint: "0.0.0.0:8126"

processors:
  batch:
    timeout: 10s
    send_batch_size: 10000

exporters:
  otlphttp/openobserve:
    endpoint: https://<your-openobserve-host>/api/<org_id>
    headers:
      Authorization: Basic <base64-creds>

service:
  pipelines:
    traces:
      receivers: [datadog]
      processors: [batch]
      exporters: [otlphttp/openobserve]

Two ways to wire it up:

Option A: Point apps directly at the Collector. Set DD_AGENT_HOST/DD_TRACE_AGENT_PORT on each service so dd-trace ships spans to the Collector instead of the Datadog Agent:

DD_AGENT_HOST=otel-collector.local
DD_TRACE_AGENT_PORT=8126

The application code does not change. Only the env vars do. Restart the service to pick up the new agent endpoint.

Option B: Keep the Datadog Agent, repoint it. If many services point at the local Datadog Agent and changing env vars across the fleet is awkward, repoint the Agent's APM forwarder at the local Collector. Because the Agent is already bound to :8126, the Collector's datadog receiver has to listen on a different port. Bind it to :18126:

# OTel Collector
receivers:
  datadog:
    endpoint: "0.0.0.0:18126"
# /etc/datadog-agent/datadog.yaml
apm_config:
  apm_dd_url: http://localhost:18126

The Agent receives dd-trace spans on 8126 as before and forwards them to the Collector on 18126, which translates and ships to OpenObserve.

Send all signals through one Collector

If you're also migrating metrics and logs, you can consolidate everything through a single OTel Collector with one otlphttp/openobserve exporter: one endpoint, one auth header, all signals.

From OpenTelemetry SDKs

If your services already use OpenTelemetry SDKs and ship OTLP, the migration is just an endpoint change. Update the OTEL_EXPORTER_OTLP_ENDPOINT env var (or the equivalent in your SDK config) to point at OpenObserve:

OTEL_EXPORTER_OTLP_ENDPOINT=https://<your-openobserve-host>
OTEL_EXPORTER_OTLP_HEADERS="Authorization=Basic <base64-creds>"
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf

For full per-language examples:

From OTel Collector

If you already run an OpenTelemetry Collector with the datadog exporter shipping to Datadog, replace it with otlphttp pointed at OpenObserve.

Current config:

exporters:
  datadog:
    api:
      key: ${env:DD_API_KEY}
      site: datadoghq.com

Updated config:

exporters:
  otlphttp/openobserve:
    endpoint: https://<your-openobserve-host>/api/<org_id>
    headers:
      Authorization: Basic <base64-creds>

Update the traces pipeline's exporters list to use otlphttp/openobserve and restart the Collector.

Step 4: How to Verify

Check in the UI

  1. Open the OpenObserve UI → Traces in the left sidebar.
  2. Select the trace stream and set a recent time range.
  3. Filter by service.name to find your services. dd-trace's service tag becomes service.name after translation.
  4. Click into a trace to verify spans, durations, and attributes are intact.

Span attribute mapping

When dd-trace spans are translated to OTLP, the following mapping applies:

Datadog field OpenTelemetry attribute
service service.name
resource resource.name (and span name)
operation Span name
env deployment.environment
version service.version
Custom tags Span attributes (same key)

Troubleshooting

  • No traces visible: Check Collector logs for receiver errors and the OTLP exporter for HTTP errors. Confirm endpoint and Authorization header.
  • Service missing from the service list: Ensure spans carry service.name after translation. If dd-trace was misconfigured (DD_SERVICE unset), spans will land but the service list will be sparse.
  • Trace appears split: Check that the trace ID and parent span ID propagation headers (x-datadog-trace-id, traceparent) are flowing through your service mesh / load balancer.
  • Auth errors (401): Regenerate the Base64 credential string and confirm it has no whitespace.

Dual-write during migration

For the same reason you'd dual-write metrics, you can dual-write traces. dd-trace agents ship to the Datadog Agent on 8126, and you can run the OTel Collector on a different port and have applications send to both via env-var per pod / deployment slice. Once dashboards and on-call workflows work against OpenObserve traces, drop the Datadog leg.

Next Steps

Need Help?