Softanza
DémarrerEnglish
Softanza
Recherche · narration

The Tail

P4 admitted a limit honestly: alerts did not carry the trace ids of the requests that tripped them, because nothing captured traces per request. P2 owed the OTLP metrics batch a sibling for spans. P7 pays both debts -- and rules on the two items that are not debts at all.

par Mansour Ayouni · dans le dépôt depuis le 2026-07-29 · série · la série performance · domaine Performance

Cet article est écrit en anglais, comme la bibliothèque.

Every request gets a trace identity, the alert names its trips -- and spans ship as one batch

Every code block below is real, and every output block is its actual output (the run lives in base/test/perf/_tail_narration_demo.ring; the guard suite is base/test/perf/tracing_tail_narrated.ring, 26 assertions). Performance system P7, the deferred tail -- doc/design/SOFTANZA_PERF_SYSTEM.md.

What was owed

A trace identity on every request

Enable tracing on the monitor before Observe() (the server takes its copy at that moment), and every request gets a W3C trace identity, recorded in an engine trace haro -- the same copy-proof design as every other perf store, which is the point: the server's face records, and every other face reads the same truth:

Haro
oMon.EnableTracing(64)          # BEFORE Observe
oSrv.Observe(oMon)
# ... three requests ...
aT = oMon.RecentTraces(3)       # read through OUR face

illustration

Sortie promise
traceparent: 00-b2e6b38e093cf3698ec96a1794e02caa-46154b26907506e1-01
258483c8ac481058348af70b5032b01c  /order  200  6.09 ms
d58848679f41bda4b23275f3b20de089  /order  200  0.57 ms
b2e6b38e093cf3698ec96a1794e02caa  /order  200  0.97 ms

Each request opened its own trace (three distinct ids), each row knows its path, outcome, and cost, and the response echoes the traceparent header so the caller can correlate. The haro is bounded: past capacity, the oldest rows give way -- constant memory forever, like everything else in the system.

Joining the caller's trace -- watch the ids

When a request arrives already carrying a valid traceparent, the server does not open a new trace -- it joins the caller's, as a child span. Read the two headers closely:

caller sends : 00-3baa1cd12fe2c9dc1cc9639a48d8ba0a-149cb59fc39c83f3-01
server echoes: 00-3baa1cd12fe2c9dc1cc9639a48d8ba0a-5555f2bf48548689-01

Same traceId, new spanId -- textbook W3C parent/child, generated by the engine's tracectx. A phone app, this server, and a downstream service its handler calls (hand TraceParent() onward) all land in one tree in any tracing backend.

The alert names its trips

The P4 debt, paid: the sentinel's black box -- already photographing senses and metrics at breach time -- now includes the trace ids of the requests nearest the breach:

Haro
gL.Set(900)
oSent.Check()
aBox = oSent.LastBlackBox()

illustration

Sortie promise
breach: value-queue.depth-under-100
the trips nearest the breach:
  258483c8ac481058348af70b5032b01c  /order -> 200
  d58848679f41bda4b23275f3b20de089  /order -> 200
  b2e6b38e093cf3698ec96a1794e02caa  /order -> 200
  3baa1cd12fe2c9dc1cc9639a48d8ba0a  /order -> 200

This is the bridge from "the p95 is bad" to "these requests are why": paste any of those ids into Jaeger or Tempo (the same ids travelled the wire in the response headers) and the 3 a.m. investigation starts from evidence, not archaeology.

Spans ship as one batch

P0's stopwatch exports one span; a real trace is many. stzOtelBatch renders the full OTLP resourceSpans envelope -- the exact JSON a collector ingests at /v1/traces:

Haro
w2.JoinTrace(w1.TraceParent())
oB = StzOtelBatch("restolean")
oB.AddSpan(w1).AddSpan(w2)
? left(oB.ToJson(), 200) + "..."

illustration

Sortie promise
{"resourceSpans":[{"resource":{"attributes":[{"key":"service.name","value":{"stringValue":"restolean"}}]},"scopeSpans":[{"scope":{"name":"softanza.perf"},"spans":[{"name":"import-orders","traceId":"17...
spans: 2 ; shared traceId appears 2x

The joined spans share one traceId inside the shipment, so the collector reassembles the tree. With this, the interop table closes: spans (single and batched), metrics (Prometheus + OTLP), SLA verdicts (the CI gate) -- perf data speaks the industry's formats in and out.

Two items ruled, not built

An honest tail states what it deliberately leaves. The counting-allocator engine-heap stats: every engine module allocates through its own c_allocator; counting them means rerouting every module's allocator -- that is a project, not a tail item, and the operational question it would answer ("is the process growing?") is already answered by RSS, peak, and the series trend. Ruled: deferred until a concrete need names it. The driven-load R-vs-X harness: the interesting knee in the R-vs-X curve comes from queueing -- concurrent arrivals -- and this in-process serial harness cannot produce them; a multi-process load driver belongs with the cluster's infra-gated work. Snapshot()/Curve() remain for load levels you drive yourself.

The performance system is complete -- P0 through P7, eight guards, 283 assertions, every phase narrated with real output. The app that runs is the app that knows how it runs, can prove who asked, and ships what it knows in any tongue the industry speaks.

Prouvé par

L'article nomme ces gardes de scénario de la bibliothèque :

Citer

Mansour Ayouni. « The Tail ». Softanza narrations, 2026. https://mayouni.github.io/stzsite/fr/narrations/stz-perf-tracing-tail-narration.html

Exécuté au nom de Haro le 2026-10-08 20:42 dans la bibliothèque au commit 4a184e6f0, bloc après bloc dans un seul processus : 0 bloc(s) sur 3 ont tenu leur promesse ; les autres sont des illustrations. Le code des articles est du code Haro. Là où un article a été écrit avant que la langue prenne son nom actuel, le nom a été changé et rien d'autre. Genre, domaine et série lus dans le nom du fichier, année tirée du premier commit : dérivés, jusqu'à ce que l'article porte son propre en-tête. Le fichier sur GitHub(s'ouvre dans un nouvel onglet)