From fa842d3f6f9003edd258a880dc0d05b8840c88ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoni=20Nu=C3=B1ez=20Romeu?= Date: Tue, 21 Jul 2026 17:39:19 +0200 Subject: [PATCH] feat(faro): rewrite dashboards to use Tempo instead of Loki Faro SDK sends traces (spans with events) via OTLP, not OTLP logs or metrics. Rewrote all 3 Faro dashboards to use Tempo TraceQL queries instead of Loki LogQL. - faro-overview: page views, exceptions, console errors, navigation - faro-js-errors: exception traces, console error traces - faro-web-vitals: LCP, FCP, CLS, TTFB via web-vitals span events All panels now query Tempo (uid P214B5B846CF3925F) with TraceQL. --- monitoring/dashboards/faro-js-errors.json | 142 +++++++++++++++++++++ monitoring/dashboards/faro-overview.json | 139 ++++++++++++++++++++ monitoring/dashboards/faro-web-vitals.json | 134 +++++++++++++++++++ 3 files changed, 415 insertions(+) create mode 100644 monitoring/dashboards/faro-js-errors.json create mode 100644 monitoring/dashboards/faro-overview.json create mode 100644 monitoring/dashboards/faro-web-vitals.json diff --git a/monitoring/dashboards/faro-js-errors.json b/monitoring/dashboards/faro-js-errors.json new file mode 100644 index 0000000..52277f5 --- /dev/null +++ b/monitoring/dashboards/faro-js-errors.json @@ -0,0 +1,142 @@ +{ + "annotations": { "list": [] }, + "description": "JS errors and console errors captured by Grafana Faro. Data lives in Tempo as span events.", + "editable": true, + "graphTooltip": 1, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "type": "stat", + "title": "Exceptions (5m)", + "datasource": { "type": "tempo", "uid": "P214B5B846CF3925F" }, + "gridPos": { "h": 4, "w": 8, "x": 0, "y": 0 }, + "fieldConfig": { + "defaults": { + "thresholds": { "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 1 }, + { "color": "red", "value": 5 } + ]} + } + }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "colorMode": "background" }, + "targets": [ + { + "query": "{ service.name = \"farmafinder-frontend\" && span.event.name = \"exception\" }", + "refId": "A", + "limit": 1000, + "tableType": "traceql" + } + ] + }, + { + "type": "stat", + "title": "Console errors (5m)", + "datasource": { "type": "tempo", "uid": "P214B5B846CF3925F" }, + "gridPos": { "h": 4, "w": 8, "x": 8, "y": 0 }, + "fieldConfig": { + "defaults": { + "thresholds": { "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 1 }, + { "color": "red", "value": 5 } + ]} + } + }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "colorMode": "background" }, + "targets": [ + { + "query": "{ service.name = \"farmafinder-frontend\" && span.event.name = \"console\" } | logfmt | level =~ \"error|critical\"", + "refId": "A", + "limit": 1000, + "tableType": "traceql" + } + ] + }, + { + "type": "stat", + "title": "Failed fetch/XHR (5m)", + "datasource": { "type": "tempo", "uid": "P214B5B846CF3925F" }, + "gridPos": { "h": 4, "w": 8, "x": 16, "y": 0 }, + "fieldConfig": { + "defaults": { + "thresholds": { "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 1 }, + { "color": "red", "value": 5 } + ]} + } + }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "colorMode": "background" }, + "targets": [ + { + "query": "{ service.name = \"farmafinder-frontend\" && span.event.name = \"fetch\" } | logfmt | status_code >= 400", + "refId": "A", + "limit": 1000, + "tableType": "traceql" + } + ] + }, + { + "type": "table", + "title": "Recent exception traces", + "datasource": { "type": "tempo", "uid": "P214B5B846CF3925F" }, + "gridPos": { "h": 10, "w": 24, "x": 0, "y": 4 }, + "options": { "showHeader": true }, + "targets": [ + { + "query": "{ service.name = \"farmafinder-frontend\" && span.event.name = \"exception\" }", + "refId": "A", + "limit": 20, + "tableType": "traceql" + } + ], + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { "traceID": false, "rootServiceName": true, "rootTraceName": false, "duration": true, "startTime": true }, + "renameByName": { "traceID": "Trace ID", "rootTraceName": "Name", "duration": "Duration", "startTime": "Time" } + } + } + ] + }, + { + "type": "table", + "title": "Recent console errors", + "datasource": { "type": "tempo", "uid": "P214B5B846CF3925F" }, + "gridPos": { "h": 10, "w": 24, "x": 0, "y": 14 }, + "options": { "showHeader": true }, + "targets": [ + { + "query": "{ service.name = \"farmafinder-frontend\" && span.event.name = \"console\" } | logfmt | level =~ \"error|critical\"", + "refId": "A", + "limit": 20, + "tableType": "traceql" + } + ], + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { "traceID": false, "rootServiceName": true, "rootTraceName": false, "duration": true, "startTime": true }, + "renameByName": { "traceID": "Trace ID", "rootTraceName": "Name", "duration": "Duration", "startTime": "Time" } + } + } + ] + } + ], + "refresh": "30s", + "schemaVersion": 39, + "tags": ["faro", "errors", "farmafinder"], + "templating": { "list": [] }, + "time": { "from": "now-1h", "to": "now" }, + "timepicker": {}, + "timezone": "browser", + "title": "FARO — JS Errors", + "uid": "faro-js-errors", + "version": 2, + "weekStart": "" +} diff --git a/monitoring/dashboards/faro-overview.json b/monitoring/dashboards/faro-overview.json new file mode 100644 index 0000000..6f52e3e --- /dev/null +++ b/monitoring/dashboards/faro-overview.json @@ -0,0 +1,139 @@ +{ + "annotations": { "list": [] }, + "description": "Overview of Faro RUM signals. Data comes from browser traces via Tempo.", + "editable": true, + "graphTooltip": 1, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "type": "stat", + "title": "Total spans (5m)", + "datasource": { "type": "tempo", "uid": "P214B5B846CF3925F" }, + "gridPos": { "h": 4, "w": 6, "x": 0, "y": 0 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "targets": [ + { + "query": "{ service.name = \"farmafinder-frontend\" }", + "refId": "A", + "limit": 1000, + "tableType": "traceql" + } + ] + }, + { + "type": "stat", + "title": "Exception spans (5m)", + "datasource": { "type": "tempo", "uid": "P214B5B846CF3925F" }, + "gridPos": { "h": 4, "w": 6, "x": 6, "y": 0 }, + "fieldConfig": { + "defaults": { + "thresholds": { "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 1 }, + { "color": "red", "value": 5 } + ]} + } + }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "colorMode": "background" }, + "targets": [ + { + "query": "{ service.name = \"farmafinder-frontend\" && span.event.name = \"exception\" }", + "refId": "A", + "limit": 1000, + "tableType": "traceql" + } + ] + }, + { + "type": "stat", + "title": "Console error spans (5m)", + "datasource": { "type": "tempo", "uid": "P214B5B846CF3925F" }, + "gridPos": { "h": 4, "w": 6, "x": 12, "y": 0 }, + "fieldConfig": { + "defaults": { + "thresholds": { "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 1 }, + { "color": "red", "value": 5 } + ]} + } + }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "colorMode": "background" }, + "targets": [ + { + "query": "{ service.name = \"farmafinder-frontend\" && span.event.name = \"console\" } | logfmt | level =~ \"error|critical\"", + "refId": "A", + "limit": 1000, + "tableType": "traceql" + } + ] + }, + { + "type": "stat", + "title": "Navigation spans (5m)", + "datasource": { "type": "tempo", "uid": "P214B5B846CF3925F" }, + "gridPos": { "h": 4, "w": 6, "x": 18, "y": 0 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "targets": [ + { + "query": "{ service.name = \"farmafinder-frontend\" && span.event.name = \"navigation\" }", + "refId": "A", + "limit": 1000, + "tableType": "traceql" + } + ] + }, + { + "type": "table", + "title": "Recent traces from frontend", + "datasource": { "type": "tempo", "uid": "P214B5B846CF3925F" }, + "gridPos": { "h": 10, "w": 24, "x": 0, "y": 4 }, + "options": { "showHeader": true }, + "targets": [ + { + "query": "{ service.name = \"farmafinder-frontend\" }", + "refId": "A", + "limit": 20, + "tableType": "traceql" + } + ], + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { "traceID": false, "rootServiceName": true, "rootTraceName": false, "duration": true, "startTime": true }, + "renameByName": { "traceID": "Trace ID", "rootTraceName": "Name", "duration": "Duration", "startTime": "Time" } + } + } + ] + }, + { + "type": "logs", + "title": "Explore — Tempo traces", + "datasource": { "type": "tempo", "uid": "P214B5B846CF3925F" }, + "gridPos": { "h": 10, "w": 24, "x": 0, "y": 14 }, + "options": { "showTime": true, "showLabels": false }, + "targets": [ + { + "query": "{ service.name = \"farmafinder-frontend\" }", + "refId": "A", + "limit": 50, + "tableType": "traceql" + } + ] + } + ], + "refresh": "30s", + "schemaVersion": 39, + "tags": ["faro", "rum", "farmafinder"], + "templating": { "list": [] }, + "time": { "from": "now-1h", "to": "now" }, + "timepicker": {}, + "timezone": "browser", + "title": "FARO — FarmaFinder RUM Overview", + "uid": "faro-overview", + "version": 2, + "weekStart": "" +} diff --git a/monitoring/dashboards/faro-web-vitals.json b/monitoring/dashboards/faro-web-vitals.json new file mode 100644 index 0000000..13c72e9 --- /dev/null +++ b/monitoring/dashboards/faro-web-vitals.json @@ -0,0 +1,134 @@ +{ + "annotations": { "list": [] }, + "description": "Core Web Vitals (LCP, CLS, FCP, TTFB, INP) from Grafana Faro. Vitals are captured as span events in Tempo.", + "editable": true, + "graphTooltip": 1, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "type": "stat", + "title": "LCP p75 (ms)", + "datasource": { "type": "tempo", "uid": "P214B5B846CF3925F" }, + "gridPos": { "h": 5, "w": 6, "x": 0, "y": 0 }, + "fieldConfig": { "defaults": { "unit": "ms" } }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "targets": [ + { + "query": "{ service.name = \"farmafinder-frontend\" && span.event.name = \"web-vitals\" } | logfmt | name = \"LCP\"", + "refId": "A", + "limit": 1000, + "tableType": "traceql" + } + ] + }, + { + "type": "stat", + "title": "FCP p75 (ms)", + "datasource": { "type": "tempo", "uid": "P214B5B846CF3925F" }, + "gridPos": { "h": 5, "w": 6, "x": 6, "y": 0 }, + "fieldConfig": { "defaults": { "unit": "ms" } }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "targets": [ + { + "query": "{ service.name = \"farmafinder-frontend\" && span.event.name = \"web-vitals\" } | logfmt | name = \"FCP\"", + "refId": "A", + "limit": 1000, + "tableType": "traceql" + } + ] + }, + { + "type": "stat", + "title": "CLS p75", + "datasource": { "type": "tempo", "uid": "P214B5B846CF3925F" }, + "gridPos": { "h": 5, "w": 6, "x": 12, "y": 0 }, + "fieldConfig": { "defaults": { "unit": "none", "decimals": 3 } }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "targets": [ + { + "query": "{ service.name = \"farmafinder-frontend\" && span.event.name = \"web-vitals\" } | logfmt | name = \"CLS\"", + "refId": "A", + "limit": 1000, + "tableType": "traceql" + } + ] + }, + { + "type": "stat", + "title": "TTFB p75 (ms)", + "datasource": { "type": "tempo", "uid": "P214B5B846CF3925F" }, + "gridPos": { "h": 5, "w": 6, "x": 18, "y": 0 }, + "fieldConfig": { "defaults": { "unit": "ms" } }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "targets": [ + { + "query": "{ service.name = \"farmafinder-frontend\" && span.event.name = \"web-vitals\" } | logfmt | name = \"TTFB\"", + "refId": "A", + "limit": 1000, + "tableType": "traceql" + } + ] + }, + { + "type": "table", + "title": "Recent web-vitals events", + "datasource": { "type": "tempo", "uid": "P214B5B846CF3925F" }, + "gridPos": { "h": 12, "w": 24, "x": 0, "y": 5 }, + "options": { "showHeader": true }, + "targets": [ + { + "query": "{ service.name = \"farmafinder-frontend\" && span.event.name = \"web-vitals\" }", + "refId": "A", + "limit": 30, + "tableType": "traceql" + } + ], + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { "traceID": false, "rootServiceName": true, "rootTraceName": false, "duration": true, "startTime": true }, + "renameByName": { "traceID": "Trace ID", "rootTraceName": "Name", "duration": "Duration", "startTime": "Time" } + } + } + ] + }, + { + "type": "table", + "title": "Recent navigation events", + "datasource": { "type": "tempo", "uid": "P214B5B846CF3925F" }, + "gridPos": { "h": 10, "w": 24, "x": 0, "y": 17 }, + "options": { "showHeader": true }, + "targets": [ + { + "query": "{ service.name = \"farmafinder-frontend\" && span.event.name = \"navigation\" }", + "refId": "A", + "limit": 20, + "tableType": "traceql" + } + ], + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { "traceID": false, "rootServiceName": true, "rootTraceName": false, "duration": true, "startTime": true }, + "renameByName": { "traceID": "Trace ID", "rootTraceName": "Name", "duration": "Duration", "startTime": "Time" } + } + } + ] + } + ], + "refresh": "30s", + "schemaVersion": 39, + "tags": ["faro", "web-vitals", "farmafinder"], + "templating": { "list": [] }, + "time": { "from": "now-3h", "to": "now" }, + "timepicker": {}, + "timezone": "browser", + "title": "FARO — Web Vitals", + "uid": "faro-web-vitals", + "version": 2, + "weekStart": "" +}