What Is a Trace ID?
Last verified on Nov 8, 2026.
A trace ID is the identifier shared by every span in one distributed trace. Services pass it along with the request, so every operation the request triggers can be found by searching for that one value. Put it in your log lines and a log search becomes a way to pull up the full story of a request.
What a Trace ID Looks Like
The W3C Trace Context standard defines it as a 16-byte array, written as 32 lowercase hexadecimal characters. All zeros is invalid, and a service that receives a traceparent header with an invalid trace ID must ignore the header. Here is a complete header:
traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
| | | |
| trace ID (32 hex) | trace flags
version parent ID (16 hex)The middle field of the header is the 8-byte ID of the calling span, which becomes the parent of the next one. OpenTelemetry's trace documentation shows the same relationship in span data: every span in the trace carries the same trace_id, a child carries its parent's span_id as parent_id, and the root span has no parent.
Trace ID vs Span ID vs Request ID
Not every platform ID is a W3C trace ID. An AWS Application Load Balancer writes X-Amzn-Trace-Id with a Root field made of a version, an 8-digit epoch time, and 24 hex digits, which is a different shape. See correlation ID for how these edge IDs fit with trace IDs.
Getting the Trace ID into Your Logs
OpenTelemetry's log data model has optional TraceId and SpanId fields, and says TraceId SHOULD be set whenever SpanId is. For Node.js, the OpenTelemetry pino instrumentation adds trace_id, span_id, and trace_flags to any record written inside a span. If you manage the logger yourself, a mixin does the same job. This ran against pino and the OpenTelemetry Node tracer:
const pino = require('pino')
const { trace } = require('@opentelemetry/api')
const logger = pino({
mixin() {
const span = trace.getActiveSpan()
if (!span) return {}
const { traceId, spanId, traceFlags } = span.spanContext()
return { trace_id: traceId, span_id: spanId, trace_flags: '0' + traceFlags.toString(16) }
},
})Inside an active span, logger.info({ order_id: 'o_123' }, 'charging card') writes:
{
"level": 30,
"trace_id": "fccb5187901fc3f49018c3f9164bb62c",
"span_id": "a99b79ab96f7e479",
"trace_flags": "01",
"order_id": "o_123",
"msg": "charging card"
}Outside a span, the mixin adds nothing, which is the first thing to check when a log line has no trace ID. The Pino logger guide covers the rest of the setup, and the OpenTelemetry Node.js guide covers tracing.
Common Problems
- A new trace starts at every hop. The caller did not send
traceparent, a proxy dropped it, or the value was malformed. The spec says to restart the trace when the header cannot be parsed. - Logs have no trace ID. The log call ran outside an active span, often in a callback that lost context.
- IDs from outside your system. OpenTelemetry advises caution with incoming context, because forged trace headers can pollute your traces. Consider ignoring them at your public edge.
- A trace ID with no spans behind it. The trace flags carry the caller's sampling recommendation, and flag
00means the caller did not record the trace. The ID still appears in logs. See trace sampling. - Uppercase hex. The header format is lowercase.
Trace IDs in Sazabi
Sazabi, an AI-native observability and security platform, stores each OpenTelemetry span as a searchable record that carries its trace and span IDs, and its docs say you can search logs by trace ID to pull spans and correlated log lines together. Sazabi ingests OpenTelemetry metrics (Prometheus metrics through an OpenTelemetry Collector) and OTLP traces through the same intake as your logs. It stores each metric data point and each span as a log record that its agent queries alongside your logs, so there is no separate metrics store to run. See sending traces for setup, and use trace IDs to follow up on latency spikes or tail latency.
Frequently Asked Questions
What is a trace ID in simple terms?
A label attached to one request so every service, span, and log line that touched it can be found together.
How long is a trace ID?
In the W3C Trace Context format, 16 bytes written as 32 lowercase hexadecimal characters. A value of all zeros is invalid.
What is the difference between a trace ID and a span ID?
The trace ID is shared by every span in the request. A span ID identifies one operation inside it and is 8 bytes, or 16 hex characters.
How do I add the trace ID to my logs?
Read the active span from your tracing library when you write each log line and add its trace and span IDs as fields. OpenTelemetry instrumentation for common loggers does this for you.
Sources
- The trace ID is a 16-byte array written as 32 lowercase hex characters; all zeros is invalid and a traceparent with an invalid trace ID must be ignored; the parent-id field is 8 bytes (accessed Nov 8, 2026)
- Every span in a trace shares one trace_id; a root span has no parent ID; span context holds the trace ID, span ID, trace flags, and trace state (accessed Nov 8, 2026)
- Log records have optional TraceId and SpanId fields; if SpanId is present TraceId SHOULD also be present (accessed Nov 8, 2026)
- The pino instrumentation adds trace_id, span_id, and trace_flags to log records written inside a span (accessed Nov 8, 2026)
- opentelemetry.trace.getActiveSpan() returns the active span in JavaScript (accessed Nov 8, 2026)
- An Application Load Balancer uses its own X-Amzn-Trace-Id header with a Root field of 24 hex digits plus an epoch time (accessed Nov 8, 2026)
- The Heroku router generates an X-Request-ID per HTTP request to correlate router logs with dyno logs (accessed Nov 8, 2026)
- Sazabi stores each span as a record with its trace and span IDs and lets you search logs by trace ID to pull spans and correlated log lines together (accessed Nov 8, 2026)