From e6fca752a22d24248174786523950796010c742a Mon Sep 17 00:00:00 2001 From: Gabriel Radureau Date: Wed, 8 Jul 2026 19:52:29 +0200 Subject: [PATCH] =?UTF-8?q?feat(monitoring):=20dashboard=20Grafana=20+=20r?= =?UTF-8?q?=C3=A8gles=20d'alerte=20prospection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consomme les métriques poussées par le pipeline prospection au Pushgateway (job=prospection, déjà scrapé). Additif — n'affecte aucun dashboard existant. - grafana : provider + dashboard « Prospection — pipeline BI missions » inliné (grafana.dashboards.prospection, json) — vue d'ensemble (fraîcheur/statut/durée/ erreurs/missions/score), collecte par étape (table + historique), modèle de données (opportunités A/B, offres/entités), livraison (brief/Telegram) + panneau Alertes actives. Inline plutôt que ConfigMap externe : grafana est déployé via un HelmChart CRD (tool lib), l'inline évite toute hypothèse de namespace. - prometheus : groupe d'alertes `prospection` (serverFiles.alerting_rules.yml) — RunStale (>25h), RunFailed, StepError, NoOffers, BriefNotSent. NB : la livraison des alertes (Alertmanager → Telegram) n'est pas câblée dans le cluster (server.alertmanagers vide, aucun receiver) ; les règles restent visibles dans Prometheus /alerts + le dashboard. Câblage delivery = décision séparée. Co-Authored-By: Claude Opus 4.8 --- grafana/values.yaml | 224 +++++++++++++++++++++++++++++++++++++++++ prometheus/values.yaml | 54 +++++++++- 2 files changed, 277 insertions(+), 1 deletion(-) diff --git a/grafana/values.yaml b/grafana/values.yaml index 0b2045b..854b088 100644 --- a/grafana/values.yaml +++ b/grafana/values.yaml @@ -703,6 +703,14 @@ grafana: &grafana_config editable: true options: path: /var/lib/grafana/dashboards/grafana-dashboards-kubernetes + - name: 'prospection' + orgId: 1 + folder: 'Prospection' + type: file + disableDeletion: false + editable: true + options: + path: /var/lib/grafana/dashboards/prospection # - name: 'default' # orgId: 1 @@ -757,6 +765,222 @@ grafana: &grafana_config k8s-views-pods: url: https://raw.githubusercontent.com/dotdc/grafana-dashboards-kubernetes/master/dashboards/k8s-views-pods.json token: '' + prospection: + prospection: + json: | + { + "__inputs": [], + "annotations": { "list": [] }, + "editable": true, + "graphTooltip": 1, + "schemaVersion": 39, + "tags": ["prospection", "arcodange"], + "title": "Prospection — pipeline BI missions", + "uid": "prospection-pipeline", + "time": { "from": "now-14d", "to": "now" }, + "refresh": "5m", + "templating": { + "list": [ + { + "name": "DS_PROMETHEUS", + "label": "Datasource", + "type": "datasource", + "query": "prometheus", + "current": {}, + "hide": 0, + "refresh": 1 + } + ] + }, + "panels": [ + { + "type": "row", "title": "Vue d'ensemble du dernier run", + "gridPos": { "h": 1, "w": 24, "x": 0, "y": 0 }, "id": 1, "collapsed": false + }, + { + "type": "stat", "title": "Dernier run réussi il y a", "id": 2, + "gridPos": { "h": 4, "w": 5, "x": 0, "y": 1 }, + "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "targets": [ { "refId": "A", "expr": "time() - prospection_run_timestamp_seconds", "instant": true, "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" } } ], + "fieldConfig": { "defaults": { + "unit": "s", + "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "yellow", "value": 86400 }, { "color": "red", "value": 90000 } ] } + }, "overrides": [] }, + "options": { "colorMode": "background", "graphMode": "none", "reduceOptions": { "calcs": ["lastNotNull"] }, "textMode": "auto" } + }, + { + "type": "stat", "title": "Statut du run", "id": 3, + "gridPos": { "h": 4, "w": 4, "x": 5, "y": 1 }, + "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "targets": [ { "refId": "A", "expr": "prospection_run_success", "instant": true, "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" } } ], + "fieldConfig": { "defaults": { + "mappings": [ { "type": "value", "options": { "0": { "text": "ÉCHEC", "color": "red", "index": 0 }, "1": { "text": "OK", "color": "green", "index": 1 } } } ], + "thresholds": { "mode": "absolute", "steps": [ { "color": "red", "value": null }, { "color": "green", "value": 1 } ] } + }, "overrides": [] }, + "options": { "colorMode": "background", "graphMode": "none", "reduceOptions": { "calcs": ["lastNotNull"] }, "textMode": "auto" } + }, + { + "type": "stat", "title": "Durée du run", "id": 4, + "gridPos": { "h": 4, "w": 5, "x": 9, "y": 1 }, + "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "targets": [ { "refId": "A", "expr": "prospection_run_duration_seconds", "instant": true, "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" } } ], + "fieldConfig": { "defaults": { "unit": "s", "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "yellow", "value": 1200 }, { "color": "red", "value": 1700 } ] } }, "overrides": [] }, + "options": { "colorMode": "value", "graphMode": "area", "reduceOptions": { "calcs": ["lastNotNull"] } } + }, + { + "type": "stat", "title": "Étapes en erreur", "id": 5, + "gridPos": { "h": 4, "w": 4, "x": 14, "y": 1 }, + "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "targets": [ { "refId": "A", "expr": "prospection_run_errors_total", "instant": true, "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" } } ], + "fieldConfig": { "defaults": { "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 1 } ] } }, "overrides": [] }, + "options": { "colorMode": "background", "graphMode": "none", "reduceOptions": { "calcs": ["lastNotNull"] } } + }, + { + "type": "stat", "title": "Missions A qualifiées", "id": 6, + "gridPos": { "h": 4, "w": 3, "x": 18, "y": 1 }, + "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "targets": [ { "refId": "A", "expr": "prospection_opportunities_total{kind=\"A\"}", "instant": true, "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" } } ], + "fieldConfig": { "defaults": { "thresholds": { "mode": "absolute", "steps": [ { "color": "red", "value": null }, { "color": "yellow", "value": 1 }, { "color": "green", "value": 10 } ] } }, "overrides": [] }, + "options": { "colorMode": "value", "graphMode": "area", "reduceOptions": { "calcs": ["lastNotNull"] } } + }, + { + "type": "stat", "title": "Meilleur score", "id": 7, + "gridPos": { "h": 4, "w": 3, "x": 21, "y": 1 }, + "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "targets": [ { "refId": "A", "expr": "prospection_opportunity_top_score", "instant": true, "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" } } ], + "fieldConfig": { "defaults": { "min": 0, "max": 100, "thresholds": { "mode": "absolute", "steps": [ { "color": "red", "value": null }, { "color": "yellow", "value": 65 }, { "color": "green", "value": 85 } ] } }, "overrides": [] }, + "options": { "colorMode": "value", "graphMode": "none", "reduceOptions": { "calcs": ["lastNotNull"] } } + }, + { + "type": "row", "title": "Collecte par étape", + "gridPos": { "h": 1, "w": 24, "x": 0, "y": 5 }, "id": 8, "collapsed": false + }, + { + "type": "table", "title": "Étapes — dernier run", "id": 9, + "gridPos": { "h": 9, "w": 12, "x": 0, "y": 6 }, + "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "targets": [ + { "refId": "Statut", "expr": "prospection_step_status", "instant": true, "format": "table", "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" } }, + { "refId": "Items", "expr": "prospection_step_items", "instant": true, "format": "table", "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" } }, + { "refId": "Durée", "expr": "prospection_step_duration_seconds", "instant": true, "format": "table", "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" } } + ], + "transformations": [ + { "id": "merge", "options": {} }, + { "id": "organize", "options": { + "excludeByName": { "Time": true, "__name__": true, "job": true, "instance": true }, + "renameByName": { "step": "Étape", "Value #Statut": "Statut", "Value #Items": "Items", "Value #Durée": "Durée (s)" }, + "indexByName": { "step": 0, "Value #Statut": 1, "Value #Items": 2, "Value #Durée": 3 } + } } + ], + "fieldConfig": { "defaults": { "custom": { "align": "auto" } }, "overrides": [ + { "matcher": { "id": "byName", "options": "Statut" }, "properties": [ + { "id": "mappings", "value": [ { "type": "value", "options": { "0": { "text": "⛔ erreur", "color": "red", "index": 0 }, "1": { "text": "✅ ok", "color": "green", "index": 1 }, "2": { "text": "⏭️ skip", "color": "blue", "index": 2 } } } ] }, + { "id": "custom.cellOptions", "value": { "type": "color-text" } } + ] }, + { "matcher": { "id": "byName", "options": "Durée (s)" }, "properties": [ { "id": "unit", "value": "s" } ] } + ] }, + "options": { "showHeader": true, "sortBy": [ { "displayName": "Durée (s)", "desc": true } ] } + }, + { + "type": "timeseries", "title": "Items collectés par étape (historique)", "id": 10, + "gridPos": { "h": 9, "w": 12, "x": 12, "y": 6 }, + "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "targets": [ { "refId": "A", "expr": "prospection_step_items > 0", "legendFormat": "{{step}}", "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" } } ], + "fieldConfig": { "defaults": { "custom": { "drawStyle": "bars", "fillOpacity": 40, "stacking": { "mode": "none" }, "lineWidth": 1 } }, "overrides": [] }, + "options": { "legend": { "displayMode": "table", "placement": "right", "calcs": ["lastNotNull"] }, "tooltip": { "mode": "multi", "sort": "desc" } } + }, + { + "type": "row", "title": "Modèle de données & scoring", + "gridPos": { "h": 1, "w": 24, "x": 0, "y": 15 }, "id": 11, "collapsed": false + }, + { + "type": "timeseries", "title": "Opportunités — missions A / cibles B", "id": 12, + "gridPos": { "h": 8, "w": 12, "x": 0, "y": 16 }, + "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "targets": [ + { "refId": "A", "expr": "prospection_opportunities_total{kind=\"A\"}", "legendFormat": "Missions A", "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" } }, + { "refId": "B", "expr": "prospection_opportunities_total{kind=\"B\"}", "legendFormat": "Cibles B", "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" } } + ], + "fieldConfig": { "defaults": { "custom": { "drawStyle": "line", "fillOpacity": 10, "lineWidth": 2, "pointSize": 5, "showPoints": "always" } }, "overrides": [] }, + "options": { "legend": { "displayMode": "list", "placement": "bottom" }, "tooltip": { "mode": "multi" } } + }, + { + "type": "timeseries", "title": "Offres & entités collectées (historique)", "id": 13, + "gridPos": { "h": 8, "w": 8, "x": 12, "y": 16 }, + "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "targets": [ + { "refId": "A", "expr": "prospection_offers_total", "legendFormat": "Offres (missions)", "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" } }, + { "refId": "B", "expr": "prospection_entities_total", "legendFormat": "Entités (territoire)", "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" } }, + { "refId": "C", "expr": "prospection_scores_total", "legendFormat": "Offres scorées", "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" } } + ], + "fieldConfig": { "defaults": { "custom": { "drawStyle": "line", "fillOpacity": 10, "lineWidth": 2, "showPoints": "auto" } }, "overrides": [] }, + "options": { "legend": { "displayMode": "list", "placement": "bottom" }, "tooltip": { "mode": "multi" } } + }, + { + "type": "bargauge", "title": "Modèle — dernier run", "id": 14, + "gridPos": { "h": 8, "w": 4, "x": 20, "y": 16 }, + "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "targets": [ + { "refId": "A", "expr": "prospection_signals_total", "legendFormat": "Signaux", "instant": true, "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" } }, + { "refId": "B", "expr": "prospection_entities_total", "legendFormat": "Entités", "instant": true, "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" } }, + { "refId": "C", "expr": "prospection_offers_total", "legendFormat": "Offres", "instant": true, "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" } }, + { "refId": "D", "expr": "prospection_scores_total", "legendFormat": "Scorées", "instant": true, "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" } } + ], + "fieldConfig": { "defaults": { "thresholds": { "mode": "absolute", "steps": [ { "color": "blue", "value": null } ] } }, "overrides": [] }, + "options": { "displayMode": "gradient", "orientation": "horizontal", "reduceOptions": { "calcs": ["lastNotNull"] }, "legend": { "showLegend": false } } + }, + { + "type": "row", "title": "Livraison & alertes", + "gridPos": { "h": 1, "w": 24, "x": 0, "y": 24 }, "id": 15, "collapsed": false + }, + { + "type": "stat", "title": "Brief rendu", "id": 16, + "gridPos": { "h": 5, "w": 4, "x": 0, "y": 25 }, + "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "targets": [ { "refId": "A", "expr": "prospection_brief_rendered", "instant": true, "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" } } ], + "fieldConfig": { "defaults": { "mappings": [ { "type": "value", "options": { "0": { "text": "non", "color": "red", "index": 0 }, "1": { "text": "oui", "color": "green", "index": 1 } } } ], "thresholds": { "mode": "absolute", "steps": [ { "color": "red", "value": null }, { "color": "green", "value": 1 } ] } }, "overrides": [] }, + "options": { "colorMode": "background", "graphMode": "none", "reduceOptions": { "calcs": ["lastNotNull"] } } + }, + { + "type": "stat", "title": "Poussé sur Telegram", "id": 17, + "gridPos": { "h": 5, "w": 4, "x": 4, "y": 25 }, + "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "targets": [ { "refId": "A", "expr": "prospection_brief_telegram_pushed", "instant": true, "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" } } ], + "fieldConfig": { "defaults": { "mappings": [ { "type": "value", "options": { "0": { "text": "non", "color": "red", "index": 0 }, "1": { "text": "oui", "color": "green", "index": 1 } } } ], "thresholds": { "mode": "absolute", "steps": [ { "color": "red", "value": null }, { "color": "green", "value": 1 } ] } }, "overrides": [] }, + "options": { "colorMode": "background", "graphMode": "none", "reduceOptions": { "calcs": ["lastNotNull"] } } + }, + { + "type": "stat", "title": "Messages / mission", "id": 18, + "gridPos": { "h": 5, "w": 4, "x": 8, "y": 25 }, + "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "targets": [ { "refId": "A", "expr": "prospection_telegram_messages_sent", "instant": true, "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" } } ], + "fieldConfig": { "defaults": { "thresholds": { "mode": "absolute", "steps": [ { "color": "blue", "value": null } ] } }, "overrides": [] }, + "options": { "colorMode": "value", "graphMode": "area", "reduceOptions": { "calcs": ["lastNotNull"] } } + }, + { + "type": "stat", "title": "Vidéo brief", "id": 19, + "gridPos": { "h": 5, "w": 4, "x": 12, "y": 25 }, + "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "targets": [ { "refId": "A", "expr": "prospection_brief_video_kb * 1024", "instant": true, "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" } } ], + "fieldConfig": { "defaults": { "unit": "bytes", "thresholds": { "mode": "absolute", "steps": [ { "color": "blue", "value": null } ] } }, "overrides": [] }, + "options": { "colorMode": "value", "graphMode": "none", "reduceOptions": { "calcs": ["lastNotNull"] } } + }, + { + "type": "table", "title": "Alertes prospection actives", "id": 20, + "gridPos": { "h": 5, "w": 8, "x": 16, "y": 25 }, + "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "targets": [ { "refId": "A", "expr": "ALERTS{alertname=~\"Prospection.*\", alertstate=\"firing\"}", "instant": true, "format": "table", "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" } } ], + "transformations": [ + { "id": "organize", "options": { + "excludeByName": { "Time": true, "Value": true, "__name__": true, "job": true, "instance": true, "alertstate": true }, + "renameByName": { "alertname": "Alerte", "severity": "Sévérité" } + } } + ], + "fieldConfig": { "defaults": { "custom": { "align": "auto" } }, "overrides": [] }, + "options": { "showHeader": true, "footer": { "show": false } } + } + ] + } # default: # some-dashboard: diff --git a/prometheus/values.yaml b/prometheus/values.yaml index b131bf6..eba525a 100644 --- a/prometheus/values.yaml +++ b/prometheus/values.yaml @@ -1115,7 +1115,59 @@ prometheus: &prometheus_config serverFiles: ## Alerts configuration ## Ref: https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/ - alerting_rules.yml: {} + alerting_rules.yml: + groups: + # Pipeline prospection (métriques poussées au Pushgateway job=prospection en fin de + # run). NB : la LIVRAISON des alertes (Alertmanager → Telegram/…) n'est pas encore + # câblée dans ce cluster — ces règles s'évaluent et sont visibles dans Prometheus + # /alerts + le dashboard Grafana « Prospection » (panneau Alertes actives). + - name: prospection + rules: + - alert: ProspectionRunStale + expr: time() - prospection_run_timestamp_seconds > 90000 # > 25 h (cron quotidien) + for: 10m + labels: + severity: warning + app: prospection + annotations: + summary: "Prospection — aucun run réussi depuis plus de 25 h" + description: "Dernier run réussi il y a {{ $value | humanizeDuration }} ; le CronJob quotidien (~06:30 UTC) n'a pas abouti." + - alert: ProspectionRunFailed + expr: prospection_run_success == 0 + for: 5m + labels: + severity: warning + app: prospection + annotations: + summary: "Prospection — le dernier run a échoué" + description: "prospection_run_success=0 : toutes les collectes ont échoué au dernier run." + - alert: ProspectionStepError + expr: prospection_step_status == 0 + for: 5m + labels: + severity: info + app: prospection + annotations: + summary: "Prospection — étape {{ $labels.step }} en erreur" + description: "L'étape {{ $labels.step }} du pipeline a fini en erreur au dernier run." + - alert: ProspectionNoOffers + expr: prospection_offers_total == 0 + for: 15m + labels: + severity: warning + app: prospection + annotations: + summary: "Prospection — 0 offre (mission) collectée" + description: "Aucune offre au dernier run : collecte France Travail / Free-Work potentiellement cassée." + - alert: ProspectionBriefNotSent + expr: prospection_brief_telegram_pushed == 0 + for: 15m + labels: + severity: info + app: prospection + annotations: + summary: "Prospection — brief non poussé sur Telegram" + description: "Le brief vidéo n'a pas été diffusé sur Telegram au dernier run." # groups: # - name: Instances # rules: -- 2.54.0