Logs & Observabilité
Journalisation structurée pour Node, Edge et Workers avec IDs de requête, masquage des secrets et exemples par route. Fonctionne sur Vercel, Cloudflare et serveurs Node.
Notions clés
- Logs structurés (JSON), corrélés via
request_id
. - Niveaux:
debug
,info
,warn
,error
. - Masquage des secrets (cookies, tokens, etc.).
Ce qui est inclus
- API commune côté Node et Edge/Workers (même forme).
- Node (fonctions serveur Next, serverless, Node): Pino (JSON rapide).
- Edge/Workers (Vercel Edge, Cloudflare Workers, middleware): implémentation légère via
console.log
JSON.
- Propagation
request_id
via middleware (sans toucher aux cookies). - Exemple branché sur la route de présignature de stockage.
Fichiers
- Node:
src/lib/logger/server.ts
- Edge:
src/lib/logger/edge.ts
- Types:
src/lib/logger/types.ts
- Middleware:
src/middleware.ts
- Exemple:
src/app/api/storage/uploads/route.ts
Fichiers
- Node:
src/lib/logger/server.ts
- Edge:
src/lib/logger/edge.ts
- Types:
src/lib/logger/types.ts
- Middleware:
src/middleware.ts
- Exemple:
src/app/api/storage/uploads/route.ts
Voir les logs
- Local: terminal (JSON sur une ligne). Pour un affichage lisible, utilisez
pino-pretty
:pnpm dev 2>&1 | pnpx pino-pretty
- sauvegarde fichier:
pnpm dev 2>&1 | pnpx pino-pretty | tee logs/dev.log
- Vercel: Deployments → Functions → Logs, ou
vercel logs
. - Cloudflare Workers:
wrangler tail
.
Utilisation (Node)
import { logger, requestIdFromHeaders } from '@/lib/logger/server'
export async function POST(req: Request){
const rid = requestIdFromHeaders(req.headers)
const log = logger.child({ request_id: rid, route: '/api/exemple' })
log.info({ event: 'exemple.start' })
// ...
log.info({ event: 'exemple.ok' })
return new Response('ok')
}
Utilisation (Edge)
import { logger } from '@/lib/logger/edge'
export const runtime = 'edge'
export function GET(){
logger.info({ event: 'edge.heartbeat' })
return new Response('ok')
}
Conseils
- Définir
LOG_LEVEL
et ajuster la redaction selon vos besoins. - Pas de fichier de logs par défaut: écriture vers stdout/stderr. En local, utilisez
tee
si besoin:pnpm dev 2>&1 | tee logs/dev.json
. - Remplacer
console.*
par le logger côté serveur.
Utilisation (Node)
import { logger, requestIdFromHeaders } from '@/lib/logger/server'
export async function POST(req: Request){
const rid = requestIdFromHeaders(req.headers)
const log = logger.child({ request_id: rid, route: '/api/exemple' })
const start = Date.now()
try {
log.info({ event: 'exemple.start' })
// ...
log.info({ event: 'exemple.ok', duration_ms: Date.now() - start })
return new Response('ok')
} catch (e:any) {
log.error({ event: 'exemple.error', message: e?.message })
return new Response('error', { status: 500 })
}
}
Utilisation (Edge)
import { logger } from '@/lib/logger/edge'
export const runtime = 'edge'
export function GET(){
logger.info({ event: 'edge.heartbeat' })
return new Response('ok')
}
Aide: withApiLogging (Node)
import { withApiLogging } from '@/lib/logger/server'
export const POST = withApiLogging(async (req) => {
return new Response('ok')
}, { route: '/api/foo', event: 'foo.process' })
Exemple déjà branché
src/app/api/storage/uploads/route.ts
émetstorage.presign.create
etstorage.presign.create.error
.
Personnaliser le masquage
- Node:
redactPaths
danssrc/lib/logger/server.ts
. - Edge:
redactKeys
danssrc/lib/logger/edge.ts
.
Intégrations optionnelles
- Sentry (
@sentry/nextjs
) pour exceptions et traces. - Sinks gérés (Axiom, Better Stack, Datadog, New Relic) pour recherche/rétention.
Dépannage
- Redirections inattendues vers login: ne pas surcharger les en‑têtes de requête/cookies dans le middleware.
- Pas de logs en Edge: vérifier
runtime='edge'
et utiliserwrangler tail
/Vercel logs.
Téléversements privés de fichiers (S3 / R2)
Guide pas à pas, accessible aux débutants, pour ajouter des téléversements privés avec un stockage compatible S3. Inclut concepts, configuration, variables d’env, API, UI, erreurs et migration S3↔R2.
Service Email (Resend)
Intégrez l’email transactionnel avec Resend. Vérifiez votre domaine, créez des clés API, générez les modèles de bienvenue et de paiement côté serveur et envoyez-les via Resend grâce à la configuration d’environnement.