Guide complet de surveillance Next.js en production : Sentry, logs et alertes en pratique

Vendredi soir, 21 h 17, le téléphone vibre.
Le groupe explose — « la page de paiement ne s’ouvre pas », « la commande a échoué », « écran blanc ». En local, tout roule. Les logs serveur ne montrent qu’une ligne « Internal Server Error ». L’utilisateur dit que la page se fige après le clic sur Payer, impossible de reproduire.
Ce week-end-là, j’ai fouillé les logs Vercel, redéployé une version de test, et découvert un timeout intermittent du SDK de paiement tiers en production. Comme chercher une aiguille dans le noir.
Votre app Next.js est fluide en dev, mais en prod c’est la boîte de Pandore — SSR qui renvoie parfois 500, fonctions edge qui plantent sans raison apparente, API qui ralentissent sans savoir où.
La cause est simple : il vous manque une stack de surveillance production complète. Cet article montre pas à pas comment la monter — Sentry, logs structurés, performance, alertes. Pas de théorie creuse : du code copiable. La prochaine fois, vous saurez avant l’utilisateur.
Pourquoi Next.js nécessite une surveillance dédiée
La triple exécution de Next.js
Une app frontend classique ne tourne que dans le navigateur ; les erreurs apparaissent dans DevTools. Next.js est différent — une même application s’exécute à trois endroits distincts :
- Client (navigateur) : composants React
- Serveur (Node.js) : SSR, API Routes, Server Actions
- Edge (Edge Runtime) : middleware, fonctions edge
Un flux de paiement peut enchaîner : validation formulaire client → auth middleware → Server Action → API Route → base de données → rendu client. Une erreur à n’importe quelle étape échappe à la surveillance navigateur classique.
L’an dernier, un bug étrange : « la page charge lentement puis affiche 500 ». Le panneau Network montre la lenteur, pas la cause. Le tracing distribué Sentry a révélé un appel API tiers côté SSR passé de 200 ms à 8 s. Impossible à voir côté client.
L’effet boîte noire du SSR
En cas d’erreur SSR, l’utilisateur ne voit souvent qu’une page 500 nue. Pas de stack trace, pas de contexte.
Pire encore : les erreurs d’hydratation. Vous avez peut-être vu :
Warning: Expected server HTML to contain a matching <div> in <div>
Peu visible en dev, en prod cela peut casser toute l’interactivité. Sans surveillance, vous dépendez du retour « la page ne répond plus ».
Selon Vercel, les erreurs liées au SSR représentent environ 35 % des problèmes Next.js en production. Et ce ne sont que les erreurs — pas les perfs, comme un composant SSR qui ralentit soudainement.
Les quatre piliers d’une surveillance complète
Suivi d’erreurs
Pas seulement capturer l’exception : qui (utilisateur), où (device, navigateur, réseau), quoi (breadcrumbs), avec quels paramètres.
Monitoring performance
LCP > 2,5 s ? API qui ralentit ? Quelle requête DB bloque tout ?
Gestion des logs
Logs structurés, recherche par heure, utilisateur, request ID. Dev : sortie lisible ; prod : plateforme centralisée.
Alertes
Taux d’erreur au-dessus du seuil → notification immédiate ; nouvelle erreur → Slack ; régression perf → alerte auto.
Avec ces quatre piliers, fini de tâtonner en aveugle. On attaque un par un.
Intégration Sentry en pratique — de l’installation à la config avancée
Intégration en 5 minutes
Sentry supporte Next.js depuis longtemps, avec un wizard officiel. Vraiment 5 minutes :
# Installer le SDK
npm install @sentry/nextjs
# Lancer le wizard
npx @sentry/wizard@latest -i nextjs
Le wizard pose quelques questions (DSN, Source Maps, etc.) et crée trois fichiers :
sentry.client.config.ts— navigateursentry.server.config.ts— Node.js serveursentry.edge.config.ts— Edge Runtime
Il modifie aussi next.config.js avec le plugin webpack Sentry. Un passage du wizard, la base est en place.
Mais ce n’est que le début. La prod demande une config plus fine.
Points clés App Router pour la capture d’erreurs
Avec App Router, quelques zones à ne pas oublier :
Gestion globale des erreurs
Créez app/global-error.tsx, dernier filet de sécurité :
'use client';
import * as Sentry from '@sentry/nextjs';
import { useEffect } from 'react';
export default function GlobalError({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
Sentry.captureException(error);
}, [error]);
return (
<html>
<body>
<div style={{ padding: '2rem', textAlign: 'center' }}>
<h2>Un problème est survenu</h2>
<p>Nous avons enregistré cette erreur et la corrigerons au plus vite</p>
<button onClick={() => reset()}>Réessayer</button>
</div>
</body>
</html>
);
}
Capture d’erreurs Server Actions
Les Server Actions sont puissantes, mais la gestion d’erreurs est souvent négligée :
'use server';
import * as Sentry from '@sentry/nextjs';
export async function createOrder(formData: FormData) {
return await Sentry.withServerActionInstrumentation(
'createOrder',
{
recordResponse: true,
},
async () => {
const productId = formData.get('productId');
const order = await db.order.create({
data: { productId, userId: getCurrentUserId() },
});
return order;
}
);
}
Ainsi, toute erreur Server Action remonte automatiquement, avec le temps d’exécution.
Config optimisée pour la production
Après intégration, la facture du premier mois peut surprendre — la config par défaut envoie tout. Ajustez l’échantillonnage :
// sentry.client.config.ts
import * as Sentry from '@sentry/nextjs';
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.1 : 1.0,
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
environment: process.env.NEXT_PUBLIC_VERCEL_ENV || 'development',
ignoreErrors: [
'ResizeObserver loop limit exceeded',
/chrome-extension/,
/^Non-Error promise rejection/,
],
});
Guide tracesSampleRate :
- UV/jour < 10 000 : 0,2 - 0,5
- UV/jour 10 000-100 000 : 0,1 - 0,2
- UV/jour > 100 000 : 0,05 - 0,1
Notre projet (~30 000 UV/jour) est à 0,15 — ~60 % du quota Sentry, bon compromis.
Source Maps : débogable sans exposer le code
Le JS de prod est minifié ; la stack ressemble à :
at r.render (app.js:1:23456)
Illisible. Les Source Maps remappent vers le code source, mais les exposer publiquement fuit le code.
Sentry les reçoit en upload ; le navigateur utilisateur ne les voit pas.
Dans le CI/CD (ex. GitHub Actions) :
# .github/workflows/deploy.yml
- name: Upload Source Maps to Sentry
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: your-org
SENTRY_PROJECT: your-project
run: npm run build
Le plugin Sentry dans next.config.js gère l’upload. Mettez SENTRY_AUTH_TOKEN dans GitHub Secrets, jamais dans le repo.
Fonctions avancées : Session Replay et tracing distribué
Session Replay — rejouer les actions utilisateur comme une vidéo.
Un retour « le bouton Payer ne répond pas » : le replay montrait un iPad paysage, bouton masqué par le clavier virtuel. Invisible dans les logs seuls.
Activation :
import * as Sentry from '@sentry/nextjs';
import { Replay } from '@sentry/nextjs';
Sentry.init({
integrations: [
new Replay({
maskAllText: false,
blockAllMedia: true,
maskAllInputs: true,
}),
],
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
});
Tracing distribué — cycle de vie complet d’une requête : clic → API → DB → rendu, durée à chaque étape.
Même config Sentry.init côté client et serveur ; le SDK propage sentry-trace dans les en-têtes.
Contexte personnalisé : des erreurs plus utiles
Par défaut, Sentry sait seulement qu’une erreur s’est produite. Enrichissez :
import * as Sentry from '@sentry/nextjs';
Sentry.setUser({
id: user.id,
email: user.email,
username: user.username,
});
Sentry.setContext('purchase', {
orderId: '12345',
amount: 99.99,
paymentMethod: 'credit_card',
});
Sentry.setTag('feature', 'checkout');
Sentry.setTag('ab_test', 'variant_b');
Cas réel : une erreur paiement plus fréquente que prévu — contexte Sentry montrait uniquement ab_test: variant_b. Bug dans le nouveau flux A/B ; variante coupée immédiatement.
Gestion des logs — faire travailler vos logs
console.log ne suffit plus
Au début, j’avais des console.log partout. Pratique en debug, inutilisable en prod :
- Pas de filtrage : retrouver une requête parmi 100 000 lignes ?
- Pas d’agrégation : combien de requêtes DB > 1 s cette heure ?
- Pas d’alerte : « Payment failed » dans les logs, personne au courant.
Les logs structurés résolvent ça : JSON avec timestamp, niveau, request ID, user ID. Recherche et agrégation par champ.
Pino vs Winston : lequel choisir
| Caractéristique | Pino | Winston |
|---|---|---|
| Performance | Très rapide, async quasi sans coût | Un peu plus lent, suffisant |
| Simplicité | Config minimaliste | Riche, bon écosystème |
| Extensibilité | Via Transport | Transports intégrés |
| Communauté | Recommandé Next.js | Bibliothèque historique |
Mon avis :
- Fort trafic (QPS > 1000) : Pino
- Traitement complexe (multi-format, multi-cible) : Winston
- Indécis : Pino, la doc Next.js l’utilise
Config Pino en pratique
npm install pino
npm install pino-pretty --save-dev
// lib/logger.ts
import pino from 'pino';
const logger = pino({
level: process.env.LOG_LEVEL || 'info',
formatters: {
level: (label) => ({ level: label.toUpperCase() }),
},
transport: process.env.NODE_ENV === 'development'
? {
target: 'pino-pretty',
options: {
colorize: true,
translateTime: 'HH:MM:ss',
ignore: 'pid,hostname',
},
}
: undefined,
});
export { logger };
Dev : sortie colorée ; prod : JSON pour la plateforme de logs.
Utilisation dans une API Route
Attribuez un correlationId à chaque requête :
// app/api/products/route.ts
import { logger } from '@/lib/logger';
import { randomUUID } from 'crypto';
export async function GET(request: Request) {
const correlationId = request.headers.get('x-correlation-id') || randomUUID();
const log = logger.child({ correlationId });
try {
log.info({ url: request.url }, 'Processing product request');
const products = await db.product.findMany();
log.info({ count: products.length }, 'Products fetched successfully');
return Response.json(products);
} catch (error) {
log.error({ error: error.message, stack: error.stack }, 'Failed to fetch products');
throw error;
}
}
Même correlationId = toute la chaîne de la requête visible d’un coup.
Bonnes pratiques des niveaux de log
ERROR — action immédiate
- Échec connexion DB, paiement, logique métier critique
log.error({ error, userId, orderId }, 'Payment processing failed');
WARN — anomalie récupérable
- Retry API réussi, fallback, quota proche
log.warn({ retryCount: 3 }, 'External API retry succeeded');
INFO — nœuds métier clés
- Login, commande, changement de config
log.info({ userId, ip }, 'User logged in');
DEBUG — détail de debug
- Paramètres, états intermédiaires, timings
log.debug({ params }, 'Calling external API');
Prod : INFO par défaut ; DEBUG temporaire en incident.
Agrégation et analyse
Vercel Logs — zéro config si déployé sur Vercel ; 7 jours, recherche limitée.
Datadog — APM + logs + monitoring entreprise.
import { datadogLogs } from '@datadog/browser-logs';
datadogLogs.init({
clientToken: process.env.NEXT_PUBLIC_DATADOG_CLIENT_TOKEN,
site: 'datadoghq.com',
forwardErrorsToLogs: true,
sampleRate: 100,
});
Logtail/BetterStack — bon rapport qualité-prix, recherche temps réel, alertes.
Perso : Logtail (1 Go/mois gratuit). Équipe : Datadog.
Champs de log essentiels
{
"timestamp": "2025-12-20T15:00:06.123Z",
"level": "INFO",
"correlationId": "abc-123-def",
"userId": "user_456",
"action": "create_order",
"duration": 234,
"status": "success",
"metadata": {
"orderId": "order_789",
"amount": 99.99
}
}
Répond à : qui, quand, quoi, résultat.
Monitoring performance — optimiser avec les données
Core Web Vitals : ce que Google regarde
- LCP : < 2,5 s idéal
- FID / INP : < 100 ms / < 200 ms
- CLS : < 0,1
Next.js expose Web Vitals ; dans app/layout.tsx :
'use client';
import { useReportWebVitals } from 'next/web-vitals';
export function WebVitalsReporter() {
useReportWebVitals((metric) => {
if (window.Sentry) {
window.Sentry.captureMessage(`Web Vital: ${metric.name}`, {
level: 'info',
tags: {
web_vital: metric.name,
},
contexts: {
web_vitals: {
value: metric.value,
rating: metric.rating,
},
},
});
}
fetch('/api/analytics/web-vitals', {
method: 'POST',
body: JSON.stringify(metric),
});
});
return null;
}
// app/layout.tsx
export default function RootLayout({ children }) {
return (
<html>
<body>
<WebVitalsReporter />
{children}
</body>
</html>
);
}
Suivi performance API
// app/api/products/[id]/route.ts
import * as Sentry from '@sentry/nextjs';
export async function GET(
request: Request,
{ params }: { params: { id: string } }
) {
return await Sentry.startSpan(
{
op: 'api.request',
name: 'GET /api/products/[id]',
},
async () => {
const product = await Sentry.startSpan(
{
op: 'db.query',
name: 'Fetch product from database',
},
async () => {
return await db.product.findUnique({
where: { id: params.id },
include: { reviews: true },
});
}
);
if (!product) {
return Response.json({ error: 'Not found' }, { status: 404 });
}
const pricing = await Sentry.startSpan(
{
op: 'http.client',
name: 'Fetch pricing from external API',
},
async () => {
const res = await fetch(`https://pricing-api.com/product/${params.id}`);
return res.json();
}
);
return Response.json({ ...product, pricing });
}
);
}
Dans Sentry : requête 450 ms — DB 120 ms, API externe 300 ms, reste 30 ms. Goulot : API externe.
Alertes requêtes lentes
Middleware Prisma :
// lib/prisma.ts
import { PrismaClient } from '@prisma/client';
import { logger } from './logger';
const prisma = new PrismaClient();
prisma.$use(async (params, next) => {
const before = Date.now();
const result = await next(params);
const after = Date.now();
const duration = after - before;
if (duration > 1000) {
logger.warn({
model: params.model,
action: params.action,
duration,
args: params.args,
}, 'Slow database query detected');
Sentry.captureMessage('Slow database query', {
level: 'warning',
tags: { model: params.model, action: params.action },
extra: { duration, args: params.args },
});
}
return result;
});
export { prisma };
RUM vs monitoring synthétique
RUM (Real User Monitoring) — données réelles (réseau, devices) ; passif.
Monitoring synthétique — Checkly, Pingdom, accès simulé planifié ; proactif.
Combiné : RUM pour l’UX, synthétique pour disponibilité (login, paiement).
Checkly toutes les 5 min depuis 5 régions sur accueil et login — timeout ou échec → alerte.
Configuration des alertes — détecter en premier
Intégration Slack
Settings → Integrations → Slack dans Sentry. Sans règles, tout part dans le canal = bruit.
- Alerts → Create Alert Rule
- Conditions :
- Taux d’erreur : « > 50 erreurs en 10 min »
- Nouvelle erreur : notification immédiate
- Régression perf : « P95 API > 1 s »
- Action : Slack
Format message :
🚨 Production Error Spike
Project: my-nextjs-app
Environment: production
Error: TypeError: Cannot read property 'id' of undefined
Events: 127 events in 10 minutes
View in Sentry: https://sentry.io/...
Niveaux d’alerte : éviter la fatigue
P0 — critique (immédiat)
- Service down, paiement, DB déconnectée
- PagerDuty + Slack @channel
P1 — important (< 1 h)
- Fonction core, > 100 erreurs/10 min, P95 > 3 s
- Slack dev
P2 — normal (heures ouvrées)
- Erreurs mineures, scripts tiers
- E-mail quotidien
Exemples Sentry :
// P0 : échec paiement
{
conditions: [
{ type: 'event.tag', key: 'feature', value: 'payment' },
{ type: 'event.level', value: 'error' }
],
frequency: 'every event',
actions: [
{ type: 'slack', channel: '#critical-alerts', mention: '@channel' },
{ type: 'pagerduty', service: 'payments' }
]
}
// P1 : pic d'erreurs
{
conditions: [
{ type: 'event.count', value: 100, interval: '10m' }
],
frequency: 'once per issue',
actions: [
{ type: 'slack', channel: '#alerts-dev' }
]
}
Réduction du bruit
1. Ignorer le bruit connu
// sentry.client.config.ts
Sentry.init({
ignoreErrors: [
/chrome-extension/,
/moz-extension/,
/google-analytics/,
/HMR/,
],
denyUrls: [
/extensions\//i,
/^chrome:\/\//i,
],
});
2. Fusionner — Issue Grouping Sentry, une notif par issue/10 min.
3. Silence déploiement — « Mute for 10 minutes » pendant le deploy.
4. Fingerprint
Sentry.captureException(error, {
fingerprint: ['database-connection-error', databaseName],
});
Cas pratique — déploiement d’une stack complète
Architecture e-commerce
L’an dernier, refonte surveillance d’un site e-commerce :
Contexte :
- ~80 000 UV/jour
- Pic QPS 3000+
- Problèmes : paiements intermittents, accueil lent
Architecture :
┌─────────────┐
│ Next.js │
│ front/SSR │
└──────┬──────┘
│
├─ Sentry (erreurs + perf)
├─ Pino (logs structurés) → Datadog
├─ Web Vitals → Sentry
└─ Checkly (synthétique)
Config clé :
- Suivi parcours utilisateur
// lib/tracking.ts
import * as Sentry from '@sentry/nextjs';
export function trackCheckoutStep(step: string, data: any) {
Sentry.addBreadcrumb({
category: 'checkout',
message: `Checkout step: ${step}`,
data,
level: 'info',
});
}
trackCheckoutStep('add_to_cart', { productId, price });
trackCheckoutStep('proceed_to_payment', { cartTotal });
trackCheckoutStep('payment_submitted', { method: 'credit_card' });
- Monitoring paiement
// app/api/payment/route.ts
export async function POST(request: Request) {
const log = logger.child({ action: 'payment' });
try {
const result = await processPayment(data);
log.info({ orderId, amount, method }, 'Payment succeeded');
return Response.json({ success: true, orderId });
} catch (error) {
log.error({ error, orderId, userId }, 'Payment failed');
Sentry.captureException(error, {
tags: { feature: 'payment', severity: 'critical' },
level: 'fatal',
});
return Response.json({ error: 'Payment failed' }, { status: 500 });
}
}
- Baseline performance
- LCP accueil < 2 s
- LCP fiche produit < 2,5 s
- API /api/products P95 < 500 ms
Dépassement → alerte auto.
Résultats :
- Détection incident : 40 min → 3 min
- Échecs paiement : 0,8 % → 0,2 %
- LCP accueil : 3,2 s → 1,8 s
Checklist surveillance
**Suivi d'erreurs**
- [ ] Sentry configuré et testé
- [ ] Source Maps uploadés
- [ ] global-error.tsx créé (App Router)
- [ ] Server Actions avec gestion d'erreurs
- [ ] Règles d'ignore (bruit filtré)
**Logs**
- [ ] Pino/Winston intégré
- [ ] JSON en production
- [ ] correlationId présent
- [ ] Niveau INFO en prod
- [ ] Plateforme d'agrégation connectée
**Performance**
- [ ] Web Vitals activés
- [ ] Core Web Vitals OK (LCP<2,5s, INP<200ms, CLS<0,1)
- [ ] Tracing sur APIs clés
- [ ] Monitoring requêtes lentes
- [ ] Monitoring synthétique (optionnel)
**Alertes**
- [ ] Slack/e-mail testés
- [ ] Règles par priorité
- [ ] Réduction du bruit
- [ ] Équipe informée du processus
- [ ] Responsable P0 défini
**Amélioration continue**
- [ ] Revue hebdomadaire des données
- [ ] Tendances d'erreurs
- [ ] Détection régressions perf
- [ ] Optimisation régulière des règles
Conclusion
De la réaction passive à la détection proactive : la surveillance vous redonne le contrôle.
Récap :
- Sentry — erreurs, perf, replay utilisateur
- Pino — logs structurés, chaîne correlationId
- Web Vitals — UX et SEO
- Slack — alertes rapides, niveaux pour éviter la fatigue
Changement de mindset : la surveillance n’est pas un plus, c’est l’airbag de la prod. Vous n’attendez pas l’accident pour l’installer.
Agissez aujourd’hui. Sans aucune surveillance :
- Ce week-end : 2 h pour Sentry de base
- Semaine suivante : logs structurés + correlationId
- Semaine d’après : alertes Slack + baseline perf
Commencez par le minimum, enrichissez ensuite. Après chaque incident : « la surveillance aurait-elle détecté plus tôt ? » Elle deviendra votre meilleur allié.
Partagez avec l’équipe — la surveillance se fait à plusieurs.
Que votre Next.js tienne bon en prod. (La réalité dit autrement — d’où l’importance de surveiller 😄)
Configuration complète de la surveillance Next.js en production
Étapes complètes de l'intégration Sentry aux logs, au monitoring performance et aux alertes
⏱️ Estimated time: 3 hr
- 1
Step 1: Intégrer le suivi d'erreurs Sentry
Installation :
```bash
npm install @sentry/nextjs
```
Initialisation :
```bash
npx @sentry/wizard@latest -i nextjs
```
Config client :
```ts
// sentry.client.config.ts
import * as Sentry from '@sentry/nextjs'
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
environment: process.env.NODE_ENV,
tracesSampleRate: 1.0,
})
```
Config serveur :
```ts
// sentry.server.config.ts
import * as Sentry from '@sentry/nextjs'
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV,
tracesSampleRate: 1.0,
})
```
Points clés :
• Config client et serveur séparées
• tracesSampleRate pour contrôler l'échantillonnage
• Variables d'environnement configurées - 2
Step 2: Configurer des logs structurés
Utiliser correlationId pour relier les requêtes :
```ts
// middleware.ts
import { v4 as uuidv4 } from 'uuid'
export function middleware(request: NextRequest) {
const correlationId = request.headers.get('x-correlation-id') || uuidv4()
const response = NextResponse.next()
response.headers.set('x-correlation-id', correlationId)
return response
}
```
Dans les logs :
```ts
import { headers } from 'next/headers'
export async function handler() {
const headersList = headers()
const correlationId = headersList.get('x-correlation-id')
console.log({
correlationId,
message: 'User action',
timestamp: new Date().toISOString(),
})
}
```
Points clés :
• ID unique par requête
• correlationId sur tous les logs
• Traçabilité de bout en bout - 3
Step 3: Configurer le monitoring performance
Sentry APM :
```ts
Sentry.init({
tracesSampleRate: 1.0,
integrations: [
new Sentry.Integrations.Http({ tracing: true }),
],
})
```
Monitoring personnalisé :
```ts
const transaction = Sentry.startTransaction({
op: 'http.server',
name: 'API Route',
})
try {
await processRequest()
} finally {
transaction.finish()
}
```
Points clés :
• tracesSampleRate pour l'échantillonnage
• Surveiller le temps de réponse API
• Identifier les goulots d'étranglement - 4
Step 4: Configurer les alertes
Alertes Sentry :
• Règles d'alerte dans le Dashboard Sentry
• Seuils d'erreur
• Canaux de notification (Slack, e-mail, etc.)
Intégration Slack :
```ts
// Configurer dans le Dashboard Sentry
// Webhook URL: https://hooks.slack.com/services/...
```
Alertes e-mail :
• Configurer dans le Dashboard Sentry
• Définir les destinataires
• Conditions d'alerte
Points clés :
• Seuils raisonnables
• Éviter la fatigue d'alerte
• Répondre rapidement
FAQ
Pourquoi Next.js nécessite-t-il une surveillance dédiée ?
Une même application tourne à trois endroits :
• Client (navigateur) : composants React
• Serveur (Node.js) : SSR, API Routes, Server Actions
• Edge (Edge Runtime) : middleware, fonctions edge
La surveillance frontend classique ne voit que les erreurs client.
Effet boîte noire SSR :
• Erreur SSR → page 500 pour l'utilisateur
• Pas de stack trace, pas de contexte
• Le tracing distribué Sentry est nécessaire
Cas réel :
• Retour utilisateur : page lente puis 500
• Network du navigateur montre la lenteur, pas la cause
• Sentry révèle un appel API tiers passé de 200 ms à 8 s côté serveur
Solution : une stack complète couvrant client, serveur et edge.
Comment intégrer Sentry ?
```bash
npm install @sentry/nextjs
```
Initialisation :
```bash
npx @sentry/wizard@latest -i nextjs
```
Config client :
```ts
// sentry.client.config.ts
import * as Sentry from '@sentry/nextjs'
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
environment: process.env.NODE_ENV,
tracesSampleRate: 1.0,
})
```
Config serveur :
```ts
// sentry.server.config.ts
import * as Sentry from '@sentry/nextjs'
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV,
tracesSampleRate: 1.0,
})
```
Points clés :
• Config client et serveur séparées
• tracesSampleRate pour l'échantillonnage
• Variables NEXT_PUBLIC_SENTRY_DSN et SENTRY_DSN
Comment configurer des logs structurés ?
Génération dans le middleware :
```ts
import { v4 as uuidv4 } from 'uuid'
export function middleware(request: NextRequest) {
const correlationId = request.headers.get('x-correlation-id') || uuidv4()
const response = NextResponse.next()
response.headers.set('x-correlation-id', correlationId)
return response
}
```
Dans les logs :
```ts
import { headers } from 'next/headers'
export async function handler() {
const headersList = headers()
const correlationId = headersList.get('x-correlation-id')
console.log({
correlationId,
message: 'User action',
timestamp: new Date().toISOString(),
})
}
```
Avantages :
• ID unique par requête
• correlationId sur tous les logs
• Traçabilité de bout en bout
• Diagnostic rapide
Point clé : générer dans le middleware, utiliser dans les logs.
Comment configurer le monitoring performance ?
```ts
Sentry.init({
tracesSampleRate: 1.0, // 100 % en dev (0.1 recommandé en prod)
integrations: [
new Sentry.Integrations.Http({ tracing: true }),
],
})
```
Monitoring personnalisé :
```ts
const transaction = Sentry.startTransaction({
op: 'http.server',
name: 'API Route',
})
try {
await processRequest()
} finally {
transaction.finish()
}
```
Métriques :
• Temps de réponse API
• Temps de requête base de données
• Appels API tiers
• Temps de chargement page
Points clés :
• tracesSampleRate (0.1 en prod recommandé)
• Surveiller les chemins critiques
• Identifier les goulots
Comment configurer les alertes ?
• Règles dans le Dashboard Sentry
• Seuils (ex. : >10 erreurs en 5 min)
• Canaux Slack, e-mail, etc.
Slack :
• Webhook URL dans le Dashboard
• Conditions d'alerte
• Test des alertes
E-mail :
• Destinataires et conditions
Règles suggérées :
• Taux d'erreur au-dessus du seuil
• Temps de réponse au-dessus du seuil
• Types d'erreur spécifiques
• Nouvelles erreurs
Points clés :
• Seuils raisonnables, éviter la fatigue
• Réponse rapide
Conseil : démarrer par le suivi d'erreurs de base, enrichir ensuite.
Quelles sont les bonnes pratiques de surveillance ?
1. Ce week-end : 2 h pour Sentry et le suivi d'erreurs de base
2. Semaine suivante : logs structurés et correlationId
3. Semaine d'après : alertes Slack et baseline performance
Ne visez pas la perfection d'un coup — commencez par le minimum viable.
Amélioration continue :
• Après chaque incident : la surveillance aurait-elle détecté plus tôt ?
• Ajuster les seuils
• Revoir la config régulièrement
Indicateurs clés :
• Taux d'erreur
• Temps de réponse
• Portée impact utilisateur
• Temps de récupération
Conseils :
• La surveillance est une affaire d'équipe
• Partager les données régulièrement
• Améliorer en continu
Rappel : la surveillance n'est pas un one-shot, c'est un processus continu.
12 min de lecture · Publié le: 20 déc. 2025 · Mis à jour le: 27 juil. 2026
Guide complet Next.js
Si vous arrivez depuis la recherche, le plus rapide est de passer à l’article précédent ou suivant de cette série.
Précédent
Quitter Vercel : guide complet de l'auto-hébergement Next.js avec Docker
Marre de la facture Vercel ? Ce guide vous montre comment auto-héberger Next.js avec Docker : config standalone, proxy inverse et correctifs pour le rendu en streaming — économisez 300 à 500 $ par mois.
Partie 42 sur 51
Suivant
Mode sombre Next.js : guide complet next-themes
Du scintillement au zéro flash : implémentez le mode sombre Next.js avec next-themes. Code complet, explications et dépannage des problèmes courants.
Partie 44 sur 51



Commentaires
Connectez-vous avec GitHub pour laisser un commentaire