Goal
Add production-grade observability so you can see what the system is actually doing — latency, token consumption, error rates, model selection patterns.
Current State
logger.ts does console.log(JSON.stringify(...)) — no persistence, no querying, no visualization.
Tasks
Structured Logging
Metrics Storage
Admin Dashboard
Alerting (stretch)
Why
A system without observability is a black box. This is what separates "I built a chat app" from "I built and operated a chat service." Every production system needs this. Also, building dashboards with real data is inherently satisfying.
Learning Points
- Structured logging best practices (correlation IDs, log levels)
- Metrics aggregation: counters, histograms, percentiles
- Time-series data visualization
- The difference between logs, metrics, and traces
Goal
Add production-grade observability so you can see what the system is actually doing — latency, token consumption, error rates, model selection patterns.
Current State
logger.tsdoesconsole.log(JSON.stringify(...))— no persistence, no querying, no visualization.Tasks
Structured Logging
pino(fast, structured, JSON by default)Metrics Storage
metricstable in SQLite: timestamp, event_type, user_id, model, provider, latency_ms, prompt_tokens, completion_tokens, status (success/error), error_codeAdmin Dashboard
GET /admin/metrics/summary— today's stats: total requests, avg latency, total tokens, error rateGET /admin/metrics/models— per-model breakdown: usage count, avg latency, total tokens, cost estimateGET /admin/metrics/timeline— time-series data for charts (requests/hour, latency/hour)GET /admin/metrics/errors— recent errors with trace_id for debuggingrechartsor plain SVG)Alerting (stretch)
Why
A system without observability is a black box. This is what separates "I built a chat app" from "I built and operated a chat service." Every production system needs this. Also, building dashboards with real data is inherently satisfying.
Learning Points