OpenTelemetry Visual Handbook · phase 02 · lab

The wire never says
“name”

An SDK holds a span as an object. To reach the Collector, that object becomes an ExportTraceServiceRequest in protobuf. Field names never travel. Each field goes as a number and a wire type, then its value.

The bytes here come from a real encoder that uses the field numbers of opentelemetry-proto. Change the span in the simulation and every byte is recomputed.

173 B protobuf
485 B OTLP/JSON
0000
0010
0020
0030
0040
0050
0060
0070
0080
0090
00a0

Pick a byte or a field. The key and length bytes are outlined; the rest is the value.

Break it, one byte at a time

  1. Set status_code to 127, then 128. 127 fits in one varint byte. 128 needs two. A varint's size depends on the value, not on the type.
  2. Tick “has a parent span”. Field 4 (parent_span_id) appears, 8 raw bytes plus key and length. A root span simply omits it. Protobuf has no null.
  3. Add the user.id attribute. Every attribute is a nested KeyValue message, and the key string travels in full every time. This is the byte-level cost of the attribute bill in Cardinality and the bill.
  4. Click the first byte, 0a. Field 1, wire type 2: resource_spans. Every message the span sits in starts with a key and a length.

Where this connects

The 16 bytes of trace_id are the same id that traceparent carries as 32 hex characters between services. In Anatomy of a trace, the backend joins spans into a trace by that id. The otlp receiver in The Collector pipeline decodes these bytes. The Agent or gateway decision is about where they travel, over gRPC connections that stay open. trace.proto → · protobuf encoding →

The boundary of this experiment

One request, one resource, one scope, one span. The encoder writes only the fields used here. Status, events, links, trace state and dropped counts are not written, and neither are the gRPC frame and the HTTP/2 headers around the message. JSON size is the compact JSON.stringify of the same request. A real OTLP/JSON exporter can differ by a few bytes.

The same span is sent as OTLP/JSON and as OTLP protobuf. Roughly how much smaller is the protobuf?

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