From f264e9f2ae1afaa9368df1f1a35b1cd1bd2c05b9 Mon Sep 17 00:00:00 2001 From: Till JS Date: Thu, 19 Mar 2026 21:14:09 +0100 Subject: [PATCH] feat(grafana): add GlitchTip error tracking dashboard - Add PostgreSQL datasource pointing to GlitchTip database - Add Error Tracking dashboard with 7 panels: - Total Open Issues (stat) - Issues by Project (pie chart) - Total Events (stat) - Projects Tracked (stat) - Resolved vs Unresolved (stat) - New Issues Over Time (stacked bar chart, 30 days) - Recent Issues (table with 50 latest, color-coded levels) - Dashboard links to GlitchTip UI for detailed investigation Co-Authored-By: Claude Opus 4.6 (1M context) --- docker/grafana/dashboards/error-tracking.json | 166 ++++++++++++++++++ .../provisioning/datasources/glitchtip.yml | 23 +++ 2 files changed, 189 insertions(+) create mode 100644 docker/grafana/dashboards/error-tracking.json create mode 100644 docker/grafana/provisioning/datasources/glitchtip.yml diff --git a/docker/grafana/dashboards/error-tracking.json b/docker/grafana/dashboards/error-tracking.json new file mode 100644 index 000000000..077e6b482 --- /dev/null +++ b/docker/grafana/dashboards/error-tracking.json @@ -0,0 +1,166 @@ +{ + "annotations": { "list": [] }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [ + { + "title": "GlitchTip", + "url": "https://glitchtip.mana.how", + "targetBlank": true, + "icon": "external link" + } + ], + "panels": [ + { + "title": "Total Open Issues", + "type": "stat", + "gridPos": { "h": 4, "w": 6, "x": 0, "y": 0 }, + "datasource": { "type": "postgres", "uid": "${DS_GLITCHTIP}" }, + "targets": [ + { + "rawSql": "SELECT COUNT(*) AS \"Open Issues\" FROM issue_events_issue WHERE status = 0 AND is_deleted = false", + "format": "table" + } + ], + "fieldConfig": { + "defaults": { + "thresholds": { + "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 10 }, + { "color": "red", "value": 50 } + ] + } + } + } + }, + { + "title": "Issues by Project", + "type": "piechart", + "gridPos": { "h": 8, "w": 6, "x": 6, "y": 0 }, + "datasource": { "type": "postgres", "uid": "${DS_GLITCHTIP}" }, + "targets": [ + { + "rawSql": "SELECT p.name AS \"Project\", COUNT(i.id) AS \"Issues\" FROM issue_events_issue i JOIN projects_project p ON i.project_id = p.id WHERE i.is_deleted = false GROUP BY p.name ORDER BY COUNT(i.id) DESC", + "format": "table" + } + ] + }, + { + "title": "Total Events (all time)", + "type": "stat", + "gridPos": { "h": 4, "w": 6, "x": 12, "y": 0 }, + "datasource": { "type": "postgres", "uid": "${DS_GLITCHTIP}" }, + "targets": [ + { + "rawSql": "SELECT SUM(count) AS \"Total Events\" FROM issue_events_issue WHERE is_deleted = false", + "format": "table" + } + ] + }, + { + "title": "Projects Tracked", + "type": "stat", + "gridPos": { "h": 4, "w": 6, "x": 18, "y": 0 }, + "datasource": { "type": "postgres", "uid": "${DS_GLITCHTIP}" }, + "targets": [ + { + "rawSql": "SELECT COUNT(*) AS \"Projects\" FROM projects_project WHERE is_deleted = false", + "format": "table" + } + ], + "fieldConfig": { "defaults": { "color": { "mode": "fixed", "fixedColor": "blue" } } } + }, + { + "title": "Resolved vs Unresolved", + "type": "stat", + "gridPos": { "h": 4, "w": 6, "x": 0, "y": 4 }, + "datasource": { "type": "postgres", "uid": "${DS_GLITCHTIP}" }, + "targets": [ + { + "rawSql": "SELECT COUNT(*) FILTER (WHERE status = 1) AS \"Resolved\", COUNT(*) FILTER (WHERE status = 0) AS \"Unresolved\" FROM issue_events_issue WHERE is_deleted = false", + "format": "table" + } + ] + }, + { + "title": "New Issues Over Time", + "type": "timeseries", + "gridPos": { "h": 8, "w": 18, "x": 6, "y": 8 }, + "datasource": { "type": "postgres", "uid": "${DS_GLITCHTIP}" }, + "targets": [ + { + "rawSql": "SELECT date_trunc('day', first_seen) AS time, p.name AS metric, COUNT(*) AS value FROM issue_events_issue i JOIN projects_project p ON i.project_id = p.id WHERE i.is_deleted = false AND i.first_seen > NOW() - INTERVAL '30 days' GROUP BY 1, 2 ORDER BY 1", + "format": "time_series" + } + ], + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "bars", + "fillOpacity": 80, + "stacking": { "mode": "normal" } + } + } + } + }, + { + "title": "Recent Issues", + "type": "table", + "gridPos": { "h": 10, "w": 24, "x": 0, "y": 16 }, + "datasource": { "type": "postgres", "uid": "${DS_GLITCHTIP}" }, + "targets": [ + { + "rawSql": "SELECT p.name AS \"Project\", i.title AS \"Error\", i.culprit AS \"Location\", i.count AS \"Events\", CASE i.level WHEN 40 THEN 'error' WHEN 50 THEN 'fatal' WHEN 30 THEN 'warning' WHEN 20 THEN 'info' ELSE 'debug' END AS \"Level\", CASE i.status WHEN 0 THEN 'unresolved' WHEN 1 THEN 'resolved' WHEN 2 THEN 'ignored' END AS \"Status\", i.first_seen AS \"First Seen\", i.last_seen AS \"Last Seen\" FROM issue_events_issue i JOIN projects_project p ON i.project_id = p.id WHERE i.is_deleted = false ORDER BY i.last_seen DESC LIMIT 50", + "format": "table" + } + ], + "fieldConfig": { + "overrides": [ + { + "matcher": { "id": "byName", "options": "Level" }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "mappings", + "value": [ + { + "type": "value", + "options": { + "error": { "color": "red", "text": "error" }, + "fatal": { "color": "dark-red", "text": "fatal" }, + "warning": { "color": "yellow", "text": "warning" } + } + } + ] + } + ] + } + ] + } + } + ], + "schemaVersion": 39, + "tags": ["error-tracking", "glitchtip"], + "templating": { + "list": [ + { + "name": "DS_GLITCHTIP", + "type": "datasource", + "query": "postgres", + "current": { "text": "GlitchTip", "value": "GlitchTip" }, + "hide": 2 + } + ] + }, + "time": { "from": "now-7d", "to": "now" }, + "title": "Error Tracking (GlitchTip)", + "uid": "error-tracking-glitchtip" +} diff --git a/docker/grafana/provisioning/datasources/glitchtip.yml b/docker/grafana/provisioning/datasources/glitchtip.yml new file mode 100644 index 000000000..6df9660a4 --- /dev/null +++ b/docker/grafana/provisioning/datasources/glitchtip.yml @@ -0,0 +1,23 @@ +# GlitchTip PostgreSQL Datasource +# Enables error tracking dashboards in Grafana + +apiVersion: 1 + +datasources: + - name: GlitchTip + type: postgres + access: proxy + url: postgres:5432 + user: postgres + secureJsonData: + password: ${POSTGRES_PASSWORD} + jsonData: + database: glitchtip + sslmode: disable + maxOpenConns: 5 + maxIdleConns: 2 + connMaxLifetime: 14400 + postgresVersion: 1600 + timescaledb: false + isDefault: false + editable: true