Traces and Spans: From Events to Structure
Event envelopes capture individual facts. Traces explain how those facts relate.
A trace represents the full lifecycle of a request. A span represents a unit of work within that lifecycle.
The earlier contract request produces a trace that can be represented as:
Trace: Contract Analysis Request
│
├── Span: Build Prompt
│ └── attributes: {template: "risk_summary_v2"}
│
├── Span: Retrieval Query
│ └── attributes: {index: "contracts_v1", top_k: 5}
│
├── Span: LLM Completion
│ └── attributes: {model: "gpt-4", prompt_tokens: 820, latency_ms: 1340}
│
├── Span: Guardrail Check
│ └── attributes: {policy: "hallucination_v1", result: "failed"}
│
└── Span: Response Formatting
Each span records timing and attributes. More importantly, each span is connected through a parent-child relationship, forming a structured execution tree.
Context propagation ensures this structure persists across boundaries. As execution moves between threads or services, trace identifiers are carried forward, preserving continuity.
When a span completes, it is deterministically converted into an event envelope. Every span produces exactly one envelope. This one-to-one mapping ensures that execution and recorded data remain perfectly aligned.
Traces provide structure. Envelopes provide persistence. Together, they form a complete, queryable representation of execution.