Observability Naming-Konvention
Referenz fuer alle Metric- und Span-Namen im Kumiko Framework und in Features.
Warum das wichtig ist: einmal in Prod emittiert, ist ein Metric- oder Span-Name schwer zu aendern — Dashboards, Alerts und Queries haengen daran. Einheitliche Konvention verhindert, dass jedes Feature seinen eigenen Stil erfindet.
Durchgesetzt wird die Konvention per Runtime-Validation beim Boot (fail fast — analog boot-validation.md).
Metrics
Grundregeln
- snake_case nur. Keine camelCase, keine Dots.
- Prefix:
kumiko_fuer Framework-Metrics,kumiko_<feature>_fuer Feature-Metrics (Framework haengt Prefix automatisch an — siehe unten). - Unit gehoert in den Namen, nicht ins Label.
- Typ-Suffix folgt Prometheus-Standard.
Typ-Suffixe
| Metric-Typ | Suffix-Muster | Beispiel |
|---|---|---|
| Counter | <noun>_total | orders_created_total |
| Counter (Fehler) | <noun>_errors_total | dispatcher_handler_errors_total |
| Histogram (Zeit) | <noun>_duration_seconds | http_request_duration_seconds |
| Histogram (Bytes) | <noun>_bytes | http_request_body_bytes |
| Histogram (Domain-Unit) | <noun>_<unit> | orders_value_eur, upload_size_bytes |
| Gauge (Stand) | <noun> (kein Suffix) | db_pool_active_connections, outbox_depth |
Feature-Prefix automatisch
Feature-Autoren schreiben den Namen ohne Feature-Prefix. Das Framework haengt kumiko_<feature>_ an:
defineFeature("orders", (r) => { r.metric("created_total", { type: "counter", labels: ["status"] }); // ^ registriert als: kumiko_orders_created_total
r.metric("value_eur", { type: "histogram", buckets: [10, 50, 100, 500] }); // ^ registriert als: kumiko_orders_value_eur});Doppelungen wie orders_orders_created_total sind damit unmoeglich.
Labels
- Nur niedrig-kardinale Werte (Status-Codes, Methoden-Namen, Handler-Namen).
- Nie User-IDs, Tenant-IDs (ausser
tenantLabel: trueopt-in), Request-IDs, UUIDs. - Label-Keys ebenfalls snake_case:
error_class, nichterrorClass. - Mehrere Label-Werte pro Metric sind erlaubt, aber die Kardinalitaet multipliziert sich:
status × method × route= Cartesian-Explosion vermeiden.
Framework-Standard-Metrics (v1)
Werden automatisch beim Boot registriert, nicht per Feature-Code:
| Name | Typ | Labels |
|---|---|---|
kumiko_http_requests_total | counter | route, method, status |
kumiko_http_request_duration_seconds | histogram | route, method |
kumiko_dispatcher_handler_duration_seconds | histogram | handler, success |
kumiko_dispatcher_handler_errors_total | counter | handler, error_class |
kumiko_db_query_duration_seconds | histogram | operation, table |
Weitere Standard-Metrics kommen in v2 (Outbox, Redis, Jobs).
Spans
Grundregeln
- dot.notation, lowercase.
- OTel-Semantic-Conventions wenn es eine gibt (
http.request,db.query,redis.cmd). - Kumiko-spezifisches mit Prefix
kumiko.*(kumiko.dispatcher.handler,kumiko.pipeline.hook). - Pattern:
<layer>.<operation>.
Framework-Spans (v1)
| Span-Name | Wo entsteht | OTel-Standard? |
|---|---|---|
http.request | Hono-Middleware | Ja (OTel HTTP) |
auth.verify | Auth-Middleware | Ja (OTel Auth) |
kumiko.dispatcher.handler | Dispatcher-Eintritt | Nein — kumiko-spezifisch |
kumiko.pipeline.hook | Lifecycle-Pipeline pro Hook | Nein — kumiko-spezifisch |
db.query | TenantDb / CrudExecutor | Ja (OTel DB) |
db.transaction | TX-Wrapper | Ja (OTel DB) |
redis.cmd | Redis-Wrapper | Ja (OTel Redis) |
outbox.publish | Outbox-Poller | Nein — kumiko-spezifisch |
job.execute | JobRunner-Worker | Nein — kumiko-spezifisch |
Span-Attribute
OTel-Semantic-Conventions (wo verfuegbar):
| Attribute | Beispiel-Wert |
|---|---|
http.method | "POST" |
http.route | "/api/write" |
http.status_code | 200 |
db.system | "postgresql" |
db.operation | "insert" |
db.table | "orders" |
db.row_count | 3 |
Kumiko-spezifische Attribute mit kumiko.-Prefix:
| Attribute | Beispiel-Wert |
|---|---|
kumiko.feature | "orders" |
kumiko.handler | "order.create" |
kumiko.tenant_id | 42 |
kumiko.user_id | 17 |
kumiko.request_id | "req-abc123" |
kumiko.hook_type | "postSave" |
kumiko.hook_phase | "inTransaction" |
Nie als Span-Attribut:
- Request-Body (egal wie gross)
- Auth-Header, Cookies
- DB-Query-Parameter (nur parametrisiert, nie raw)
- Redis-Keys (nur Pattern, nie raw Key)
- Felder die am Entity als
encrypted: truemarkiert sind
Siehe observability.md fuer den Sensitive-Filter.
Runtime-Validation beim Boot
registry.build() validiert jeden registrierten Metric-Namen. Verstoesse fuehren zu einem Boot-Error mit praeziser Message:
ValidationError: Metric "orders_created" muss als Counter auf "_total" enden. Feature: orders Typ: counter Vorschlag: "orders_created_total"Damit koennen falsche Namen gar nicht erst in Prod gelangen.
Migration bestehender Namen
Wenn ein Name bereits in Prod emittiert wurde und sich als falsch herausstellt:
- Nicht umbenennen — Dashboards brechen.
- Neuen Namen einfuehren, beide parallel emittieren.
- Dashboards/Alerts umstellen.
- Alten Namen nach Beobachtungszeitraum entfernen.
In Dev / vor First-Release ist free-for-all — einfach umbenennen.
Zusammenhang zu anderen Docs
- observability.md — Gesamt-Architektur, Sensitive-Filter, Sampling
- boot-validation.md — fail-fast-Prinzip
- naming-conventions.md — allgemeine Kumiko-Namens-Regeln (Feature-Prefix, Entity-Namen)