OpenTelemetry Visual Handbook · lab

The span you forgot to end is the one you needed

The payment span is in the backend, root of nothing, pointing at a parent that does not exist. The checkout span it belonged to never arrived: an early return skipped span.end(), and nothing complained.

Three calls do almost all manual instrumentation: startSpan, setAttribute, end. The rules between them are few and strict — a span leaves when it ends, nothing sticks after it ends, and a child only means something if its parent arrives too. Watch the handler run, then edit it.

Break it

  1. Comment out line 6, span.end(), and run to the end. The child arrives an orphan; checkout is still open in memory and is never exported.
  2. Run again with every line on, and read line 7. order.total is set after the span ended, so it is dropped — move it above span.end() in your head and the attribute would be there.
  3. Comment out line 5, child.end(). Now the parent arrives and the child never does: the trace looks complete and is missing the payment.
  4. Turn on “put the order id in the span name”. The warning appears: each order becomes a new operation. The id was already an attribute — that is where it belongs.

Predict before you look

Answer first, then try it in the editor.

A handler starts a parent span, starts and ends a child inside it, and then returns early without calling end() on the parent. What does the backend receive?

Commit to an answer first. You cannot change it afterwards.

What people get wrong

Each row is a belief the editor is built to take apart. The right column is the specification, with the link.

What people believe What the spec says
A span is sent when it starts, and updated as it goes. The span processor receives a span on end(). Until then it is an open record in process memory; a span that never ends is never exported. source
You can add attributes to a span any time, even after it ended. After end(), the span is no longer recording: calls that change it, setAttribute included, are ignored. source
Put the order id in the span name so you can find the trace. Span names should be low-cardinality: they name a class of operation. Per-request identifiers belong in attributes, where they can be searched without making each request its own operation. source

Where this connects

Anatomy of a trace is why the orphan still looks like a tree: the backend builds from what arrived. Cardinality and the bill is the price of an id in the wrong place, and A log that knows its trace needs the span you start here to be the active one.

Check your understanding

The assessment for this lab has not been authored yet.

Continue to the handbook assessment →