From 37fb5fa1c942fde89e5325bf29bc645b4b31c93d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 12 Apr 2026 16:00:00 +0200 Subject: [PATCH] Add Journal dashboard, fix Caddy metrics, and improve alerts Fix blind spot where Caddy 502 errors were invisible: the dashboards and alerts queried caddy_http_response_duration_seconds (upstream responses only), missing 502s that Caddy generates itself. Switch to caddy_http_request_duration_seconds (server-level, all responses). Add Journal Grafana dashboard with: 502 rate, response codes, request rate by route, latency percentiles, container restarts/memory/CPU, Node.js event loop lag and heap, and Loki log panels for errors and Caddy 5xx entries. Add color coding to Caddy status code panel (green=2xx, blue=3xx, yellow=4xx, red=5xx). Add log-based error rate panel to the overview dashboard. New alerts: container restart loop, PostgreSQL connections > 80, application crash log detection (Loki), and Caddy 502 rate. Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/planner/app/lib/brouter.ts | 7 +- .../grafana/dashboards/journal.json | 312 ++++++++++++++++++ .../grafana/dashboards/overview.json | 41 ++- .../grafana/dashboards/service-health.json | 24 +- .../grafana/provisioning/alerting/alerts.yml | 102 +++++- 5 files changed, 478 insertions(+), 8 deletions(-) create mode 100644 infrastructure/grafana/dashboards/journal.json diff --git a/apps/planner/app/lib/brouter.ts b/apps/planner/app/lib/brouter.ts index d4a3974..f1ab53e 100644 --- a/apps/planner/app/lib/brouter.ts +++ b/apps/planner/app/lib/brouter.ts @@ -68,12 +68,11 @@ export async function computeRoute(request: RouteRequest): Promise 80 + condition: B + data: + - refId: A + relativeTimeRange: { from: 300, to: 0 } + datasourceUid: prometheus + model: + expr: sum(pg_stat_activity_count{datname="trails"}) + instant: true + - refId: B + datasourceUid: __expr__ + model: + type: threshold + expression: A + conditions: + - evaluator: { params: [80], type: gt } + operator: { type: and } + reducer: { type: last } + for: 5m + annotations: + summary: "PostgreSQL active connections above 80 — approaching default max_connections limit" + + - uid: app-crash-log + title: Application crash detected + condition: C + data: + - refId: A + relativeTimeRange: { from: 300, to: 0 } + datasourceUid: loki + model: + expr: sum(count_over_time({service=~"journal|planner"} |~ "uncaughtException|unhandledRejection|ERR_|FATAL|segfault|OOMKilled"[5m])) + instant: true + - refId: B + datasourceUid: __expr__ + model: + type: reduce + expression: A + reducer: last + - refId: C + datasourceUid: __expr__ + model: + type: threshold + expression: B + conditions: + - evaluator: { params: [0], type: gt } + operator: { type: and } + reducer: { type: last } + for: 0s + noDataState: OK + annotations: + summary: "Crash signature detected in application logs" + + - uid: caddy-502-rate + title: Caddy 502 errors detected + condition: B + noDataState: OK + data: + - refId: A + relativeTimeRange: { from: 300, to: 0 } + datasourceUid: prometheus + model: + expr: sum(rate(caddy_http_request_duration_seconds_count{code="502"}[5m])) or vector(0) + instant: true + - refId: B + datasourceUid: __expr__ + model: + type: threshold + expression: A + conditions: + - evaluator: { params: [0], type: gt } + operator: { type: and } + reducer: { type: last } + for: 2m + annotations: + summary: "Caddy is returning 502 errors — journal or planner upstream unreachable" + contactPoints: - orgId: 1 name: email