Tracing
The trace viewer shows where the time went in a request that crossed many services. Give it a trace exported from OpenTelemetry, Zipkin or Jaeger and every unit of work - every span - is a bar on one time axis in its place in the call tree, coloured by service, with its failures and events marked; drag across the overview to zoom into a stretch of time.
The critical path - the chain of work that actually decided the request's duration - is marked under the bars, with each span's own time and its time on the path, so it is clear what to speed up. A flame graph, figures by service and operation, the service map, and two runs of the same request compared span by span. Traces of tens of thousands of spans scroll smoothly; nothing leaves the page.
A slow checkout
Checkout requests at a fictional shop, twelve services deep, as an OpenTelemetry export, with a normal run as the baseline. The slowest waited on the bank: see "Where the time went", choose the failed call for its exception, then open Compare to see exactly what changed against the baseline.
Get the code
<script src="/assets/bmx-components.min.js"></script>
<bmx-trace-viewer id="tv-checkout" style="inline-size: 100%; --bmx-trace-viewer-height: 26rem"></bmx-trace-viewer>
<script>
const traceViewer = document.getElementById('tv-checkout');
traceViewer.data = [ /* your data */ ];
</script>
From Zipkin, in the flame graph
A search request traced by Zipkin - the format service meshes such as Istio and Linkerd emit - shown in the flame graph, where callers sit above what they called. Use the arrow keys to move through it and Enter to open a span on the timeline.
// Node 18 or later: the tracing engine, from the Gold package.
import { readTraces, serviceStats, compareTraces, waterfallSvg } from './dist/node/bmx-trace-viewer.mjs';
// In an incident review: the slow trace against last week's normal run, and a picture for the write-up.
const [slow] = readTraces(await readFile('slow-trace.json', 'utf8')).traces;
const [normal] = readTraces(await readFile('baseline.json', 'utf8')).traces;
const changes = compareTraces(normal, slow).rows.filter(r => r.kind !== 'same');
console.table(serviceStats(slow));
await writeFile('incident-trace.svg', waterfallSvg(slow, { title: slow.title }));