Skip to content

Repository files navigation

Trace ID Canonicalization Lab

The trace exists. The logs exist. The join says they have never met.

This interactive lab demonstrates a cross-signal correlation failure: a valid 128-bit trace ID is parsed as an integer by a log pipeline and serialized back to hexadecimal without fixed-width padding. Leading zeroes disappear. The trace store retains the canonical ID, the log index stores a shorter string, and an exact join silently orphans every log in that cohort.

The executable model is written in Hy, a Lisp dialect embedded in Python. A dependency-free Python HTTP adapter runs the model and serves a responsive investigation workbench with OTLP-shaped traces, metrics, and logs.

Default experiment

The model balances 16,000 trace IDs across all sixteen possible first hexadecimal nibbles:

Observation Result
Valid traces beginning with 0 1,000
Affected share 6.25%
Logs per trace 4
Orphaned logs 4,000
Exact correlation coverage 93.75%
Hidden incident traces at a 25% incident rate 250

The fleet-wide 93.75% can look healthy. The 0… cohort has 0% exact log-to-trace correlation.

The representative identity makes the transformation explicit:

canonical trace:  00a123456789abcdef0123456789abcd  (32 nibbles)
numeric log ID:     a123456789abcdef0123456789abcd  (30 nibbles)
fixed-width log:  00a123456789abcdef0123456789abcd  (32 nibbles)

The number denotes the same magnitude, but identifiers are not magnitudes. They are byte sequences with a canonical wire representation.

Why the format matters

W3C Trace Context defines trace-id as exactly 16 bytes represented by 32 lowercase hexadecimal characters. OpenTelemetry's Logs Data Model stores TraceId as a byte sequence, and OTLP JSON represents trace and span ID byte arrays as hexadecimal strings.

The malformed log record in this lab is intentionally visible in the payload. It represents the bad string produced by a legacy log ETL boundary; it is not presented as a valid OTLP trace ID.

Why telemetry.sh helps

Request rates, exporter success, and trace counts can all remain normal. Diagnosing the failure requires correlating representation evidence:

  • canonical and indexed trace ID widths;
  • unmatched log counts grouped by ID length;
  • exact join coverage in basis points;
  • the first-nibble cohort boundary;
  • warning logs that carry both the expected and indexed values;
  • a trace event describing the missed correlation;
  • recovered joins after fixed-width encoding.

The lab emits:

lab.correlation.orphaned_logs
lab.correlation.join_coverage
lab.trace_id.numeric_width
lab.correlation.repair_recovered_logs

Telemetry.sh can keep those metrics beside the example trace and both log representations, turning “logs are missing” into a precise encoding diagnosis.

Run locally

Requirements:

  • Python 3.9 or newer
  • Hy 1.3
  • Node.js (syntax check only)
  • GNU Make
python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
make check
make run

Open http://127.0.0.1:3000.

Useful endpoints:

GET /healthz
GET /api/simulate
GET /api/telemetry

Every control is also a query parameter:

/api/simulate?traceCount=32000&logsPerTrace=6&coercionPercent=50&incidentPercent=40&leadingZeroNibbles=4

Run with Docker

docker compose up --build

The image runs the complete model and test suite during its build, then starts the service as an unprivileged user.

Repair pattern

Do not move trace IDs through numeric columns or numeric JSON values. Preserve the original 16-byte value when possible. At text boundaries:

  1. encode all 16 bytes;
  2. emit exactly 32 hexadecimal characters;
  3. normalize to lowercase where required by the target format;
  4. validate width and content before indexing;
  5. monitor correlation misses grouped by encoded width.

Padding a value after a known, lossless integer conversion can recover leading zeroes:

canonical = format(trace_id_integer, "032x")

Preserving the byte sequence end to end is safer because it makes lossy numeric interpretation impossible.

Project layout

model/canonicalize.hy  executable Hy model
service/lab.py         model adapter and correlated telemetry
service/server.py      dependency-free HTTP and static service
public/                investigation workbench
tests/                 model, telemetry, and static checks

License

MIT

About

Interactive Hy lab: numeric trace ID coercion strips leading zeroes and silently breaks log-to-trace correlation.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages