feat(logging): ~2-month container rotation, ISO timestamps, level names
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:
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user