High cardinality is free here
A span is already one row per request per hop, so attaching the customer id adds bytes to a row that was being written anyway and multiplies nothing — the exact opposite of a metric label, where each distinct value creates another series that lives for the whole retention window.
Every hop now produces a span in the right trace, including across the queue. A span is a row that is being written anyway — so what else can ride on that row?
Scene 05
High cardinality is free here
- Watch
- Try it
- Predict
- Capture
A span is already being written for this hop — so what else can ride on it, and what does riding on it cost? Watch one payments span fill with rows. Each row is a key and a value; the meter at the foot of the card climbs as they land. Keep one eye on the counter to the right of the card: it stays at 1 the whole time, because this is one row, not a series. At the end, one more row lands underneath the others, with a timestamp on it.
Highlighted lines are the ones running in the diagram right now.
def set_attribute(self, key, value):# keys: lowercase, dot-delimited; your own# take a com.* prefix — otel.* is reservedif is_credential(key, value):value = redact(value) # url.full# attr_count_limit defaults to 128if len(self.attributes) >= attr_count_limit:self.dropped_attributes_count += 1return # silent, but countedself.attributes[key] = valueself.bytes += len(key) + len(value)
def add_event(self, name, attributes, at):if len(self.events) >= event_count_limit:self.dropped_events_count += 1returnself.events.append(Event(name, at, attributes))# no new span_id, no new parent_span_id —# the trace keeps the shape it already haddef record_exception(self, err):self.add_event("exception",exception_attrs(err), clock.now())
def on_charge(span, customer_id):# the same value, on both sides at oncespan.set_attribute("com.shopfront.customer_id", customer_id)charges.add(1, {"customer_id": customer_id})# what charges.add does in the metrics SDKdef add(self, n, labels):key = fingerprint(labels)if key not in self.series:self.series[key] = new_series(key)self.series[key].value += n
Where this sits in Build a distributed tracing system (Jaeger / Zipkin style)
Scene 05 of 17, in the Carry it act — The header, the queue that drops it, what rides along.. A span is already one row per request per hop, so attaching a customer id adds bytes to a row that was being written anyway and multiplies nothing — the exact opposite of a metric label.
Up next. Attributes are nearly free per span, but a span itself is not free, and there is one per hop per request. What does keeping every one of them actually cost?
All 17 scenes in Build a distributed tracing system (Jaeger / Zipkin style) · Every curriculum