feat(logging): ~2-month container rotation, ISO timestamps, level names
Build & push images / images (push) Successful in 2m54s
CI / check (push) Successful in 41s

Operator asked for bounded container logs (~2 months of history), human-
readable timestamps, and clarity on levels. Levels already existed (LOG_LEVEL
env → pino, default info; warn+ teed into app_logs, queryable at /setup/logs)
— the "level":30 / epoch-ms "time" in docker logs were pino defaults.

- server.ts logger: stamp ISO-8601 UTC time (timestamp fn) and level NAMES
  (formatters.level) so `docker logs` reads human.
- log-service.ts pinoDbStream: accept BOTH level encodings (name + numeric) —
  the label switch would otherwise have silently stopped warn+ persistence
  into app_logs. New log-service-stream.test.ts pins both encodings, the
  info-stays-stdout-only rule, and the never-throws fallback.
- docker-compose.prod.yml: json-file caps resized from 10m×3 (≈30 MB — days,
  not months) to ≈2 months by volume: server 20m×30, vision 20m×10, proxy
  10m×5. json-file rotates by SIZE; time-based isn't a driver feature —
  comment says to revisit if `docker logs` holds under ~60 days.
- app_logs retention default aligned 30→60 days (LOG_RETENTION_DAYS still
  overrides).

Wiki: app-logs.md gains the container-log store section (rotation, format,
LOG_LEVEL knob) + retention update; log.md entry.

Suite 282 green.

Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
2026-07-04 19:47:53 +02:00
parent 43c1f45e29
commit c21babf293
6 changed files with 120 additions and 15 deletions
+21 -4
View File
@@ -2,7 +2,7 @@
type: concept
tags: [parking, observability, diagnostics, logging, frontend, backend]
sources: []
updated: 2026-06-19
updated: 2026-07-04
status: open
---
@@ -66,9 +66,26 @@ column — the failed request, error name, component stack, anything), plus pull
## Retention (offline appliance ⇒ must be bounded)
Pruned by **age AND a row cap** (a burst could blow past an age-only window): delete older than
`LOG_RETENTION_DAYS` (default 30) **and** keep only the newest `LOG_RETENTION_MAX_ROWS` (default
50 000). Runs **hourly** (unref'd timer) + once at startup. Both env-configurable. Same "prunable,
not precious" durability class as `device_events` — the opposite of the append-only ledger.
`LOG_RETENTION_DAYS` (default **60** — the operator's ≈2-month diagnostic window, 2026-07-04;
was 30) **and** keep only the newest `LOG_RETENTION_MAX_ROWS` (default 50 000). Runs **hourly**
(unref'd timer) + once at startup. Both env-configurable. Same "prunable, not precious"
durability class as `device_events` — the opposite of the append-only ledger.
## Container (stdout) logs — the OTHER log store (2026-07-04)
`docker logs` is a separate, size-bounded store from `app_logs` — it holds **everything**
(info/debug too), while `app_logs` keeps only warn+. Three knobs, all set 2026-07-04:
- **Rotation:** Docker's json-file driver rotates by SIZE, not time; the caps in
`docker-compose.prod.yml` are sized to hold **≈2 months** at observed booth rates (server
20 MB × 30, vision 20 MB × 10, proxy 10 MB × 5). `docker logs` reaches back only that far —
revisit the caps if it shows under ~60 days. (Dev compose is uncapped — laptop concern only.)
- **Human-readable lines:** the pino logger stamps **ISO-8601 UTC** `time` (was epoch-ms) and
**level NAMES** (`"warn"`, was `40`) via `timestamp` + `formatters.level` in `server.ts`.
`pinoDbStream` accepts BOTH level encodings, so the app_logs tee survives either config.
- **Level knob:** `LOG_LEVEL` env (trace|debug|info|warn|error|fatal; default `info`) — a booth
under diagnosis runs `LOG_LEVEL=debug` with no code change; warn+ persistence is unaffected
(it filters independently in the tee).
## The booth viewer
+10
View File
@@ -2272,3 +2272,13 @@ card, unknown SUB- code) still signs the normal anomaly; enrolled credentials ma
filter and can never be hidden by it. Works for legacy unprefixed reads too, so the feed cleans up
before the vendor-tool visit. 6 new tests; suite 278 green. Also this session: reader channel
tagging (clone defense) — see the prior entry.
## [2026-07-04] update | Logging: 2-month rotation, ISO timestamps, level names
Operator asked for bounded container logs (~2 months), human-readable timestamps, and clarity on
levels. Findings + changes on [[app-logs]]: levels EXISTED (LOG_LEVEL env, pino, warn+ teed to
app_logs); the "level":30 numbers and epoch-ms times were pino defaults — the logger now stamps
ISO-8601 UTC + level names (pinoDbStream hardened to accept both encodings so the DB tee can't
silently break). Rotation: docker json-file caps in docker-compose.prod.yml resized from 10m×3
(≈30 MB!) to ≈2 months by volume (server 20m×30, vision 20m×10, proxy 10m×5; json-file rotates by
SIZE — time-based isn't a driver feature). app_logs retention default aligned 30→60 days.