Guide complet pour configurer OpenTelemetry avec Next.js 15 pour la supervision en production

Introduction
Dans le monde des applications modernes, il ne suffit pas que votre application fonctionne — vous devez savoir comment elle fonctionne. Les réponses sont-elles lentes ? Où le serveur passe-t-il la majeure partie de son temps ? Quels sont les goulots d'étranglement ? C'est là qu'intervient OpenTelemetry (OTel) — le standard ouvert pour la supervision et le traçage distribué.
Dans ce guide complet, vous apprendrez à :
- Configurer OpenTelemetry avec Next.js 15 depuis zéro
- Tracer automatiquement les requêtes API et les pages
- Ajouter des spans personnalisés pour mesurer les performances des opérations critiques
- Exporter les données vers Jaeger pour le traçage et Prometheus pour les métriques
- Visualiser le tout dans un tableau de bord Grafana intégré
- Déployer la configuration en production avec Docker Compose
Prérequis
Avant de commencer, assurez-vous de disposer de :
- Node.js 20+ installé sur votre machine
- Docker et Docker Compose pour les services locaux
- Connaissance de base de Next.js et TypeScript
- Familiarité avec les concepts HTTP et REST API
- Un éditeur de code (VS Code recommandé)
Ce que vous allez construire
Vous allez construire une application Next.js 15 avec un système de supervision complet incluant :
- Traçage automatique de toutes les requêtes HTTP et pages
- Spans personnalisés pour les opérations de base de données et services externes
- Métriques de performance comme le temps de réponse et le taux d'erreurs
- Tableau de bord de supervision intégré dans Grafana
- Alertes lorsque les seuils de performance sont dépassés
Étape 1 : Créer un projet Next.js 15
Commencez par créer un nouveau projet Next.js :
npx create-next-app@latest otel-nextjs-demo --typescript --tailwind --app --src-dir
cd otel-nextjs-demoChoisissez les options par défaut lorsque demandé. Après l'installation, vérifiez que le projet fonctionne :
npm run devÉtape 2 : Installer les packages OpenTelemetry
Installez les packages OpenTelemetry nécessaires :
npm install @opentelemetry/api \
@opentelemetry/sdk-node \
@opentelemetry/sdk-trace-node \
@opentelemetry/sdk-metrics \
@opentelemetry/resources \
@opentelemetry/semantic-conventions \
@opentelemetry/exporter-trace-otlp-http \
@opentelemetry/exporter-metrics-otlp-http \
@opentelemetry/instrumentation-http \
@opentelemetry/instrumentation-fetch \
@vercel/otelLe package @vercel/otel offre une intégration optimisée avec Next.js et simplifie considérablement la configuration initiale. Vous pouvez l'utiliser avec n'importe quel fournisseur OpenTelemetry, pas seulement Vercel.
Étape 3 : Configurer OpenTelemetry dans Next.js
Activer la fonctionnalité expérimentale
D'abord, activez le support OpenTelemetry dans next.config.ts :
// next.config.ts
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
experimental: {
instrumentationHook: true,
},
};
export default nextConfig;Créer le fichier d'instrumentation
Créez src/instrumentation.ts — c'est le point d'entrée pour OpenTelemetry :
// src/instrumentation.ts
export async function register() {
if (process.env.NEXT_RUNTIME === "nodejs") {
const { NodeSDK } = await import("@opentelemetry/sdk-node");
const { OTLPTraceExporter } = await import(
"@opentelemetry/exporter-trace-otlp-http"
);
const { OTLPMetricExporter } = await import(
"@opentelemetry/exporter-metrics-otlp-http"
);
const { PeriodicExportingMetricReader } = await import(
"@opentelemetry/sdk-metrics"
);
const { Resource } = await import("@opentelemetry/resources");
const {
ATTR_SERVICE_NAME,
ATTR_SERVICE_VERSION,
ATTR_DEPLOYMENT_ENVIRONMENT_NAME,
} = await import("@opentelemetry/semantic-conventions");
const { HttpInstrumentation } = await import(
"@opentelemetry/instrumentation-http"
);
const resource = new Resource({
[ATTR_SERVICE_NAME]: "nextjs-otel-demo",
[ATTR_SERVICE_VERSION]: "1.0.0",
[ATTR_DEPLOYMENT_ENVIRONMENT_NAME]:
process.env.NODE_ENV || "development",
});
const traceExporter = new OTLPTraceExporter({
url:
process.env.OTEL_EXPORTER_OTLP_ENDPOINT ||
"http://localhost:4318/v1/traces",
});
const metricExporter = new OTLPMetricExporter({
url:
process.env.OTEL_EXPORTER_OTLP_ENDPOINT ||
"http://localhost:4318/v1/metrics",
});
const sdk = new NodeSDK({
resource,
traceExporter,
metricReader: new PeriodicExportingMetricReader({
exporter: metricExporter,
exportIntervalMillis: 10000,
}),
instrumentations: [new HttpInstrumentation()],
});
sdk.start();
process.on("SIGTERM", () => {
sdk.shutdown().then(
() => console.log("OpenTelemetry SDK shut down successfully"),
(err) => console.error("Error shutting down OpenTelemetry SDK", err)
);
});
}
}La vérification process.env.NEXT_RUNTIME === "nodejs" est essentielle car le SDK OpenTelemetry fonctionne uniquement dans le runtime Node.js et ne supporte pas Edge Runtime. Sans cette vérification, votre application échouera lors de l'utilisation de Middleware ou de Edge Functions.
Étape 4 : Configurer les services de supervision avec Docker Compose
Créez un fichier docker-compose.yml à la racine du projet pour exécuter Jaeger, Prometheus, Grafana et le collecteur OpenTelemetry :
# docker-compose.yml
services:
otel-collector:
image: otel/opentelemetry-collector-contrib:latest
command: ["--config=/etc/otel-collector-config.yml"]
volumes:
- ./otel-collector-config.yml:/etc/otel-collector-config.yml
ports:
- "4317:4317" # gRPC
- "4318:4318" # HTTP
- "8889:8889" # Métriques Prometheus
depends_on:
- jaeger
jaeger:
image: jaegertracing/all-in-one:latest
environment:
- COLLECTOR_OTLP_ENABLED=true
ports:
- "16686:16686" # Interface Jaeger
- "14268:14268" # Collecteur Jaeger
prometheus:
image: prom/prometheus:latest
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
grafana:
image: grafana/grafana:latest
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=admin123
volumes:
- grafana-data:/var/lib/grafana
ports:
- "3001:3000"
depends_on:
- prometheus
- jaeger
volumes:
grafana-data:Configurer le collecteur OpenTelemetry
Créez le fichier otel-collector-config.yml :
# otel-collector-config.yml
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch:
timeout: 5s
send_batch_size: 1024
memory_limiter:
check_interval: 1s
limit_mib: 512
exporters:
otlp/jaeger:
endpoint: jaeger:4317
tls:
insecure: true
prometheus:
endpoint: "0.0.0.0:8889"
namespace: "nextjs"
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [otlp/jaeger]
metrics:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [prometheus]Configurer Prometheus
Créez le fichier prometheus.yml :
# prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: "otel-collector"
static_configs:
- targets: ["otel-collector:8889"]
- job_name: "nextjs-app"
static_configs:
- targets: ["host.docker.internal:3000"]Démarrez tous les services :
docker compose up -dÉtape 5 : Ajouter des Spans personnalisés
Créer un utilitaire de traçage
Créez src/lib/tracing.ts pour fournir des utilitaires de traçage faciles à utiliser :
// src/lib/tracing.ts
import { trace, SpanStatusCode, Span, context } from "@opentelemetry/api";
const tracer = trace.getTracer("nextjs-app", "1.0.0");
export function withSpan<T>(
name: string,
fn: (span: Span) => Promise<T>,
attributes?: Record<string, string | number | boolean>
): Promise<T> {
return tracer.startActiveSpan(name, async (span) => {
try {
if (attributes) {
Object.entries(attributes).forEach(([key, value]) => {
span.setAttribute(key, value);
});
}
const result = await fn(span);
span.setStatus({ code: SpanStatusCode.OK });
return result;
} catch (error) {
span.setStatus({
code: SpanStatusCode.ERROR,
message: error instanceof Error ? error.message : "Unknown error",
});
span.recordException(error as Error);
throw error;
} finally {
span.end();
}
});
}
export function createDbSpan<T>(
operation: string,
table: string,
fn: (span: Span) => Promise<T>
): Promise<T> {
return withSpan(`db.${operation}`, fn, {
"db.system": "postgresql",
"db.operation": operation,
"db.sql.table": table,
});
}
export function createExternalApiSpan<T>(
service: string,
endpoint: string,
fn: (span: Span) => Promise<T>
): Promise<T> {
return withSpan(`external.${service}`, fn, {
"http.url": endpoint,
"peer.service": service,
});
}
export { tracer };Utiliser les Spans dans les routes API
Créez une route API qui utilise le traçage personnalisé :
// src/app/api/users/route.ts
import { NextResponse } from "next/server";
import { withSpan, createDbSpan } from "@/lib/tracing";
// Base de données simulée
async function fetchUsersFromDb() {
return createDbSpan("SELECT", "users", async (span) => {
// Simuler la latence de la base de données
await new Promise((resolve) => setTimeout(resolve, 50));
span.setAttribute("db.rows_affected", 10);
return [
{ id: 1, name: "Ahmed", email: "ahmed@example.com" },
{ id: 2, name: "Sara", email: "sara@example.com" },
{ id: 3, name: "Mohamed", email: "mohamed@example.com" },
];
});
}
async function enrichUserData(users: any[]) {
return withSpan(
"enrichUserData",
async (span) => {
span.setAttribute("users.count", users.length);
// Simuler l'enrichissement depuis un service externe
await new Promise((resolve) => setTimeout(resolve, 30));
return users.map((user) => ({
...user,
avatar: `https://api.dicebear.com/7.x/initials/svg?seed=${user.name}`,
}));
},
{ "enrichment.source": "dicebear" }
);
}
export async function GET() {
return withSpan("GET /api/users", async (span) => {
span.setAttribute("http.method", "GET");
span.setAttribute("http.route", "/api/users");
const users = await fetchUsersFromDb();
const enrichedUsers = await enrichUserData(users);
span.setAttribute("response.count", enrichedUsers.length);
return NextResponse.json({
users: enrichedUsers,
total: enrichedUsers.length,
});
});
}Étape 6 : Ajouter des métriques personnalisées
Créez src/lib/metrics.ts pour définir les métriques :
// src/lib/metrics.ts
import { metrics } from "@opentelemetry/api";
const meter = metrics.getMeter("nextjs-app", "1.0.0");
// Compteur de requêtes
export const requestCounter = meter.createCounter("http_requests_total", {
description: "Nombre total de requêtes HTTP",
unit: "requests",
});
// Histogramme du temps de réponse
export const responseTimeHistogram = meter.createHistogram(
"http_response_duration_ms",
{
description: "Durée de réponse HTTP en millisecondes",
unit: "ms",
}
);
// Compteur d'erreurs
export const errorCounter = meter.createCounter("http_errors_total", {
description: "Nombre total d'erreurs HTTP",
unit: "errors",
});
// Jauge des connexions actives
export const activeConnections = meter.createUpDownCounter(
"active_connections",
{
description: "Nombre de connexions actuellement actives",
unit: "connections",
}
);Intégrer les métriques dans le Middleware
Créez un middleware pour enregistrer automatiquement les métriques :
// src/middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function middleware(request: NextRequest) {
const start = Date.now();
const response = NextResponse.next();
// Ajouter des en-têtes de traçage
response.headers.set("X-Request-Start", start.toString());
response.headers.set(
"X-Request-Id",
crypto.randomUUID()
);
return response;
}
export const config = {
matcher: ["/api/:path*", "/((?!_next/static|_next/image|favicon.ico).*)"],
};Créer une route API avec métriques complètes
// src/app/api/health/route.ts
import { NextResponse } from "next/server";
import {
requestCounter,
responseTimeHistogram,
errorCounter,
} from "@/lib/metrics";
import { withSpan } from "@/lib/tracing";
export async function GET() {
const start = Date.now();
return withSpan("GET /api/health", async (span) => {
try {
// Enregistrer la requête
requestCounter.add(1, {
method: "GET",
route: "/api/health",
});
// Simuler les vérifications de santé
const checks = {
database: "healthy",
cache: "healthy",
external_api: "healthy",
uptime: process.uptime(),
timestamp: new Date().toISOString(),
};
// Enregistrer le temps de réponse
const duration = Date.now() - start;
responseTimeHistogram.record(duration, {
method: "GET",
route: "/api/health",
status: "200",
});
span.setAttribute("health.status", "healthy");
span.setAttribute("health.duration_ms", duration);
return NextResponse.json(checks);
} catch (error) {
errorCounter.add(1, {
method: "GET",
route: "/api/health",
error_type: "health_check_failed",
});
throw error;
}
});
}Étape 7 : Créer une page de tableau de bord
Créez une page simple pour afficher l'état de la supervision :
// src/app/dashboard/page.tsx
"use client";
import { useEffect, useState } from "react";
interface HealthStatus {
database: string;
cache: string;
external_api: string;
uptime: number;
timestamp: string;
}
export default function DashboardPage() {
const [health, setHealth] = useState<HealthStatus | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchHealth = async () => {
try {
const res = await fetch("/api/health");
const data = await res.json();
setHealth(data);
} catch (err) {
console.error("Failed to fetch health:", err);
} finally {
setLoading(false);
}
};
fetchHealth();
const interval = setInterval(fetchHealth, 5000);
return () => clearInterval(interval);
}, []);
if (loading) {
return (
<div className="flex items-center justify-center min-h-screen">
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500" />
</div>
);
}
return (
<div className="max-w-4xl mx-auto p-8">
<h1 className="text-3xl font-bold mb-8">
Tableau de bord de supervision
</h1>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
{health && (
<>
<StatusCard
title="Base de données"
status={health.database}
/>
<StatusCard
title="Cache"
status={health.cache}
/>
<StatusCard
title="API externe"
status={health.external_api}
/>
</>
)}
</div>
<div className="bg-gray-900 rounded-lg p-6">
<h2 className="text-xl font-semibold mb-4">
Liens rapides
</h2>
<div className="space-y-3">
<ExternalLink
href="http://localhost:16686"
label="Jaeger UI — Voir les traces"
/>
<ExternalLink
href="http://localhost:9090"
label="Prometheus — Requêter les métriques"
/>
<ExternalLink
href="http://localhost:3001"
label="Grafana — Tableaux de bord"
/>
</div>
</div>
</div>
);
}
function StatusCard({
title,
status,
}: {
title: string;
status: string;
}) {
const isHealthy = status === "healthy";
return (
<div className="bg-gray-800 rounded-lg p-6">
<h3 className="text-sm font-medium text-gray-400 mb-2">
{title}
</h3>
<div className="flex items-center gap-2">
<div
className={`w-3 h-3 rounded-full ${
isHealthy ? "bg-green-500" : "bg-red-500"
}`}
/>
<span
className={
isHealthy ? "text-green-400" : "text-red-400"
}
>
{isHealthy ? "Sain" : "Défaillant"}
</span>
</div>
</div>
);
}
function ExternalLink({
href,
label,
}: {
href: string;
label: string;
}) {
return (
<a
href={href}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 text-blue-400 hover:text-blue-300 transition-colors"
>
<span>→</span>
{label}
</a>
);
}Étape 8 : Configurer le tableau de bord Grafana
Après avoir démarré les services avec docker compose up -d, ouvrez Grafana à http://localhost:3001 et connectez-vous avec admin / admin123.
Ajouter les sources de données
- Allez dans Configuration puis Data Sources
- Ajoutez Prometheus avec l'URL :
http://prometheus:9090 - Ajoutez Jaeger avec l'URL :
http://jaeger:16686
Créer un tableau de bord personnalisé
Créez un fichier grafana-dashboard.json pour l'importer dans Grafana :
{
"dashboard": {
"title": "Next.js Application Monitoring",
"panels": [
{
"title": "Request Rate",
"type": "timeseries",
"targets": [
{
"expr": "rate(nextjs_http_requests_total[5m])",
"legendFormat": "Requests/sec"
}
]
},
{
"title": "Response Time (p95)",
"type": "gauge",
"targets": [
{
"expr": "histogram_quantile(0.95, rate(nextjs_http_response_duration_ms_bucket[5m]))",
"legendFormat": "p95 Latency"
}
]
},
{
"title": "Error Rate",
"type": "stat",
"targets": [
{
"expr": "rate(nextjs_http_errors_total[5m])",
"legendFormat": "Errors/sec"
}
]
}
]
}
}Vous pouvez importer ce fichier via l'interface Grafana en allant dans Dashboards, puis Import, puis en collant le contenu JSON. Vous obtiendrez un tableau de bord prêt à l'emploi avec trois panneaux.
Étape 9 : Traçage avancé — Relier le Frontend au Backend
Pour corréler les traces du navigateur avec celles du serveur, créez un utilitaire côté client :
// src/lib/client-tracing.ts
export function createTracedFetch(
originalFetch: typeof fetch
): typeof fetch {
return async (input, init) => {
const requestId = crypto.randomUUID();
const start = performance.now();
const headers = new Headers(init?.headers);
headers.set("X-Request-Id", requestId);
headers.set("X-Client-Start", start.toString());
try {
const response = await originalFetch(input, {
...init,
headers,
});
const duration = performance.now() - start;
console.debug(
`[Trace] ${
typeof input === "string" ? input : input.url
} - ${duration.toFixed(1)}ms`
);
return response;
} catch (error) {
const duration = performance.now() - start;
console.error(
`[Trace Error] ${
typeof input === "string" ? input : input.url
} - ${duration.toFixed(1)}ms`,
error
);
throw error;
}
};
}Utiliser le Fetch tracé dans les composants
// src/hooks/useTracedFetch.ts
"use client";
import { useCallback } from "react";
import { createTracedFetch } from "@/lib/client-tracing";
const tracedFetch = createTracedFetch(fetch);
export function useTracedFetch() {
const fetchWithTrace = useCallback(
async <T>(url: string, options?: RequestInit): Promise<T> => {
const response = await tracedFetch(url, options);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return response.json();
},
[]
);
return { fetch: fetchWithTrace };
}Étape 10 : Configurer les alertes
Règles d'alerte Prometheus
Créez le fichier alert-rules.yml :
# alert-rules.yml
groups:
- name: nextjs-alerts
rules:
- alert: HighErrorRate
expr: rate(nextjs_http_errors_total[5m]) > 0.1
for: 2m
labels:
severity: critical
annotations:
summary: "Taux d'erreurs élevé dans l'application Next.js"
description: "Le taux d'erreurs a dépassé 10% au cours des 5 dernières minutes"
- alert: SlowResponseTime
expr: histogram_quantile(0.95, rate(nextjs_http_response_duration_ms_bucket[5m])) > 2000
for: 5m
labels:
severity: warning
annotations:
summary: "Temps de réponse lent détecté"
description: "Le temps de réponse p95 a dépassé 2000ms"
- alert: HighMemoryUsage
expr: process_resident_memory_bytes > 512 * 1024 * 1024
for: 10m
labels:
severity: warning
annotations:
summary: "Utilisation mémoire élevée"
description: "L'utilisation mémoire a dépassé 512 Mo"Mettez à jour prometheus.yml pour inclure les règles d'alerte :
# prometheus.yml (mis à jour)
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
- "alert-rules.yml"
scrape_configs:
- job_name: "otel-collector"
static_configs:
- targets: ["otel-collector:8889"]Étape 11 : Configurer les variables d'environnement
Créez .env.local pour le développement local :
# .env.local
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
OTEL_SERVICE_NAME=nextjs-otel-demo
OTEL_LOG_LEVEL=info
NODE_ENV=developmentEt .env.production pour la production :
# .env.production
OTEL_EXPORTER_OTLP_ENDPOINT=https://otel-collector.yourdomain.com
OTEL_SERVICE_NAME=nextjs-otel-production
OTEL_LOG_LEVEL=warn
NODE_ENV=productionÉtape 12 : Tester le système complet
Démarrer les services
# Démarrer les services de supervision
docker compose up -d
# Démarrer l'application Next.js
npm run devGénérer des données de traçage
Utilisez curl ou le navigateur pour envoyer des requêtes :
# Requête unique
curl http://localhost:3000/api/users
# Vérification de santé
curl http://localhost:3000/api/health
# Générer une charge légère (10 requêtes)
for i in $(seq 1 10); do
curl -s http://localhost:3000/api/users > /dev/null
echo "Request $i sent"
doneVérifier les résultats
-
Jaeger — Ouvrez
http://localhost:16686- Sélectionnez le service
nextjs-otel-demo - Vous verrez les traces pour chaque requête avec le timing détaillé
- Cliquez sur une trace pour voir l'arbre des spans
- Sélectionnez le service
-
Prometheus — Ouvrez
http://localhost:9090- Essayez la requête :
nextjs_http_requests_total - Essayez :
histogram_quantile(0.95, rate(nextjs_http_response_duration_ms_bucket[5m]))
- Essayez la requête :
-
Grafana — Ouvrez
http://localhost:3001- Importez le tableau de bord depuis le fichier JSON
- Observez les métriques en temps réel
Dépannage
Pas de traces dans Jaeger
- Vérifiez que le collecteur OpenTelemetry tourne :
docker compose logs otel-collector - Vérifiez que
OTEL_EXPORTER_OTLP_ENDPOINTpointe vers la bonne adresse - Assurez-vous que
instrumentationHook: trueest activé dansnext.config.ts
Métriques absentes dans Prometheus
- Vérifiez que le collecteur exporte vers Prometheus :
curl http://localhost:8889/metrics - Vérifiez que
scrape_configsest correctement configuré dansprometheus.yml
Erreurs avec Edge Runtime
- Le SDK OpenTelemetry ne supporte pas Edge Runtime
- Utilisez la condition
NEXT_RUNTIME === "nodejs"dans votre fichier instrumentation - N'importez pas les packages OTel dans le Middleware ou les Edge API Routes
Consommation mémoire élevée
- Réduisez
send_batch_sizedans les paramètres du collecteur - Augmentez
exportIntervalMillispour réduire la fréquence d'export - Utilisez le sampling pour réduire le volume de données en production
Bonnes pratiques pour la production
1. Utiliser le sampling
En production, vous n'avez pas besoin de tracer chaque requête. Utilisez le tail-based sampling :
// Dans instrumentation.ts
import { TraceIdRatioBasedSampler } from "@opentelemetry/sdk-trace-node";
const sdk = new NodeSDK({
// Ne tracer que 10% des requêtes
sampler: new TraceIdRatioBasedSampler(0.1),
// ... reste de la configuration
});2. Éviter le sur-traçage
- N'ajoutez pas de spans pour des opérations très rapides (moins de 1ms)
- Évitez d'enregistrer des données sensibles dans les attributs
- Utilisez des niveaux de log appropriés pour chaque environnement
3. Sécuriser les points de terminaison
# En production, utilisez TLS et l'authentification
exporters:
otlp/secure:
endpoint: https://otel.yourdomain.com:4317
tls:
cert_file: /etc/ssl/certs/client.crt
key_file: /etc/ssl/private/client.key
headers:
Authorization: "Bearer YOUR_TOKEN"4. Superviser le collecteur OpenTelemetry lui-même
# Ajouter la surveillance de santé du collecteur
extensions:
health_check:
endpoint: 0.0.0.0:13133
zpages:
endpoint: 0.0.0.0:55679
service:
extensions: [health_check, zpages]Prochaines étapes
Après avoir terminé ce guide, vous pouvez approfondir :
- Traçage distribué — Corréler les traces entre plusieurs microservices
- Métriques personnalisées — Ajouter des métriques métier comme le nombre d'utilisateurs actifs
- Corrélation des logs — Lier les logs aux traces via trace_id
- Real User Monitoring — Suivre les performances du navigateur avec OpenTelemetry Browser SDK
- Intégration CI/CD — Ajouter le traçage à votre pipeline de déploiement
Conclusion
Dans ce guide, vous avez appris à :
- Configurer OpenTelemetry avec Next.js 15 en utilisant le hook d'instrumentation
- Tracer les requêtes automatiquement et ajouter des spans personnalisés pour des opérations spécifiques
- Collecter des métriques comme le taux de requêtes, le temps de réponse et le taux d'erreurs
- Déployer un système de supervision complet avec Jaeger, Prometheus et Grafana
- Configurer les alertes pour détecter les problèmes avant que les utilisateurs ne les remarquent
Une bonne supervision n'est pas un luxe — c'est une nécessité pour toute application en production. Avec OpenTelemetry, vous disposez maintenant d'une visibilité complète sur ce qui se passe à l'intérieur de votre application.
Discutez de votre projet avec nous
Nous sommes ici pour vous aider avec vos besoins en développement Web. Planifiez un appel pour discuter de votre projet et comment nous pouvons vous aider.
Trouvons les meilleures solutions pour vos besoins.
Articles connexes

Deployer une Application Next.js avec Docker et CI/CD en Production
Apprenez a containeriser votre application Next.js avec Docker, configurer un pipeline CI/CD avec GitHub Actions, et deployer en production sur un VPS. Guide complet du developpement au deploiement automatise.

Docker Compose pour développeurs Full-Stack : Next.js, PostgreSQL et Redis
Apprenez à conteneuriser une application Next.js full-stack avec PostgreSQL et Redis en utilisant Docker Compose. Ce tutoriel pratique couvre l'orchestration multi-services, les workflows de développement, le rechargement à chaud, les health checks et les configurations prêtes pour la production.

Next.js 15 Partial Prerendering (PPR) : Construire un Dashboard Ultra-Rapide avec le Rendu Hybride
Maîtrisez le Partial Prerendering (PPR) de Next.js 15 — combinez rendu statique et dynamique dans une seule page. Construisez un dashboard analytique avec un shell statique instantané et du contenu dynamique en streaming.