Tracing

Composable primitives for distributed-trace views built on the shared design system

import { Trace } from 'ui-patterns/Trace'

Trace.Root indexes a list of OpenTelemetry-style spans and shares the result with the parts inside it. Trace.Waterfall is the layout container and measures its width so time can be mapped to pixels. Trace.Ruler draws the time axis and Trace.Grid draws the vertical gridlines below it, and Trace.Cursor draws the live cursor. The waterfall has two columns: the tree (treeWidth) and the timeline. The children of Trace.Ruler render at the right end of the ruler's tree cell, next to the "Span" label.

Waterfall and Ruler

The ruler adapts its ticks to the visible range. While a trace is live (any span has no end), Trace.Cursor also draws a line at nowMs from the top of the ruler to the bottom of the waterfall, with a dot on the ruler's bottom edge. Pass nowMs on the trace to pin it, and minRangeMs to keep a minimum visible duration while live.

Loading...
import { Trace, type Span, type TraceData } from 'ui-patterns/Trace'
 
function span(
  id: string,
  parentId: string | null,
  name: string,
  startMs: number,
  endMs: number | null
): Span {
  return {
    id,
    parentId,
    traceId: 'demo',
    name,
    startMs,
    endMs,
    status: 'ok',
    attributes: {},
    events: [],
  }
}
 
const finished: TraceData = {
  spans: [
    span('root', null, 'POST /checkout', 0, 480),
    span('auth', 'root', 'auth.verify', 8, 62),
    span('db', 'root', 'db.query', 70, 410),
  ],
}
 
const live: TraceData = {
  nowMs: 1500,
  spans: [
    span('root', null, 'GET /export', 0, 1240),
    span('db', 'root', 'db.query', 100, 900),
    span('stream', 'root', 'stream.write', 1000, null),
  ],
}
 
export function TraceWaterfallDemo() {
  return (
    <div className="flex w-full flex-col gap-8">
      <Trace.Root trace={finished}>
        <Trace.Waterfall treeWidth={120}>
          <Trace.Ruler />
          <Trace.Grid />
          <Trace.Cursor />
          <div className="h-24" />
        </Trace.Waterfall>
      </Trace.Root>
 
      <Trace.Root trace={live} minRangeMs={3000}>
        <Trace.Waterfall treeWidth={120}>
          <Trace.Ruler />
          <Trace.Grid />
          <Trace.Cursor />
          <div className="h-24" />
        </Trace.Waterfall>
      </Trace.Root>
    </div>
  )
}