🔔 Sentry – Le Guide Ultime
Deep Dive : Error Tracking, APM (Performance), Session Replay, Context, Breadcrumbs & SDKs.
1. C'est quoi Sentry ?
Monitoring d'application (APM) & Error Tracking. Ne plus dire "ça marche chez moi".
Error Tracking APM2. Concepts Clés
Le DSN (la clé), Event (l'erreur), Issue (le groupe). Grouping (Fingerprinting).
DSN Event Issue3. Installation (SDK)
Sentry.init(). Python (sentry-sdk), JS (@sentry/react), etc.
4. Capturer Erreurs
Auto (intégrations Django/React) vs Manuel (captureException, captureMessage).
5. 🚀 Enrichir le Contexte
La "vraie" puissance. setUser, setTag (filtrable), setExtra (data).
6. Breadcrumbs (Fil d'Ariane)
La "boîte noire" de l'utilisateur. Clics, requêtes réseau, logs avant l'erreur.
Breadcrumbs Debug7. Source Maps (JS)
Le "plugin" vital pour le JS (minifié/transpilé). sentry-cli upload-sourcemaps.
8. 📈 APM (Performance)
Application Performance Monitoring. tracesSampleRate. Transactions & Spans.
9. 📹 Session Replay
Revoir la session de l'utilisateur (DOM) en "vidéo". replaysSessionSampleRate.
10. Alerting & Intégrations
La finalité : être notifié (Slack, Teams, PagerDuty). "Issue Owners" (CODEOWNERS).
Alerts Slack11. SaaS vs Self-Hosted
sentry.io (SaaS) vs Auto-hébergement (Docker). Le "Business Source License" (BSL).
12. Outils & Liens
sentry-cli, GlitchTip (Alternative OSS), Docs.
Sentry est une plateforme de monitoring d'application (APM) open-source, centrée sur le suivi des erreurs (Error Tracking). Il est disponible en SaaS (sentry.io) ou en auto-hébergement.
Son but est de répondre à la phrase : "Ça marche sur ma machine !".
La Philosophie : Ne pas dépendre des utilisateurs
Avant Sentry (Le "Passé") :
1. Une erreur 500 se produit en production.
2. L'utilisateur voit une page "Oops". Il est frustré.
3. (Peut-être) Il contacte le support en disant "ça marche pas".
4. Le développeur doit "chasser" l'erreur dans 10 Go de fichiers logs (grep, awk...).
Avec Sentry (Le "Moderne") :
1. Une erreur 500 se produit en production.
2. Le SDK Sentry (installé dans l'app) intercepte l'erreur, collecte le contexte (qui, quoi, où), et l'envoie à Sentry.
3. Sentry regroupe l'erreur, l'analyse, et notifie l'équipe (Slack/Email) *avant même que l'utilisateur n'ait contacté le support*.
4. Le développeur reçoit un lien avec la stack trace exacte, l'utilisateur impacté, les "breadcrumbs" (clics) avant l'erreur, etc.
Les 3 Piliers de Sentry
- Error Tracking : Le cœur. Capturer et regrouper les exceptions (Python, JS, Java, .NET...).
- Performance (APM) : Identifier les requêtes lentes (
N+1 query), les goulots d'étranglement (Transactions & Spans). - Session Replay : (Frontend) "Filmer" la session du DOM de l'utilisateur pour voir *exactement* ce qu'il a fait.
Comprendre Sentry, c'est comprendre son "data model".
| Concept | Description |
|---|---|
| DSN (Data Source Name) | La clé API. C'est l'URL unique (que Sentry vous donne) que vous mettez dans votre Sentry.init(). Elle dit au SDK où envoyer les erreurs. Format : https://[CLE_PUBLIQUE]@[ORG].sentry.io/[ID_PROJET] |
| Event (Événement) | L'erreur brute. C'est *une* occurrence d'une erreur. C'est un gros objet JSON contenant la stack trace, le contexte, les breadcrumbs... Si 1000 utilisateurs ont la même NullPointerException, cela fait 1000 Events. |
| Issue (Problème) | Le groupe. C'est la "killer feature". Sentry est assez intelligent pour savoir que ces 1000 NullPointerException sont le *même* problème. Il les regroupe en 1 seule "Issue" (un "cas" à traiter). Ce regroupement (fingerprinting) est sa magie. |
| Release (Version) | Un "tag" (ex: mon-app@1.2.3) que vous associez aux événements. Permet de savoir si une erreur est "nouvelle dans la v1.2.3" ou si elle a été "corrigée dans la v1.2.4". |
Cycle de vie d'une "Issue"
Une "Issue" est un ticket de bug dans Sentry. Elle a un cycle de vie :
Unresolved(Nouveau) : L'erreur se produit. Sentry crée l'Issue.Ignored(Ignoré) : Vous dites "Je m'en fiche de cette erreur" (ex: un bot).Resolved(Résolu) : Vous marquez l'Issue comme "Corrigée".Regressed(Régression) : Si une Issue "Résolue" se reproduit (dans une nouvelle release), Sentry la marque comme "Régression" (alerte rouge !).
Sentry fonctionne en installant un SDK (Software Development Kit) natif à votre langage/framework. Le SDK s'accroche (hook) aux "uncaught exceptions" (erreurs non gérées) de votre application.
L'initialisation (Sentry.init()) doit se faire le plus *tôt* possible dans le code.
Python (sentry-sdk)
1. Installation
(venv) $ pip install sentry-sdk[django]
2. Initialisation (settings.py pour Django)
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
sentry_sdk.init(
# Le DSN (NE PAS hardcoder, mettre dans les secrets)
dsn="https://...votre_dsn...@...sentry.io/12345",
# Active l'intégration Django (attrape les erreurs 500)
integrations=[DjangoIntegration()],
# Pour l'APM (Performance) - (Ex: 20% des requêtes)
traces_sample_rate=0.2,
# (Mettre à 'False' en DEBUG)
enable_tracing=True,
# (Attache la 'release' (version) de l'app)
release="mon-app@1.0.1"
)
JavaScript (@sentry/react)
1. Installation
$ npm install --save @sentry/react
2. Initialisation (index.js ou main.jsx)
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import * as Sentry from "@sentry/react";
// 1. Initialisation (le plus tôt possible)
Sentry.init({
dsn: "https://...votre_dsn...@...sentry.io/12345",
// 2. Intégrations (erreurs + performance)
integrations: [
Sentry.browserTracingIntegration(),
// 3. (Session Replay, voir 2.3)
Sentry.replayIntegration({
maskAllText: false, // (Attention GDPR)
blockAllMedia: true,
}),
],
// 4. Sample Rate (Performance)
tracesSampleRate: 1.0, // 100% (OK pour le dev)
// 5. Sample Rate (Session Replay)
replaysSessionSampleRate: 0.1, // 10% des sessions
});
// 6. Envelopper l'App
// (On utilise le 'ErrorBoundary' de Sentry)
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<Sentry.ErrorBoundary fallback={<p>Une erreur est survenue.</p>}>
<App />
</Sentry.ErrorBoundary>
</React.StrictMode>
);
1. Capture Automatique (Les Intégrations)
C'est la méthode 90%. Si vous avez installé le SDK (voir 1.3) avec les intégrations (DjangoIntegration, @sentry/react), Sentry attrape *automatiquement* :
- Backend (Python/Java) : Toutes les "Unhandled Exceptions" (ex: une
NullPointerExceptionouKeyErrorqui cause une Erreur 500). - Frontend (JS) : Toutes les erreurs JavaScript non-catchées (ex:
undefined is not a function).
2. Capture Manuelle (try...except & captureException)
Parfois, vous "attrapez" une erreur (try...except), mais vous voulez quand même la *signaler* à Sentry sans planter l'application.
# Python (Django/Flask)
import sentry_sdk
def ma_vue(request):
try:
# Tente une opération risquée
resultat = 10 / 0
except ZeroDivisionError as e:
# 1. On gère l'erreur (on ne plante pas)
print("Erreur gérée, on continue.")
# 2. MAIS on notifie Sentry manuellement
sentry_sdk.capture_exception(e)
# 3. On renvoie une réponse propre à l'utilisateur
return HttpResponse("Oops, une erreur est survenue.", status=500)
3. captureMessage
Pour envoyer un "log" (un message, pas une exception) qui doit créer une Issue Sentry. (Utilisé pour des événements métiers anormaux).
if user.balance < 0:
# Ceci va créer une Issue (gravité "warning")
sentry_sdk.capture_message(
f"Alerte Métier: Utilisateur {user.id} a un solde négatif !",
level="warning"
)
Une stack trace seule ne suffit pas. C'est le Contexte qui rend Sentry puissant. Le "contexte" répond à la question : "Que se passait-il au moment de l'erreur ?".
On utilise le "Scope" pour ajouter ce contexte à *toutes* les erreurs futures (dans cette requête/session).
| Méthode | Description | Exemple (Python) |
|---|---|---|
setUser | Identifie l'utilisateur impacté. (Ajoute une section "User" dédiée dans l'UI). | sentry_sdk.set_user({ "id": user.id, "email": user.email }) |
setTag | Le plus important pour filtrer. Ajoute une "étiquette" (Clé/Valeur) *indexée* et *filtrable*. | sentry_sdk.set_tag("plan_abonnement", "premium") |
setExtra | "Le fourre-tout". Ajoute des données de débug (Clé/Valeur) *non-indexées*. | sentry_sdk.set_extra("panier_actuel", cart_data) |
Exemple (Middleware Django)
La "bonne pratique" est de mettre le contexte dans un middleware (ou un décorateur de vue) pour qu'il soit appliqué à *toutes* les requêtes.
# Exemple: un middleware Django
import sentry_sdk
class SentryContextMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# (S'exécute AVANT la vue)
if request.user.is_authenticated:
# 1. Configurer un "scope" (isolé à cette requête)
with sentry_sdk.configure_scope() as scope:
# 2. Identifier l'utilisateur
scope.set_user({
"id": request.user.id,
"username": request.user.username,
"email": request.user.email
})
# 3. Ajouter des Tags (pour filtrer les erreurs)
scope.set_tag("customer_tier", request.user.profile.tier)
scope.set_tag("langue", request.LANGUAGE_CODE)
# 4. Ajouter des Extras (pour débugger)
scope.set_extra("session_id", request.session.session_key)
# Si une erreur 500 se produit dans la vue (plus tard),
# Sentry attrapera l'erreur ET ce contexte !
response = self.get_response(request)
else:
response = self.get_response(request)
return response
Les Breadcrumbs (fil d'Ariane) sont la "boîte noire" d'une erreur. C'est un journal (log) des événements qui se sont produits *avant* que l'erreur ne survienne.
1. Breadcrumbs Automatiques
Les SDKs Sentry sont "instrumentés" pour enregistrer automatiquement les événements courants :
- (Frontend) Clics Utilisateur :
ui.click(ex: "Clic surbutton.btn-primary"). - (Frontend) Navigation :
navigation(ex: "Navigation vers/profil"). - (Frontend/Backend) Requêtes Réseau :
http(ex: "GETvers/api/usersa renvoyé 200"). - (Frontend/Backend) Logs Console :
console.log,logging.info...
Exemple d'UI Sentry (ce que vous voyez)
ERREUR: TypeError: 'NoneType' object is not callable ... (stack trace) ... BREADCRUMBS (Fil d'Ariane): 1. 10:30:15 - navigation - Navigation vers /profil 2. 10:30:16 - ui.click - Clic sur "button#load-data" 3. 10:30:17 - http - fetch GET /api/data/123 (status 200) 4. 10:30:18 - console - "Données reçues: null" 5. 10:30:18 - exception - TypeError: 'NoneType' object is not callable (Le développeur voit immédiatement que l'API a renvoyé 'null' (log 4) juste avant l'erreur (log 5). Problème trouvé !)
2. Breadcrumbs Manuels (Addon)
Vous pouvez (et devez) ajouter vos propres "miettes" pour les événements métiers.
# Python
import sentry_sdk
sentry_sdk.add_breadcrumb(
category='auth',
message=f'Tentative de connexion pour {username}',
level='info',
data={'source': 'login_form'}
)
C'est une étape obligatoire pour tout projet JavaScript (React, Vue, Angular...).
Le Problème : Votre code JS (MonComposant.jsx) est minifié et transpilé en un seul fichier (ex: app.min.js). Si une erreur se produit, Sentry reçoit une stack trace illisible :
Erreur: 'e.target is undefined' dans main.js:1:4587 (inutile).
La Solution : Les Source Maps (.map)
Les "Source Maps" sont des fichiers (générés par votre "builder" : Vite, Webpack) qui font le lien entre le code *compilé* (main.js:1:4587) et le code *original* (MonComposant.jsx:30:5).
Le Workflow (en Production)
- Build : Vous "buildez" votre app JS (ex:
npm run build).
-> Créeapp.min.js(pour les utilisateurs)
-> Créeapp.min.js.map(le fichier de "traduction") - Upload : Vous *devez* uploader le Source Map (
.map) à Sentry (viasentry-cli). NE PAS l'uploader sur votre serveur web. - Erreur : L'utilisateur (qui n'a que
app.min.js) a une erreur. - Magie : Sentry reçoit l'erreur (
main.js:1:4587), voit le "Source Map" que vous avez uploadé, et vous montre la stack trace *originale* (MonComposant.jsx:30:5).
sentry-cli (L'outil "plugin" pour l'upload)
# 1. Installer le CLI $ npm install -g @sentry/cli # 2. Se connecter (une seule fois) $ sentry-cli login # 3. (Dans votre script de CI/CD, après le 'npm run build') # 3a. Créer une "release" (version) $ sentry-cli releases new "mon-app@1.2.4" # 3b. Uploader les source maps $ sentry-cli releases files "mon-app@1.2.4" upload-sourcemaps ./dist --rewrite
APM (Application Performance Monitoring) est le deuxième pilier de Sentry (après les Erreurs). Il répond à la question : "Pourquoi mon application est-elle *lente* ?".
Il s'active en mettant tracesSampleRate à une valeur > 0 dans Sentry.init().
Transactions & Spans
Sentry trace les "opérations" sous forme de Transactions et de Spans.
- Transaction : Une "opération" de haut niveau. (Ex:
GET /api/users, ou "Chargement de la page"). - Span : Une "sous-opération" à l'intérieur d'une Transaction. (Ex:
db.query,http.request,file.read).
Exemple d'UI Sentry (Diagramme de Gantt)
Sentry vous montre un "waterfall" (cascade) de ce qui s'est passé :
Transaction: GET /api/profil/123 (Total: 850ms) | |-- [ app.handler ] (850ms) | | | |-- [ db.query: SELECT * FROM users... ] (150ms) | | | |-- [ http.request: GET api.meteo.com ] (400ms) | | | |-- [ db.query: N+1 QUERY (SLOW) ] (300ms) | ...
Ici, Sentry identifie automatiquement les problèmes de performance (ex: N+1 Query) ou les appels API externes lents.
Distributed Tracing (Traçage Distribué)
Si votre Frontend (React) appelle votre Backend (Python), et que les deux ont Sentry... Sentry "connecte" les deux transactions. L'appel fetch (React) est le "parent" de la transaction GET /api/profil (Python).
Session Replay est une fonctionnalité (plugin) pour le frontend (JS). C'est un "enregistreur vidéo" de la session de votre utilisateur.
Il n'enregistre *pas* une vidéo (ce serait trop lourd). Il enregistre les mutations du DOM (ce qui a changé) et les mouvements de la souris, et les "rejoue" dans Sentry dans un lecteur vidéo.
C'est le "pont" ultime entre une stack trace (le code) et le "rage click" (l'utilisateur).
Activation (Sentry.init)
S'active via une intégration et deux "sample rates" :
Sentry.init({
dsn: "...",
integrations: [
Sentry.replayIntegration({
// (GDPR/Vie privée) Masque TOUT le texte (remplace par '***')
maskAllText: true,
// (GDPR) Bloque les images/médias
blockAllMedia: true,
}),
],
// 1. Taux de "Session":
// (ex: 10% des sessions utilisateur seront enregistrées)
replaysSessionSampleRate: 0.1,
// 2. Taux "Erreur":
// (Si une erreur se produit, 100% de chance d'enregistrer
// cette session (même si elle n'était pas dans les 10%))
replaysOnErrorSampleRate: 1.0,
});
Capturer les erreurs c'est bien, agir c'est mieux. Le but de Sentry est d'alerter la bonne personne au bon moment.
Règles d'Alerte (Alert Rules)
Vous créez des règles dans l'UI de Sentry basées sur des "triggers".
Exemples de "plugins" d'alerte :
- Alerte d'Erreur (Issue) :
SIl'erreur estNOUVELLEETl'environnement estproductionALORSenvoyer une notificationSlackau canal#dev-alerts. - Alerte de Régression :
SIune erreur marquéeRésolueré-apparaîtALORSenvoyer un email àl-equipe. - Alerte de Volume (Métrique) :
SIle nombre d'erreurs (par minute) est> 100ALORSenvoyer une alertePagerDuty.
Intégrations (Addons)
Sentry s'intègre à vos outils de travail pour lier les erreurs au code et aux tâches.
- Slack / Teams : Notifie un canal.
- Jira / Asana : Permet de créer un "Ticket" (tâche) directement depuis l'Issue Sentry.
- GitHub / GitLab : (Le plus puissant)
1. Stack Trace Linking : Rend les lignes de la stack trace cliquables (ouvre le fichier/ligne dans GitHub).
2. Commit Tracking : Sentry sait quel "commit" a (probablement) introduit l'erreur.
3. Issue Owners : Via un fichierCODEOWNERS, Sentry assigne *automatiquement* l'erreur au développeur/équipe qui possède ce code.
Sentry est "Open Source", mais avec une nuance de licence. Vous avez deux choix pour l'utiliser :
| Modèle | Description | Avantages | Inconvénients |
|---|---|---|---|
SaaS (sentry.io) | La version "cloud" hébergée par Sentry. Vous payez en fonction du volume d'événements. | Facile (5 min pour démarrer). Maintenu, scalable. Accès à 100% des features. | Coût (peut devenir cher si vous avez *énormément* d'erreurs). Souveraineté des données (elles sont chez Sentry). |
| Self-Hosted | Vous hébergez Sentry vous-même (via Docker Compose). | Contrôle des données (requis pour RGPD/HDS strict). Coût "fixe" (vos serveurs). | Complexe à maintenir (base de données, Redis, Kafka...). Vous devez gérer les mises à jour et la scalabilité. |
La Licence : BSL (Business Source License)
Sentry n'est *plus* 100% Apache/MIT (comme OpenSearch). En 2019, Sentry est passé à la BSL (similaire à la SSPL d'Elastic).
- Ce que ça signifie : Le code est "source-available" (visible).
- Vous pouvez l'utiliser *gratuitement* pour du "Self-hosting".
- Vous n'avez PAS le droit de revendre Sentry en tant que service concurrent de
sentry.io.
Outils (Addons)
| Outil | Description |
|---|---|
sentry-cli | Outil en ligne de commande (Node.js). Indispensable pour gérer les Releases et uploader les Source Maps (voir 2.1). |
| Sentry Webpack Plugin | Le "plugin" (wrapper) qui utilise sentry-cli automatiquement pendant votre build npm run build. |
| GlitchTip | Une alternative "vraiment" open-source (Apache 2.0) à Sentry (avant la BSL). Moins de fonctionnalités, mais 100% libre. |
Cheatsheet sentry-cli
# 1. Se connecter (via un Auth Token)
$ export SENTRY_AUTH_TOKEN=...
$ sentry-cli info
# 2. Créer une nouvelle "Release" (version)
$ sentry-cli releases new "mon-app@1.5.0"
# 3. Uploader les Source Maps (JS)
$ sentry-cli releases files "mon-app@1.5.0" upload-sourcemaps ./dist/assets \
--url-prefix "~/assets" # (Associe les fichiers aux URLs)
# 4. Finaliser la Release
$ sentry-cli releases finalize "mon-app@1.5.0"
