OpenTelemetry trace viewer
Open a distributed trace as OTLP/JSON, a Jaeger export or Zipkin v2 JSON and read it as a waterfall with events and errors, a service map, the critical path and self time per service — flag and adjust clock skew, compare two traces span by span, and convert between the formats, all in the browser.
Added
How to use it
A trace viewer for the files you already have — the collector’s file exporter, a Jaeger “Download JSON”, a Zipkin API response — without standing up a tracing backend. Everything runs in this page; nothing is uploaded.
How to use it
Data. Drop, open or paste a trace, or pick an example. The format is detected:
-
OTLP/JSON —
resourceSpans→scopeSpans(or the olderinstrumentationLibrarySpans) → spans, as written by the OpenTelemetry Collector’sfileexporter (one export per line is fine) and sent to/v1/traces. Ids may be hex (as the OTLP/JSON spec says) or base64 (the plain protobuf JSON mapping some SDKs emit); times are Unix nanoseconds; attribute values may be strings, numbers, booleans, arrays or key–value lists.kindandstatus.codemay be numbers or enum names. -
Jaeger JSON — the UI’s download and the query API (
data[].spans,processes,referenceswithCHILD_OFandFOLLOWS_FROM, tags, logs; times in microseconds).span.kind,error=trueandotel.status_codetags become kind and status. -
Zipkin v2 JSON — an array of spans (
localEndpoint.serviceName,parentId,kind, tags, annotations). A shared span (the server half of an RPC that reuses the client’s id) is given its own id under the client, as Zipkin’s UI does.
A file with several traces gets a picker above the tabs. Convert saves the loaded trace in any of the three formats. Trace B (a sample or your own file) is for the Compare tab.
Waterfall. One row per span, indented by parent, coloured by service. ! marks spans with
error status (the bar is outlined red); striped bars are asynchronous — FOLLOWS_FROM
references, consumer spans, or children of a producer — and may legitimately outlive their parent.
Ticks are span events (logs, annotations, exceptions); the dark underline is the critical path.
Drag across the strip above the waterfall to zoom into a time range (tap it to reset), collapse
subtrees with the arrows, and tap a span for its attributes, resource, events, links, self time
and time on the critical path. Search matches names, services, ids, events and attributes; write
key=value to match one attribute (http.response.status_code=503). Errors only and a minimum
duration keep the spans that matter (and their parents). Full screen (F) gives the waterfall the
whole screen.
Clock skew. Spans from different hosts carry different clocks, so a server span can appear to start before the client that called it, or end after it. Such children are listed above the waterfall. Adjust clock skew shifts each offending server span — and everything under it — so it sits centred inside its client parent, splitting the difference as network time each way (or aligned to the parent’s start when the server took longer). This is the idea of Jaeger’s clock-skew adjuster, not its exact code; the original times are back when you untick it.
Service map. Services and the calls between them in this trace: count, errors and mean
duration per edge, dashed for messaging. Client and producer spans that name a peer
(peer.service, db.system, messaging.system, server.address) but have no server span
underneath add a grey “not instrumented” node, so databases, caches and third-party APIs show up.
Critical path. The chain of work that determined the request’s duration, found the way Jaeger UI does: start at the end of the root span and walk backwards; the child that finished last is on the path (children that outlive their parent are clipped to its end); recurse into it, then carry on from that child’s start with the latest child that finished before it; time no child covers belongs to the parent itself. The segments tile the root exactly, so the table’s shares add to 100%. Next to it: self time — a span’s duration minus the union of its children — by service and by operation, which is where the time was spent rather than waited.
Compare. Trace A against trace B, matched by each span’s path of service · operation from the
root (with the occurrence number among same-named siblings), so two runs of the same request line
up although their ids and timestamps differ. Durations, the difference (red slower, green
faster), and spans that only one trace has.
Limits
-
A trace of a few thousand spans draws comfortably; tens of thousands will be slow (the waterfall draws every row).
-
Span links to other traces are listed but not followed. Zipkin has no links or
FOLLOWS_FROM, so converting to it loses them; Zipkin tags are strings. -
The skew adjustment is a heuristic and only moves cross-service server spans.
-
The service map is per trace; it is not an aggregate over many traces like a backend’s dependency graph.
Sources: OpenTelemetry OTLP
JSON encoding and trace semantic conventions (HTTP, RPC, database, messaging attribute names);
Jaeger’s JSON model and UI (critical path: jaeger-ui CriticalPath; clock-skew adjuster);
Zipkin’s v2 API (shared spans).
Related: Agent trace viewer (LLM agent traces, including OTel GenAI spans), PromQL / LogQL playground, latency numbers, queueing, JSON workbench.
Linking to an example
/tools/otel-trace/?<parameters>#<tab> with tab data, waterfall, map, critical or
compare. Links carry the settings and a sample name, never your own traces.
| Parameter | Meaning | Example |
|---|---|---|
|
a sample trace (below) |
|
|
waterfall search |
|
|
errors only ( |
|
|
minimum span duration, ms |
|
|
show the critical path ( |
|
|
adjust clock skew ( |
|
|
trace B for Compare: |
|
example= |
Tab | Shows |
|---|---|---|
|
waterfall |
A checkout across frontend, cart, checkout, payment and email services with Redis, Postgres, Kafka and a retried card-processor call; the email consumer runs after the response (open) |
|
waterfall |
The same trace as a Jaeger export (open) |
|
waterfall |
The same trace as Zipkin v2 (open) |
|
waterfall |
The card processor fails twice and the error propagates to the root (open) |
|
critical |
Critical path and self time of the checkout (open) |
|
map |
The checkout’s service map (open) |
|
waterfall |
The cart service’s clock runs 30 ms fast (open) |
|
compare |
Checkout against a slow run with a cache miss and a slow insert (open) |
For example, ?example=checkout-otlp&q=db.system=postgresql#waterfall
highlights the database call.
Feedback is a gift. Something to improve, a feature to add, or a bug? Tell me.
Runs entirely in your browser; nothing you type leaves this page.