chore(ci): remove smoke tests from preprod and prod pipelines
All checks were successful
CD Preprod / Backend — Lint (push) Successful in 10m22s
CD Preprod / Frontend — Lint & Type-check (push) Successful in 10m55s
CD Preprod / Backend — Unit Tests (push) Successful in 10m10s
CD Preprod / Frontend — Unit Tests (push) Successful in 10m34s
CD Preprod / Backend — Integration Tests (push) Successful in 9m57s
CD Preprod / Build Frontend (push) Successful in 47s
CD Preprod / Build Log Exporter (push) Successful in 33s
CD Preprod / Build Backend (push) Successful in 7m24s
CD Preprod / Deploy to Preprod (push) Successful in 24s
CD Preprod / Notify Failure (push) Has been skipped
CD Preprod / Notify Success (push) Successful in 2s

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
David 2026-04-06 20:13:17 +02:00
parent a5b21436c7
commit 40d917e160
6 changed files with 293 additions and 462 deletions

View File

@ -10,7 +10,7 @@ name: CD Production
# If someone merges to main without going through preprod, # If someone merges to main without going through preprod,
# this step fails and the deployment is blocked. # this step fails and the deployment is blocked.
# #
# Flow: quality-gate → verify-image → promote → deploy → smoke-tests → notify # Flow: quality-gate → verify-image → promote → deploy → notify
# #
# Secrets required: # Secrets required:
# REGISTRY_TOKEN — Scaleway registry (read/write) # REGISTRY_TOKEN — Scaleway registry (read/write)
@ -231,47 +231,11 @@ jobs:
kubectl rollout status deployment/xpeditis-frontend -n ${{ env.K8S_NAMESPACE }} --timeout=120s kubectl rollout status deployment/xpeditis-frontend -n ${{ env.K8S_NAMESPACE }} --timeout=120s
echo "Rollback complete. Previous version is live." echo "Rollback complete. Previous version is live."
# ── 5. Smoke Tests ───────────────────────────────────────────────────
# kubectl rollout status already verified pod readiness.
# These smoke tests validate the full network path:
# Cloudflare → Hetzner LB → Traefik → pod.
smoke-tests:
name: Smoke Tests
runs-on: ubuntu-latest
needs: deploy
steps:
- name: Wait for LB propagation
run: sleep 30
- name: Health — Backend
run: |
for i in {1..12}; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 \
"${{ secrets.PROD_BACKEND_URL }}/api/v1/health" 2>/dev/null || echo "000")
echo " Attempt $i: HTTP $STATUS"
if [ "$STATUS" = "200" ]; then echo "Backend OK."; exit 0; fi
sleep 15
done
echo "CRITICAL: Backend unreachable after 12 attempts."
exit 1
- name: Health — Frontend
run: |
for i in {1..12}; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 \
"${{ secrets.PROD_FRONTEND_URL }}" 2>/dev/null || echo "000")
echo " Attempt $i: HTTP $STATUS"
if [ "$STATUS" = "200" ]; then echo "Frontend OK."; exit 0; fi
sleep 15
done
echo "CRITICAL: Frontend unreachable after 12 attempts."
exit 1
# ── Notifications ──────────────────────────────────────────────────── # ── Notifications ────────────────────────────────────────────────────
notify-success: notify-success:
name: Notify Success name: Notify Success
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [verify-image, smoke-tests] needs: [verify-image, deploy]
if: success() if: success()
steps: steps:
- run: | - run: |
@ -292,7 +256,7 @@ jobs:
notify-failure: notify-failure:
name: Notify Failure name: Notify Failure
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [backend-quality, frontend-quality, backend-tests, frontend-tests, verify-image, promote-images, deploy, smoke-tests] needs: [backend-quality, frontend-quality, backend-tests, frontend-tests, verify-image, promote-images, deploy]
if: failure() if: failure()
steps: steps:
- run: | - run: |

View File

@ -1,7 +1,7 @@
name: CD Preprod name: CD Preprod
# Full pipeline triggered on every push to preprod. # Full pipeline triggered on every push to preprod.
# Flow: lint → unit tests → integration tests → docker build → deploy → smoke tests → notify # Flow: lint → unit tests → integration tests → docker build → deploy → notify
# #
# Secrets required: # Secrets required:
# REGISTRY_TOKEN — Scaleway registry (read/write) # REGISTRY_TOKEN — Scaleway registry (read/write)
@ -274,42 +274,11 @@ jobs:
fi fi
echo "Frontend webhook triggered." echo "Frontend webhook triggered."
# ── 6. Smoke Tests ───────────────────────────────────────────────────
smoke-tests:
name: Smoke Tests
runs-on: ubuntu-latest
needs: deploy
steps:
- name: Wait for services
run: sleep 40
- name: Health — Backend
run: |
for i in {1..12}; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 \
"${{ secrets.PREPROD_BACKEND_URL }}/api/v1/health" 2>/dev/null || echo "000")
echo " Attempt $i: HTTP $STATUS"
if [ "$STATUS" = "200" ]; then echo "Backend OK."; exit 0; fi
sleep 15
done
echo "Backend unreachable after 12 attempts."
exit 1
- name: Health — Frontend
run: |
for i in {1..12}; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 \
"${{ secrets.PREPROD_FRONTEND_URL }}" 2>/dev/null || echo "000")
echo " Attempt $i: HTTP $STATUS"
if [ "$STATUS" = "200" ]; then echo "Frontend OK."; exit 0; fi
sleep 15
done
echo "Frontend unreachable after 12 attempts."
exit 1
# ── Notifications ──────────────────────────────────────────────────── # ── Notifications ────────────────────────────────────────────────────
notify-success: notify-success:
name: Notify Success name: Notify Success
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [build-backend, build-frontend, smoke-tests] needs: [build-backend, build-frontend, deploy]
if: success() if: success()
steps: steps:
- run: | - run: |
@ -329,7 +298,7 @@ jobs:
notify-failure: notify-failure:
name: Notify Failure name: Notify Failure
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [backend-quality, frontend-quality, backend-tests, frontend-tests, integration-tests, build-backend, build-frontend, deploy, smoke-tests] needs: [backend-quality, frontend-quality, backend-tests, frontend-tests, integration-tests, build-backend, build-frontend, deploy]
if: failure() if: failure()
steps: steps:
- run: | - run: |

View File

@ -1,6 +1,8 @@
import { Controller, Get } from '@nestjs/common'; import { Controller, Get } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
import { Public } from '../decorators/public.decorator';
@Public()
@ApiTags('health') @ApiTags('health')
@Controller('health') @Controller('health')
export class HealthController { export class HealthController {

View File

@ -1,32 +1,37 @@
{ {
"title": "Xpeditis — Logs & Monitoring", "__inputs": [
"uid": "xpeditis-logs", {
"description": "Dashboard complet — logs backend/frontend, métriques HTTP, erreurs", "name": "DS_LOKI",
"tags": ["xpeditis", "logs", "backend", "frontend"], "label": "Loki",
"timezone": "browser", "description": "Loki datasource",
"type": "datasource",
"pluginId": "loki",
"pluginName": "Loki"
}
],
"__requires": [
{ "type": "grafana", "id": "grafana", "name": "Grafana", "version": "11.0.0" },
{ "type": "datasource", "id": "loki", "name": "Loki", "version": "1.0.0" },
{ "type": "panel", "id": "stat", "name": "Stat", "version": "" },
{ "type": "panel", "id": "timeseries", "name": "Time series", "version": "" },
{ "type": "panel", "id": "piechart", "name": "Pie chart", "version": "" },
{ "type": "panel", "id": "bargauge", "name": "Bar gauge", "version": "" },
{ "type": "panel", "id": "logs", "name": "Logs", "version": "" }
],
"title": "Xpeditis — Logs & KPIs",
"uid": "xpeditis-logs-kpis",
"description": "Logs applicatifs, KPIs HTTP, temps de réponse et erreurs — Backend & Frontend",
"tags": ["xpeditis", "logs", "monitoring", "backend"],
"timezone": "Europe/Paris",
"refresh": "30s", "refresh": "30s",
"schemaVersion": 38, "schemaVersion": 39,
"time": { "from": "now-1h", "to": "now" }, "time": { "from": "now-1h", "to": "now" },
"timepicker": {}, "timepicker": {},
"fiscalYearStartMonth": 0,
"graphTooltip": 1, "graphTooltip": 1,
"editable": true, "editable": true,
"version": 1, "version": 1,
"weekStart": "",
"links": [], "links": [],
"annotations": { "annotations": { "list": [] },
"list": [
{
"builtIn": 1,
"datasource": { "type": "grafana", "uid": "-- Grafana --" },
"enable": true,
"hide": true,
"iconColor": "rgba(0,211,255,1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"templating": { "templating": {
"list": [ "list": [
@ -34,119 +39,99 @@
"name": "service", "name": "service",
"label": "Service", "label": "Service",
"type": "query", "type": "query",
"datasource": { "type": "loki", "uid": "loki-xpeditis" }, "datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"query": "label_values(service)", "query": "label_values(service)",
"refresh": 2, "refresh": 2,
"sort": 1,
"includeAll": true, "includeAll": true,
"allValue": ".+", "allValue": ".+",
"multi": false, "multi": true,
"hide": 0,
"current": {}, "current": {},
"options": [] "hide": 0,
"sort": 1
}, },
{ {
"name": "level", "name": "level",
"label": "Niveau", "label": "Niveau",
"type": "custom", "type": "query",
"query": "All : .+, error : error, fatal : fatal, warn : warn, info : info, debug : debug", "datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"includeAll": false, "query": "label_values(level)",
"multi": false, "refresh": 2,
"includeAll": true,
"allValue": ".+",
"multi": true,
"current": {},
"hide": 0, "hide": 0,
"current": { "text": "All", "value": ".+" }, "sort": 1
"options": [
{ "text": "All", "value": ".+", "selected": true },
{ "text": "error", "value": "error", "selected": false },
{ "text": "fatal", "value": "fatal", "selected": false },
{ "text": "warn", "value": "warn", "selected": false },
{ "text": "info", "value": "info", "selected": false },
{ "text": "debug", "value": "debug", "selected": false }
]
},
{
"name": "search",
"label": "Recherche",
"type": "textbox",
"query": "",
"hide": 0,
"current": { "text": "", "value": "" },
"options": [{ "selected": true, "text": "", "value": "" }]
} }
] ]
}, },
"panels": [ "panels": [
{
"id": 100,
"type": "row",
"title": "Vue d'ensemble",
"collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 0 }
},
{ {
"id": 1, "id": 1,
"title": "Total logs", "title": "Requêtes totales",
"type": "stat", "type": "stat",
"gridPos": { "h": 4, "w": 4, "x": 0, "y": 1 }, "gridPos": { "x": 0, "y": 0, "w": 6, "h": 4 },
"datasource": { "type": "loki", "uid": "loki-xpeditis" }, "datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"options": { "options": {
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false }, "reduceOptions": { "calcs": ["sum"], "fields": "", "values": false },
"orientation": "auto", "orientation": "auto",
"textMode": "auto", "textMode": "auto",
"colorMode": "background", "colorMode": "background",
"graphMode": "area", "graphMode": "none",
"justifyMode": "center" "justifyMode": "center"
}, },
"fieldConfig": { "fieldConfig": {
"defaults": { "defaults": {
"color": { "mode": "thresholds" }, "color": { "mode": "fixed", "fixedColor": "#10183A" },
"thresholds": { "mode": "absolute", "steps": [{ "color": "blue", "value": null }] }, "unit": "short",
"mappings": [] "thresholds": { "mode": "absolute", "steps": [{ "color": "#10183A", "value": null }] }
}, },
"overrides": [] "overrides": []
}, },
"targets": [ "targets": [
{ {
"refId": "A", "datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"datasource": { "type": "loki", "uid": "loki-xpeditis" }, "expr": "sum(count_over_time({service=~\"$service\"} | json | req_method != \"\" [$__range]))",
"expr": "sum(count_over_time({service=~\"$service\"} [$__range]))", "legendFormat": "Requêtes",
"legendFormat": "Total", "instant": true,
"instant": true "range": false,
"refId": "A"
} }
] ]
}, },
{ {
"id": 2, "id": 2,
"title": "Erreurs & Fatal", "title": "Erreurs (error + fatal)",
"type": "stat", "type": "stat",
"gridPos": { "h": 4, "w": 4, "x": 4, "y": 1 }, "gridPos": { "x": 6, "y": 0, "w": 6, "h": 4 },
"datasource": { "type": "loki", "uid": "loki-xpeditis" }, "datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"options": { "options": {
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false }, "reduceOptions": { "calcs": ["sum"], "fields": "", "values": false },
"orientation": "auto", "orientation": "auto",
"textMode": "auto", "textMode": "auto",
"colorMode": "background", "colorMode": "background",
"graphMode": "area", "graphMode": "none",
"justifyMode": "center" "justifyMode": "center"
}, },
"fieldConfig": { "fieldConfig": {
"defaults": { "defaults": {
"color": { "mode": "thresholds" }, "color": { "mode": "fixed", "fixedColor": "red" },
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }, { "color": "red", "value": 1 }] }, "unit": "short",
"mappings": [] "thresholds": { "mode": "absolute", "steps": [{ "color": "red", "value": null }] }
}, },
"overrides": [] "overrides": []
}, },
"targets": [ "targets": [
{ {
"refId": "A", "datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"datasource": { "type": "loki", "uid": "loki-xpeditis" },
"expr": "sum(count_over_time({service=~\"$service\", level=~\"error|fatal\"} [$__range]))", "expr": "sum(count_over_time({service=~\"$service\", level=~\"error|fatal\"} [$__range]))",
"legendFormat": "Erreurs", "legendFormat": "Erreurs",
"instant": true "instant": true,
"range": false,
"refId": "A"
} }
] ]
}, },
@ -155,342 +140,342 @@
"id": 3, "id": 3,
"title": "Warnings", "title": "Warnings",
"type": "stat", "type": "stat",
"gridPos": { "h": 4, "w": 4, "x": 8, "y": 1 }, "gridPos": { "x": 12, "y": 0, "w": 6, "h": 4 },
"datasource": { "type": "loki", "uid": "loki-xpeditis" }, "datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"options": { "options": {
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false }, "reduceOptions": { "calcs": ["sum"], "fields": "", "values": false },
"orientation": "auto", "orientation": "auto",
"textMode": "auto", "textMode": "auto",
"colorMode": "background", "colorMode": "background",
"graphMode": "area", "graphMode": "none",
"justifyMode": "center" "justifyMode": "center"
}, },
"fieldConfig": { "fieldConfig": {
"defaults": { "defaults": {
"color": { "mode": "thresholds" }, "color": { "mode": "fixed", "fixedColor": "orange" },
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }, { "color": "orange", "value": 1 }] }, "unit": "short",
"mappings": [] "thresholds": { "mode": "absolute", "steps": [{ "color": "orange", "value": null }] }
}, },
"overrides": [] "overrides": []
}, },
"targets": [ "targets": [
{ {
"refId": "A", "datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"datasource": { "type": "loki", "uid": "loki-xpeditis" },
"expr": "sum(count_over_time({service=~\"$service\", level=\"warn\"} [$__range]))", "expr": "sum(count_over_time({service=~\"$service\", level=\"warn\"} [$__range]))",
"legendFormat": "Warnings", "legendFormat": "Warnings",
"instant": true "instant": true,
"range": false,
"refId": "A"
} }
] ]
}, },
{ {
"id": 4, "id": 4,
"title": "Info", "title": "Taux d'erreur",
"type": "stat", "type": "stat",
"gridPos": { "h": 4, "w": 4, "x": 12, "y": 1 }, "gridPos": { "x": 18, "y": 0, "w": 6, "h": 4 },
"datasource": { "type": "loki", "uid": "loki-xpeditis" }, "datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"options": { "options": {
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false }, "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false },
"orientation": "auto", "orientation": "auto",
"textMode": "auto", "textMode": "auto",
"colorMode": "background", "colorMode": "background",
"graphMode": "area", "graphMode": "none",
"justifyMode": "center" "justifyMode": "center"
}, },
"fieldConfig": { "fieldConfig": {
"defaults": { "defaults": {
"color": { "fixedColor": "blue", "mode": "fixed" }, "unit": "percentunit",
"thresholds": { "mode": "absolute", "steps": [{ "color": "blue", "value": null }] }, "thresholds": {
"mappings": [] "mode": "absolute",
"steps": [
{ "color": "green", "value": null },
{ "color": "orange", "value": 0.01 },
{ "color": "red", "value": 0.05 }
]
},
"color": { "mode": "thresholds" }
}, },
"overrides": [] "overrides": []
}, },
"targets": [ "targets": [
{ {
"refId": "A", "datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"datasource": { "type": "loki", "uid": "loki-xpeditis" }, "expr": "sum(rate({service=~\"$service\", level=~\"error|fatal\"} [$__interval])) / sum(rate({service=~\"$service\"} [$__interval]))",
"expr": "sum(count_over_time({service=~\"$service\", level=\"info\"} [$__range]))", "legendFormat": "Taux d'erreur",
"legendFormat": "Info", "instant": false,
"instant": true "range": true,
"refId": "A"
} }
] ]
}, },
{ {
"id": 5, "id": 5,
"title": "Requêtes HTTP 5xx", "title": "Trafic par service (req/s)",
"type": "stat", "type": "timeseries",
"gridPos": { "h": 4, "w": 4, "x": 16, "y": 1 }, "gridPos": { "x": 0, "y": 4, "w": 12, "h": 8 },
"datasource": { "type": "loki", "uid": "loki-xpeditis" }, "datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"options": { "options": {
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false }, "tooltip": { "mode": "multi", "sort": "desc" },
"orientation": "auto", "legend": { "displayMode": "list", "placement": "bottom" }
"textMode": "auto",
"colorMode": "background",
"graphMode": "area",
"justifyMode": "center"
}, },
"fieldConfig": { "fieldConfig": {
"defaults": { "defaults": {
"color": { "mode": "thresholds" }, "unit": "reqps",
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }, { "color": "red", "value": 1 }] }, "color": { "mode": "palette-classic" },
"mappings": [] "custom": {
"lineWidth": 2,
"fillOpacity": 10,
"gradientMode": "opacity",
"spanNulls": false
}
}, },
"overrides": [] "overrides": []
}, },
"targets": [ "targets": [
{ {
"refId": "A", "datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"datasource": { "type": "loki", "uid": "loki-xpeditis" }, "expr": "sum by(service) (rate({service=~\"$service\"} | json | req_method != \"\" [$__interval]))",
"expr": "sum(count_over_time({service=\"backend\"} | json | res_statusCode >= 500 [$__range]))", "legendFormat": "{{service}}",
"legendFormat": "5xx", "instant": false,
"instant": true "range": true,
"refId": "A"
} }
] ]
}, },
{ {
"id": 6, "id": 6,
"title": "Temps réponse moyen (ms)", "title": "Erreurs & Warnings dans le temps",
"type": "stat", "type": "timeseries",
"gridPos": { "h": 4, "w": 4, "x": 20, "y": 1 }, "gridPos": { "x": 12, "y": 4, "w": 12, "h": 8 },
"datasource": { "type": "loki", "uid": "loki-xpeditis" }, "datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"options": { "options": {
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false }, "tooltip": { "mode": "multi", "sort": "desc" },
"orientation": "auto", "legend": { "displayMode": "list", "placement": "bottom" }
"textMode": "auto",
"colorMode": "background",
"graphMode": "area",
"justifyMode": "center"
}, },
"fieldConfig": { "fieldConfig": {
"defaults": { "defaults": {
"color": { "mode": "thresholds" }, "unit": "short",
"unit": "ms", "color": { "mode": "palette-classic" },
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }, { "color": "orange", "value": 500 }, { "color": "red", "value": 2000 }] }, "custom": {
"mappings": [] "lineWidth": 2,
"fillOpacity": 15,
"gradientMode": "opacity"
}
}, },
"overrides": [] "overrides": [
{
"matcher": { "id": "byName", "options": "error" },
"properties": [{ "id": "color", "value": { "mode": "fixed", "fixedColor": "red" } }]
},
{
"matcher": { "id": "byName", "options": "fatal" },
"properties": [{ "id": "color", "value": { "mode": "fixed", "fixedColor": "dark-red" } }]
},
{
"matcher": { "id": "byName", "options": "warn" },
"properties": [{ "id": "color", "value": { "mode": "fixed", "fixedColor": "orange" } }]
}
]
}, },
"targets": [ "targets": [
{ {
"refId": "A", "datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"datasource": { "type": "loki", "uid": "loki-xpeditis" }, "expr": "sum by(level) (rate({service=~\"$service\", level=~\"error|fatal|warn\"} [$__interval]))",
"expr": "avg(avg_over_time({service=\"backend\"} | json | unwrap responseTime [$__range]))", "legendFormat": "{{level}}",
"legendFormat": "Avg", "instant": false,
"instant": true "range": true,
"refId": "A"
} }
] ]
}, },
{
"id": 200,
"type": "row",
"title": "Volume des logs",
"collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 5 }
},
{ {
"id": 7, "id": 7,
"title": "Volume par niveau", "title": "Temps de réponse Backend",
"type": "timeseries", "type": "timeseries",
"gridPos": { "h": 8, "w": 14, "x": 0, "y": 6 }, "gridPos": { "x": 0, "y": 12, "w": 16, "h": 8 },
"datasource": { "type": "loki", "uid": "loki-xpeditis" }, "datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"options": { "options": {
"legend": { "calcs": ["sum"], "displayMode": "list", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "multi", "sort": "desc" },
"tooltip": { "mode": "multi", "sort": "desc" } "legend": { "displayMode": "list", "placement": "bottom" }
}, },
"fieldConfig": { "fieldConfig": {
"defaults": { "defaults": {
"unit": "ms",
"color": { "mode": "palette-classic" }, "color": { "mode": "palette-classic" },
"custom": { "custom": {
"drawStyle": "bars", "lineWidth": 2,
"fillOpacity": 80, "fillOpacity": 8,
"stacking": { "group": "A", "mode": "normal" }, "gradientMode": "opacity"
"lineWidth": 1,
"pointSize": 5,
"showPoints": "never",
"spanNulls": false
}, },
"unit": "short", "thresholds": {
"mappings": [], "mode": "absolute",
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] } "steps": [
{ "color": "green", "value": null },
{ "color": "orange", "value": 500 },
{ "color": "red", "value": 1000 }
]
}
}, },
"overrides": [ "overrides": [
{ "matcher": { "id": "byName", "options": "error" }, "properties": [{ "id": "color", "value": { "fixedColor": "red", "mode": "fixed" } }] }, {
{ "matcher": { "id": "byName", "options": "fatal" }, "properties": [{ "id": "color", "value": { "fixedColor": "dark-red", "mode": "fixed" } }] }, "matcher": { "id": "byName", "options": "Pire cas (1% des requêtes)" },
{ "matcher": { "id": "byName", "options": "warn" }, "properties": [{ "id": "color", "value": { "fixedColor": "orange", "mode": "fixed" } }] }, "properties": [{ "id": "color", "value": { "mode": "fixed", "fixedColor": "red" } }]
{ "matcher": { "id": "byName", "options": "info" }, "properties": [{ "id": "color", "value": { "fixedColor": "blue", "mode": "fixed" } }] }, },
{ "matcher": { "id": "byName", "options": "debug" }, "properties": [{ "id": "color", "value": { "fixedColor": "gray", "mode": "fixed" } }] } {
"matcher": { "id": "byName", "options": "Lent (5% des requêtes)" },
"properties": [{ "id": "color", "value": { "mode": "fixed", "fixedColor": "orange" } }]
},
{
"matcher": { "id": "byName", "options": "Temps médian (requête typique)" },
"properties": [{ "id": "color", "value": { "mode": "fixed", "fixedColor": "#34CCCD" } }]
}
] ]
}, },
"targets": [ "targets": [
{ {
"refId": "A", "datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"datasource": { "type": "loki", "uid": "loki-xpeditis" }, "expr": "quantile_over_time(0.50, {service=\"backend\"} | json | responseTime > 0 | unwrap responseTime [$__interval])",
"expr": "sum by (level) (count_over_time({service=~\"$service\", level=~\".+\"} [$__interval]))", "legendFormat": "Temps médian (requête typique)",
"legendFormat": "{{level}}" "instant": false,
"range": true,
"refId": "A"
},
{
"datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"expr": "quantile_over_time(0.95, {service=\"backend\"} | json | responseTime > 0 | unwrap responseTime [$__interval])",
"legendFormat": "Lent (5% des requêtes)",
"instant": false,
"range": true,
"refId": "B"
},
{
"datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"expr": "quantile_over_time(0.99, {service=\"backend\"} | json | responseTime > 0 | unwrap responseTime [$__interval])",
"legendFormat": "Pire cas (1% des requêtes)",
"instant": false,
"range": true,
"refId": "C"
} }
] ]
}, },
{ {
"id": 8, "id": 8,
"title": "Volume par service", "title": "Répartition par niveau de log",
"type": "timeseries", "type": "piechart",
"gridPos": { "h": 8, "w": 10, "x": 14, "y": 6 }, "gridPos": { "x": 16, "y": 12, "w": 8, "h": 8 },
"datasource": { "type": "loki", "uid": "loki-xpeditis" }, "datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"options": { "options": {
"legend": { "calcs": ["sum"], "displayMode": "list", "placement": "bottom", "showLegend": true }, "pieType": "donut",
"tooltip": { "mode": "multi", "sort": "desc" } "tooltip": { "mode": "single" },
"legend": { "displayMode": "list", "placement": "bottom", "values": ["percent"] }
}, },
"fieldConfig": { "fieldConfig": {
"defaults": { "defaults": { "unit": "short", "color": { "mode": "palette-classic" } },
"color": { "mode": "palette-classic" }, "overrides": [
"custom": { { "matcher": { "id": "byName", "options": "error" }, "properties": [{ "id": "color", "value": { "mode": "fixed", "fixedColor": "red" } }] },
"drawStyle": "bars", { "matcher": { "id": "byName", "options": "fatal" }, "properties": [{ "id": "color", "value": { "mode": "fixed", "fixedColor": "dark-red" } }] },
"fillOpacity": 60, { "matcher": { "id": "byName", "options": "warn" }, "properties": [{ "id": "color", "value": { "mode": "fixed", "fixedColor": "orange" } }] },
"stacking": { "group": "A", "mode": "normal" }, { "matcher": { "id": "byName", "options": "info" }, "properties": [{ "id": "color", "value": { "mode": "fixed", "fixedColor": "#34CCCD" } }] },
"lineWidth": 1, { "matcher": { "id": "byName", "options": "debug" }, "properties": [{ "id": "color", "value": { "mode": "fixed", "fixedColor": "blue" } }] }
"showPoints": "never", ]
"spanNulls": false
},
"unit": "short",
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] }
},
"overrides": []
}, },
"targets": [ "targets": [
{ {
"refId": "A", "datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"datasource": { "type": "loki", "uid": "loki-xpeditis" }, "expr": "sum by(level) (count_over_time({service=~\"$service\", level=~\"$level\"} [$__range]))",
"expr": "sum by (service) (count_over_time({service=~\"$service\"} [$__interval]))", "legendFormat": "{{level}}",
"legendFormat": "{{service}}" "instant": true,
"range": false,
"refId": "A"
} }
] ]
}, },
{
"id": 300,
"type": "row",
"title": "HTTP — Backend",
"collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 14 }
},
{ {
"id": 9, "id": 9,
"title": "Taux d'erreur HTTP", "title": "Codes HTTP (5m)",
"type": "timeseries", "type": "bargauge",
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 15 }, "gridPos": { "x": 0, "y": 20, "w": 12, "h": 8 },
"datasource": { "type": "loki", "uid": "loki-xpeditis" }, "datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"options": { "options": {
"legend": { "calcs": ["max", "mean"], "displayMode": "list", "placement": "bottom", "showLegend": true }, "orientation": "horizontal",
"tooltip": { "mode": "multi", "sort": "desc" } "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false },
"displayMode": "gradient",
"valueMode": "color",
"showUnfilled": true,
"minVizWidth": 10,
"minVizHeight": 10
}, },
"fieldConfig": { "fieldConfig": {
"defaults": { "defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"drawStyle": "line",
"fillOpacity": 20,
"lineWidth": 2,
"pointSize": 5,
"showPoints": "never",
"spanNulls": false
},
"unit": "short", "unit": "short",
"mappings": [], "color": { "mode": "palette-classic" },
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] } "thresholds": {
}, "mode": "absolute",
"overrides": [ "steps": [
{ "matcher": { "id": "byName", "options": "5xx" }, "properties": [{ "id": "color", "value": { "fixedColor": "red", "mode": "fixed" } }] }, { "color": "green", "value": null },
{ "matcher": { "id": "byName", "options": "4xx" }, "properties": [{ "id": "color", "value": { "fixedColor": "orange", "mode": "fixed" } }] }, { "color": "orange", "value": 1 }
{ "matcher": { "id": "byName", "options": "2xx" }, "properties": [{ "id": "color", "value": { "fixedColor": "green", "mode": "fixed" } }] }
] ]
}
},
"overrides": []
}, },
"targets": [ "targets": [
{ {
"refId": "A", "datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"datasource": { "type": "loki", "uid": "loki-xpeditis" }, "expr": "sum by(status_code) (count_over_time({service=\"backend\"} | json | res_statusCode != \"\" | label_format status_code=\"{{res_statusCode}}\" [$__range]))",
"expr": "sum(count_over_time({service=\"backend\"} | json | res_statusCode >= 500 [$__interval]))", "legendFormat": "HTTP {{status_code}}",
"legendFormat": "5xx" "instant": true,
}, "range": false,
{ "refId": "A"
"refId": "B",
"datasource": { "type": "loki", "uid": "loki-xpeditis" },
"expr": "sum(count_over_time({service=\"backend\"} | json | res_statusCode >= 400 < 500 [$__interval]))",
"legendFormat": "4xx"
},
{
"refId": "C",
"datasource": { "type": "loki", "uid": "loki-xpeditis" },
"expr": "sum(count_over_time({service=\"backend\"} | json | res_statusCode >= 200 < 300 [$__interval]))",
"legendFormat": "2xx"
} }
] ]
}, },
{ {
"id": 10, "id": 10,
"title": "Temps de réponse (ms)", "title": "Top erreurs par contexte NestJS",
"type": "timeseries", "type": "bargauge",
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 15 }, "gridPos": { "x": 12, "y": 20, "w": 12, "h": 8 },
"datasource": { "type": "loki", "uid": "loki-xpeditis" }, "datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"options": { "options": {
"legend": { "calcs": ["max", "mean"], "displayMode": "list", "placement": "bottom", "showLegend": true }, "orientation": "horizontal",
"tooltip": { "mode": "multi", "sort": "desc" } "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false },
"displayMode": "gradient",
"showUnfilled": true
}, },
"fieldConfig": { "fieldConfig": {
"defaults": { "defaults": {
"color": { "mode": "palette-classic" }, "unit": "short",
"custom": { "color": { "mode": "fixed", "fixedColor": "red" },
"drawStyle": "line", "thresholds": { "mode": "absolute", "steps": [{ "color": "red", "value": null }] }
"fillOpacity": 10,
"lineWidth": 2,
"pointSize": 5,
"showPoints": "never",
"spanNulls": false
},
"unit": "ms",
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }, { "color": "orange", "value": 500 }, { "color": "red", "value": 2000 }] }
}, },
"overrides": [] "overrides": []
}, },
"targets": [ "targets": [
{ {
"refId": "A", "datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"datasource": { "type": "loki", "uid": "loki-xpeditis" }, "expr": "topk(10, sum by(context) (count_over_time({service=\"backend\", level=~\"error|fatal\"} | json | context != \"\" [$__range]) ))",
"expr": "avg(avg_over_time({service=\"backend\"} | json | unwrap responseTime [$__interval]))", "legendFormat": "{{context}}",
"legendFormat": "Moy" "instant": true,
}, "range": false,
{ "refId": "A"
"refId": "B",
"datasource": { "type": "loki", "uid": "loki-xpeditis" },
"expr": "max(max_over_time({service=\"backend\"} | json | unwrap responseTime [$__interval]))",
"legendFormat": "Max"
} }
] ]
}, },
{
"id": 400,
"type": "row",
"title": "Logs — Flux en direct",
"collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 23 }
},
{ {
"id": 11, "id": 11,
"title": "Backend — Logs", "title": "Logs — Backend",
"type": "logs", "type": "logs",
"gridPos": { "h": 14, "w": 12, "x": 0, "y": 24 }, "gridPos": { "x": 0, "y": 28, "w": 24, "h": 12 },
"datasource": { "type": "loki", "uid": "loki-xpeditis" }, "datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"options": { "options": {
"dedupStrategy": "none", "dedupStrategy": "none",
"enableLogDetails": true, "enableLogDetails": true,
@ -503,24 +488,27 @@
}, },
"targets": [ "targets": [
{ {
"datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"expr": "{service=\"backend\", level=~\"$level\"}",
"legendFormat": "",
"instant": false,
"range": true,
"refId": "A", "refId": "A",
"datasource": { "type": "loki", "uid": "loki-xpeditis" }, "maxLines": 500
"expr": "{service=\"backend\", level=~\"$level\"} |= \"$search\"",
"legendFormat": ""
} }
] ]
}, },
{ {
"id": 12, "id": 12,
"title": "Frontend — Logs", "title": "Logs — Frontend",
"type": "logs", "type": "logs",
"gridPos": { "h": 14, "w": 12, "x": 12, "y": 24 }, "gridPos": { "x": 0, "y": 40, "w": 24, "h": 10 },
"datasource": { "type": "loki", "uid": "loki-xpeditis" }, "datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"options": { "options": {
"dedupStrategy": "none", "dedupStrategy": "none",
"enableLogDetails": true, "enableLogDetails": true,
"prettifyLogMessage": true, "prettifyLogMessage": false,
"showCommonLabels": false, "showCommonLabels": false,
"showLabels": false, "showLabels": false,
"showTime": true, "showTime": true,
@ -529,105 +517,13 @@
}, },
"targets": [ "targets": [
{ {
"datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"expr": "{service=\"frontend\"}",
"legendFormat": "",
"instant": false,
"range": true,
"refId": "A", "refId": "A",
"datasource": { "type": "loki", "uid": "loki-xpeditis" }, "maxLines": 200
"expr": "{service=\"frontend\", level=~\"$level\"} |= \"$search\"",
"legendFormat": ""
}
]
},
{
"id": 500,
"type": "row",
"title": "Tous les logs filtrés",
"collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 38 }
},
{
"id": 13,
"title": "Flux filtré — $service / $level",
"description": "Utilisez les variables en haut pour filtrer par service, niveau ou mot-clé",
"type": "logs",
"gridPos": { "h": 14, "w": 24, "x": 0, "y": 39 },
"datasource": { "type": "loki", "uid": "loki-xpeditis" },
"options": {
"dedupStrategy": "none",
"enableLogDetails": true,
"prettifyLogMessage": true,
"showCommonLabels": false,
"showLabels": true,
"showTime": true,
"sortOrder": "Descending",
"wrapLogMessage": true
},
"targets": [
{
"refId": "A",
"datasource": { "type": "loki", "uid": "loki-xpeditis" },
"expr": "{service=~\"$service\", level=~\"$level\"} |= \"$search\"",
"legendFormat": ""
}
]
},
{
"id": 600,
"type": "row",
"title": "Erreurs & Exceptions",
"collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 53 }
},
{
"id": 14,
"title": "Erreurs — Backend",
"type": "logs",
"gridPos": { "h": 10, "w": 12, "x": 0, "y": 54 },
"datasource": { "type": "loki", "uid": "loki-xpeditis" },
"options": {
"dedupStrategy": "signature",
"enableLogDetails": true,
"prettifyLogMessage": true,
"showCommonLabels": false,
"showLabels": false,
"showTime": true,
"sortOrder": "Descending",
"wrapLogMessage": true
},
"targets": [
{
"refId": "A",
"datasource": { "type": "loki", "uid": "loki-xpeditis" },
"expr": "{service=\"backend\", level=~\"error|fatal\"}",
"legendFormat": ""
}
]
},
{
"id": 15,
"title": "Erreurs — Frontend",
"type": "logs",
"gridPos": { "h": 10, "w": 12, "x": 12, "y": 54 },
"datasource": { "type": "loki", "uid": "loki-xpeditis" },
"options": {
"dedupStrategy": "signature",
"enableLogDetails": true,
"prettifyLogMessage": true,
"showCommonLabels": false,
"showLabels": false,
"showTime": true,
"sortOrder": "Descending",
"wrapLogMessage": true
},
"targets": [
{
"refId": "A",
"datasource": { "type": "loki", "uid": "loki-xpeditis" },
"expr": "{service=\"frontend\", level=~\"error|fatal\"}",
"legendFormat": ""
} }
] ]
} }

View File

@ -5,7 +5,7 @@ datasources:
uid: loki-xpeditis uid: loki-xpeditis
type: loki type: loki
access: proxy access: proxy
url: http://loki:3100 url: http://xpeditis-loki:3100
isDefault: true isDefault: true
version: 1 version: 1
editable: false editable: false

View File

@ -21,7 +21,7 @@ scrape_configs:
values: ['logging=promtail'] values: ['logging=promtail']
relabel_configs: relabel_configs:
- source_labels: ['__meta_docker_container_label_com_docker_compose_service'] - source_labels: ['__meta_docker_container_label_logging_service']
target_label: service target_label: service
- source_labels: ['__meta_docker_container_name'] - source_labels: ['__meta_docker_container_name']
regex: '/?(.*)' regex: '/?(.*)'