Softanza
DémarrerEnglish
Softanza
Recherche · narration

Labels and Dimensions

The vs-the-field document called flat metric names this system's most consequential absence: http.request.ms measured everything, so "which route is slow?" had no direct answer. P8 closes the gap with the field's vocabulary -- a metric FAMILY is one name plus declared label names, and each label-value combination is a CHILD with its own engine stores:

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

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

One name, many children -- engine-registered, cardinality-bounded, and honest about overflow

Every code block below is real, and every output block is its actual output (the run lives in base/test/perf/_labels_narration_demo.ring; the guard suite is base/test/perf/labels_narrated.ring, 29 assertions). Performance system P8 -- doc/design/SOFTANZA_PERF_SYSTEM.md.

The gap the comparison named

Haro
oF = StzMetricFamily("checkout.ms", :Timer, [ "route", "method" ])
oF.Child([ "/menu", "GET" ]).Record(12)
oF.Child([ "/menu", "GET" ]).Record(18)
oF.Child([ "/pay", "POST" ]).Record(220)
? oF.Child([ "/menu", "GET" ]).ExactPercentile(95)
? oF.Child([ "/pay", "POST" ]).ExactPercentile(95)

illustration

Sortie promise
children     : 3 (incl. the reserved overflow)
/menu p95    : 18 ms
/pay  p95    : 220 ms

A child is a full stzMetric -- exact window percentiles, streaming buckets, rates, trends -- scoped to its label values.

The registry lives in the engine -- the copy law, one level up

The hard problem was not the label syntax; it was Haro's copy-on-assign, one level up from where P2 met it. Children are created dynamically -- a route first hit after the server copied its monitor -- and a Haro-side child registry would fork per copy: the server's face would know routes the user's face never sees. So the child registry is an ENGINE store, like every other perf truth:

Haro
oF2 = oF                                  # a Haro copy
oF2.Child([ "/refund", "POST" ]).Record(77)   # a child born through the COPY
? oF.Child([ "/refund", "POST" ]).Count()     # read through the ORIGINAL

illustration

Sortie promise
born through the copy, seen by the original: 1 sample(s)

Each face keeps only a small reconstruction cache of child wrapper objects -- derived state, rebuilt on miss, never the truth.

Cardinality bounded, overflow visible

The field's label systems have a famous failure mode: an unbounded label value (a user id, a raw URL) mints millions of children and takes the monitoring down with the app. A Softanza family takes its bound at birth and RESERVES an overflow child; when the family is full, new label sets route there -- counted, never silently dropped, and visible in the exposition, which is itself the alarm:

Haro
oB = StzMetricFamilyXT("api.calls", :Counter, [ "user" ], 64, 4)
# alice, bob, carol fit; dave and erin arrive when the family is full
see oB.PromText()

illustration

Sortie promise
# TYPE api_calls_total counter
api_calls_total{user="_overflow"} 2
api_calls_total{user="alice"} 1
api_calls_total{user="bob"} 1
api_calls_total{user="carol"} 1

One TYPE header for the family, one labeled sample line per child -- the exposition format Prometheus scrapes, quantiles merged into the label braces for timers. The OTLP side renders one metric with one data point per child, labels as attributes.

Per-route truth from real traffic

ObserveRoutes() is Observe() plus a timer family http.route.ms labeled [method, route, class] -- one child per route the traffic actually exercises, status-classed (2xx/4xx/5xx) so errors get their own distribution:

Haro
oSrv.ObserveRoutes(oMon)
# ... six real requests across /menu and /order ...
oFam = oMon.MetricQ("http.route.ms")
? oFam.Child([ "GET", "/menu", "2xx" ]).ExactPercentile(95)
? oFam.Child([ "GET", "/order", "2xx" ]).ExactPercentile(95)

illustration

Sortie promise
/menu  p95 : 6.13 ms (3 reqs)
/order p95 : 3.23 ms (3 reqs)

Read that output twice -- it contains a lesson. /order does real work per request; /menu returns a constant string; yet /menu's p95 is higher. The first request of the run landed on /menu and paid the connection warm-up. This is exactly what per-route views are FOR: the aggregate http.request.ms averaged that spike away, and the labeled view surfaces it. (It is also a reminder from the P5 grind: small samples carry their outliers -- judge distributions, not anecdotes.)

The flat instruments stay flat -- http_requests_total renders without braces, byte-identical to P3, and the SLA's well-known subjects still judge them. An SLA judges CHILDREN, not families: asking a family for a single Value() refuses with that guidance.

Where this leaves the comparison

The vs-the-field scorecard moves: labels/dimensions shift from "the biggest gap" to shipped -- with two properties the field's label systems lack (an engine-shared child registry that survives value copies, and cardinality bounded by design with a visible overflow bucket). Still absent, still honest: PromQL-style aggregation ACROSS children (sum by route) is a downstream system's job; label-based SLA selection stays child-explicit.

Prouvé par

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

Citer

Mansour Ayouni. « Labels and Dimensions ». Softanza narrations, 2026. https://mayouni.github.io/stzsite/fr/narrations/stz-perf-labels-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 4 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)