What is W3C Trace Context?
The W3C Trace Context specification is a standard for propagating distributed tracing context across service boundaries. It defines HTTP headers that allow you to track requests as they flow through multiple services in a distributed system.tctx implements W3C Trace Context Level 2, providing a lightweight, spec-compliant way to handle distributed tracing in your applications.
Why Trace Context Matters
In modern distributed systems, a single user request often touches dozens of services. Without a standardized way to correlate these interactions:- Debugging becomes painful - You can’t track a request’s journey through your system
- Performance analysis is incomplete - You can’t see the full picture of where time is spent
- Different vendors use incompatible formats - Each monitoring tool has its own proprietary format
The traceparent Header
Thetraceparent header is the core of the W3C Trace Context specification. It carries essential information about a trace across service boundaries.
Anatomy of a traceparent
version (2 hex digits)
version (2 hex digits)
The version of the W3C Trace Context specification being used.
- Current version is
00 - Version
ffis invalid (reserved for future use) - Future versions will be backward compatible
00 traceparents and normalizes parsed traceparents to this version.trace-id (32 hex digits)
trace-id (32 hex digits)
A globally unique identifier for the entire trace.
- Must be 32 hexadecimal characters (16 bytes)
- Cannot be all zeros (
00000000000000000000000000000000) - Remains the same for all spans within a single trace
- Generated randomly when starting a new trace
parent-id (16 hex digits)
parent-id (16 hex digits)
A unique identifier for the current operation/span.
- Must be 16 hexadecimal characters (8 bytes)
- Cannot be all zeros (
0000000000000000) - Changes with each child span created
- Becomes the “parent” when passed downstream
flags (2 hex digits)
flags (2 hex digits)
Bit flags that control trace behavior.
- Bit 0 (
0x01): sampled - Indicates whether this trace should be recorded - Bit 1 (
0x02): random - Indicates the trace-id was randomly generated (tctx extension) - Bits 2-7: Reserved for future use
00: Not sampled01: Sampled03: Sampled and random (tctx default)
Working with traceparent in tctx
Creating a new traceparent
By default,
make() creates a traceparent with both the FLAG_SAMPLE (0x01) and FLAG_RANDOM (0x02) flags set, resulting in flags value 03.Parsing an incoming traceparent
Creating child spans
child() method:
- Preserves the
trace_id(keeping the trace intact) - Generates a new random
parent_id(identifying this specific operation) - Copies all flags from the parent
Sampling control
tctx provides utilities to control sampling:According to the W3C spec, you should create a child span (
.child()) before modifying sampling flags to ensure proper trace hierarchy.The tracestate Header
Whiletraceparent provides standardized trace correlation, tracestate allows vendors and applications to attach additional metadata to traces.
Ring Buffer Design
tracestate is implemented as a ring buffer with the following characteristics:- Maximum of 32 key-value pairs
- Keys can be up to 256 characters
- Values can be up to 256 characters
- Most recently updated entries appear first
- When full, the oldest entry is removed when adding new ones
Key Format
Keys must follow one of two formats:-
Simple keys:
[a-z0-9][_0-9a-z-*/]{0,255} -
Tenant keys:
[a-z0-9][_0-9a-z-*/]{0,240}@[a-z][_0-9a-z-*/]{0,13}
Tenant keys (with
@) allow multi-tenant systems to namespace their trace data.Value Format
Values must:- Contain only printable ASCII characters (space through
~) - Not contain commas (
,) or equals signs (=) - Not end with trailing whitespace
- Match pattern:
/^[ -~]{0,255}[!-~]$/
Working with tracestate in tctx
Creating a new tracestate
Parsing an incoming tracestate
You should only parse
tracestate if you successfully parsed a valid traceparent header, as per the W3C specification.Updating tracestate
set():
- If the key exists, its value is updated and it moves to the front
- If the key is new and there’s space, it’s prepended
- If the ring buffer is full (32 entries), the oldest entry is removed
Complete Example
Here’s how to use both headers together in a real-world scenario:Validation and Error Handling
tctx performs robust validation on both parsing and creation:traceparent Validation
Theparse() function returns null if:
- The header is too short (< 55 characters)
- Contains invalid characters (underscores, non-hex)
- Version is
ff(invalid/reserved) - trace-id is all zeros
- parent-id is all zeros
- Flags are not exactly 2 hex digits
tracestate Validation
Theset() method throws TypeError if:
- Key doesn’t match allowed patterns
- Value contains commas or equals signs
- Value is longer than 256 characters
- Value ends with whitespace
Performance
tctx is designed for high performance with minimal overhead:- 12.47x faster than alternatives for creating traceparents
- 11.29x faster for creating child spans
- Uses cryptographically secure random generation
- Zero dependencies beyond
@lukeed/csprng - Optimized string operations and validation