Vous connaissez cette sensation frustrante quand votre site WordPress rame sans que vous compreniez pourquoi ? Les outils classiques de monitoring vous montrent des métriques globales, mais impossible de savoir si c’est ce plugin gourmand, cette requête SQL mal optimisée ou ce call API qui plombe tout. Heureusement, avec OpenTelemetry et Jaeger, on peut enfin traquer chaque requête dans les moindres détails et transformer le debugging en véritable enquête policière !
Concepts d’observabilité et tracing distribué
Quand on parle de monitoring WordPress, on pense souvent aux plugins classiques qui affichent quelques métriques basiques. Mais avec l’évolution vers des architectures plus complexes (API REST, microservices, CDN), on a besoin d’outils plus sophistiqués. C’est là qu’intervient l’observabilité moderne.
OpenTelemetry et l’écosystème d’observabilité
OpenTelemetry, c’est un peu le couteau suisse de l’observabilité. Ce framework open-source permet de collecter des données de télémétrie (traces, métriques, logs) depuis vos applications WordPress. Contrairement à des solutions propriétaires comme New Relic ou Datadog, OpenTelemetry vous évite le vendor lock-in : vous restez maître de vos données.
L’avantage principal ? Vous instrumentez votre code une seule fois, et vous pouvez envoyer les données vers n’importe quel backend compatible (Jaeger, Zipkin, Prometheus). Pour un site WordPress, cela signifie qu’on peut tracer les requêtes depuis le navigateur jusqu’à la base de données, en passant par tous les plugins et thèmes.
Les traces distribuées : comprendre les spans
Une trace distribuée, c’est comme suivre un colis à la trace. Chaque étape du parcours (tri postal, transport, livraison) correspond à un « span » dans notre terminologie. Dans WordPress, une requête HTTP génère une trace composée de plusieurs spans : traitement du thème, exécution des hooks, requêtes SQL, appels d’API externes.
Chaque span contient des informations précieuses : durée d’exécution, paramètres, erreurs éventuelles. Quand votre page WordPress met 3 secondes à se charger, au lieu de chercher à l’aveugle, vous voyez exactement que le problème vient du plugin de e-commerce qui fait 15 requêtes SQL non optimisées.
Métriques vs logs vs traces : quelle différence ?
C’est souvent là que ça se complique, alors clarifions avec des exemples WordPress concrets :
Les métriques : ce sont vos indicateurs numériques (temps de réponse moyen, nombre de requêtes par minute, utilisation CPU). Perfect pour les dashboards et les alertes.
Les logs : vos fichiers debug.log habituels, mais en mieux structurés. Ils racontent ce qui s’est passé à un moment donné (« Plugin XYZ a généré une erreur PHP à 14h32 »).
Les traces : elles montrent le parcours complet d’une requête à travers votre stack. C’est le film complet, pas juste une photo. Vous voyez comment les différents composants interagissent entre eux.
En pratique, ces trois éléments se complètent. Les métriques vous alertent qu’il y a un problème, les logs vous donnent le contexte, et les traces vous montrent la chaîne de causalité complète.
Installation et configuration d’OpenTelemetry pour PHP
Maintenant qu’on a bien cerné les concepts d’observabilité, passons à la pratique ! Installer OpenTelemetry pour PHP, ça peut sembler intimidant au premier abord, mais en réalité c’est assez straightforward. Je vais vous guider étape par étape pour que tout fonctionne correctement.
Prérequis système et versions supportées
Avant de se lancer, vérifions que notre environnement est compatible. OpenTelemetry pour PHP nécessite au minimum PHP 8.0 (même si je recommande fortement PHP 8.1 ou plus récent pour de meilleures performances). Côté système, vous aurez besoin de :
- PHP 8.0+ avec l’extension
jsonetcurl - Composer pour gérer les dépendances
- L’extension
grpcsi vous comptez utiliser le protocole OTLP (recommandé) - Un serveur web configuré (Apache, Nginx…)
Attention : sur certains hébergements mutualisés, vous n’aurez pas accès aux extensions PECL. Dans ce cas, l’instrumentation manuelle reste possible.
Installation via PECL et compilation
La méthode la plus efficace, c’est d’installer l’extension PECL. Ça donne de meilleures performances qu’une implémentation purement PHP :
# Installation via PECL
pecl install opentelemetry
# Ou compilation depuis les sources
git clone https://github.com/open-telemetry/opentelemetry-php-instrumentation.git
cd opentelemetry-php-instrumentation
phpize
./configure
make && make install
Ensuite, ajoutez l’extension dans votre php.ini :
extension=opentelemetry.so
Bon, je dois être honnête : cette approche nécessite des droits administrateur. Sur un serveur partagé, ça peut poser problème.
Auto-instrumentation vs instrumentation manuelle
Là, vous avez deux écoles. L’auto-instrumentation, c’est magique : elle détecte automatiquement les frameworks et bibliothèques populaires (Symfony, Laravel, WordPress…). Très pratique pour débuter !
Pour l’activer :
composer require open-telemetry/opentelemetry-auto-instrumentation
L’instrumentation manuelle vous donne plus de contrôle. Vous décidez exactement quoi tracer :
use OpenTelemetry\API\Trace\Propagation\TraceContextPropagator;
use OpenTelemetry\SDK\Trace\TracerProvider;
$tracerProvider = new TracerProvider();
$tracer = $tracerProvider->getTracer('wordpress-monitor');
Personnellement, je commence toujours par l’auto-instrumentation pour avoir une vue d’ensemble, puis j’affine avec du manuel.
Configuration via variables d’environnement
OpenTelemetry utilise extensivement les variables d’environnement. C’est pratique car ça évite de hard-coder les configurations :
# Endpoint du collecteur
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
# Headers d'authentification
OTEL_EXPORTER_OTLP_HEADERS="authorization=Bearer your-token"
# Nom du service
OTEL_SERVICE_NAME="wordpress-production"
# Ratio d'échantillonnage (1.0 = 100%)
OTEL_TRACES_SAMPLER=traceidratio
OTEL_TRACES_SAMPLER_ARG=0.1
Dans WordPress, vous pouvez définir ces variables dans votre wp-config.php :
putenv('OTEL_SERVICE_NAME=mon-site-wordpress');
putenv('OTEL_EXPORTER_OTLP_ENDPOINT=https://jaeger.example.com:4318');
Configuration php.ini détaillée
Le fichier php.ini permet de configurer finement le comportement d’OpenTelemetry :
[opentelemetry]
; Active l'auto-instrumentation
otel.traces.enabled = On
; Définit les hooks à instrumenter
otel.traces.hooks = curl,pdo,wordpress
; Limite la taille des spans
otel.traces.span_max_attributes = 128
; Configuration des logs
otel.logs.level = info
otel.logs.destination = /var/log/otel.log
Attention : redémarrez votre serveur web après modification du php.ini !
Exemples de configuration par environnement
Développement local :
# .env.local
OTEL_SERVICE_NAME="wordpress-dev"
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
OTEL_TRACES_SAMPLER_ARG=1.0 # 100% des traces
OTEL_LOG_LEVEL=debug
Staging :
# .env.staging
OTEL_SERVICE_NAME="wordpress-staging"
OTEL_EXPORTER_OTLP_ENDPOINT=https://otel-collector-staging.example.com
OTEL_TRACES_SAMPLER_ARG=0.5 # 50% des traces
OTEL_EXPORTER_OTLP_HEADERS="x-api-key=staging-key"
Production :
# .env.production
OTEL_SERVICE_NAME="wordpress-prod"
OTEL_EXPORTER_OTLP_ENDPOINT=https://secure-otel.example.com:4318
OTEL_TRACES_SAMPLER_ARG=0.01 # 1% seulement
OTEL_EXPORTER_OTLP_HEADERS="authorization=Bearer prod-secret-token"
Configuration des exportateurs
Les exportateurs définissent où vont vos données. Voici les configurations principales :
OTLP (recommandé) :
use OpenTelemetry\Contrib\Otlp\OtlpHttpTransportFactory;
use OpenTelemetry\SDK\Trace\SpanExporter\OtlpSpanExporter;
$transport = (new OtlpHttpTransportFactory())->create(
'http://localhost:4318/v1/traces',
'application/x-protobuf'
);
$exporter = new OtlpSpanExporter($transport);
Jaeger (legacy) :
use OpenTelemetry\Contrib\Jaeger\JaegerHttpTransportFactory;
$transport = (new JaegerHttpTransportFactory())->create(
'http://localhost:14268/api/traces'
);
Zipkin :
use OpenTelemetry\Contrib\Zipkin\ZipkinTransportFactory;
$transport = (new ZipkinTransportFactory())->create(
'http://localhost:9411/api/v2/spans'
);
Bonnes pratiques de sécurité
C’est crucial : vos données de monitoring contiennent des informations sensibles ! Quelques règles de base :
- Utilisez HTTPS pour tous les endpoints de production
- Tokens d’authentification : stockez-les dans des variables d’environnement, jamais dans le code
- Filtrage des données : évitez de tracer les mots de passe ou tokens
- Rate limiting : configurez des limites pour éviter le spam
// Exemple de filtrage des données sensibles
use OpenTelemetry\API\Trace\Span;
function sanitizeSpanData(Span $span, array $data): array {
$sensitive = ['password', 'token', 'api_key'];
foreach ($sensitive as $key) {
if (isset($data[$key])) {
$data[$key] = '[FILTERED]';
}
}
return $data;
}
N’oubliez pas de configurer des endpoints sécurisés avec authentification mutuelle (mTLS) en production. Ça vaut vraiment le coup pour protéger vos données de monitoring !
Instrumentation du code WordPress
Maintenant qu’on a installé OpenTelemetry, passons aux choses sérieuses : instrumenter le code WordPress. Et attention, c’est là que ça devient vraiment intéressant ! On va pouvoir tracer chaque action, chaque requête, chaque appel pour comprendre ce qui se passe sous le capot de notre site.
Hooks et actions WordPress instrumentés
Les hooks WordPress, c’est le cœur du système. Instrumenter ces actions nous permet de voir exactement où notre site passe du temps. Voici comment faire :
// Instrumentation des hooks principaux
function instrument_wp_hooks() {
$tracer = OpenTelemetry\API\Globals::tracerProvider()->getTracer('wordpress');
add_action('init', function() use ($tracer) {
$span = $tracer->spanBuilder('wp_hook_init')->startSpan();
// Votre code init ici
$span->end();
}, 1);
add_action('wp_head', function() use ($tracer) {
$span = $tracer->spanBuilder('wp_head_render')
->setAttribute('hook.name', 'wp_head')
->startSpan();
// Logique wp_head
$span->end();
}, 1);
}
Personnellement, j’ai découvert que le hook wp_head pouvait prendre jusqu’à 300ms sur certains sites… avec 15 plugins qui s’y accrochent !
Monitoring des requêtes base de données
La base de données, c’est souvent le goulot d’étranglement. WordPress utilise wpdb, et on peut facilement l’instrumenter :
// Hooker wpdb pour tracer les requêtes
add_filter('query', function($query) {
global $wpdb;
$tracer = OpenTelemetry\API\Globals::tracerProvider()->getTracer('wordpress-db');
$span = $tracer->spanBuilder('db_query')
->setAttribute('db.statement', substr($query, 0, 100))
->setAttribute('db.operation', $wpdb->last_operation)
->startSpan();
$start_time = microtime(true);
$result = $query;
$duration = (microtime(true) - $start_time) * 1000;
if ($duration > 100) { // Requête lente
$span->setAttribute('db.slow_query', true);
$span->setAttribute('db.duration_ms', $duration);
}
$span->end();
return $result;
});
Attention : cette approche peut générer beaucoup de données. En production, utilisez un sampling à 1% maximum pour les requêtes normales, mais gardez 100% pour les requêtes > 500ms.
Traçage des appels API et requêtes HTTP
WordPress fait souvent des appels externes (APIs, webhooks, etc.). Voici comment les tracer :
// Instrumenter wp_remote_get et wp_remote_post
add_filter('pre_http_request', function($preempt, $args, $url) {
$tracer = OpenTelemetry\API\Globals::tracerProvider()->getTracer('wordpress-http');
$span = $tracer->spanBuilder('http_request')
->setAttribute('http.url', $url)
->setAttribute('http.method', $args['method'] ?? 'GET')
->startSpan();
// Le span sera fermé par le hook suivant
set_transient('otel_current_span', $span, 60);
return $preempt;
}, 10, 3);
add_filter('http_response', function($response, $args, $url) {
$span = get_transient('otel_current_span');
if ($span) {
$span->setAttribute('http.status_code', wp_remote_retrieve_response_code($response));
$span->end();
delete_transient('otel_current_span');
}
return $response;
}, 10, 3);
Pour les APIs REST WordPress, c’est encore plus simple :
// Tracer les endpoints REST
add_action('rest_api_init', function() {
$tracer = OpenTelemetry\API\Globals::tracerProvider()->getTracer('wp-rest');
add_filter('rest_pre_dispatch', function($result, $server, $request) use ($tracer) {
$span = $tracer->spanBuilder('rest_endpoint')
->setAttribute('rest.route', $request->get_route())
->setAttribute('rest.method', $request->get_method())
->startSpan();
// Stocker le span pour le fermer après
$GLOBALS['rest_span'] = $span;
return $result;
}, 10, 3);
});
Instrumentation des plugins et thèmes
Instrumenter les plugins, c’est là où on découvre les vrais coupables des lenteurs ! Voici des exemples concrets :
// Instrumentation WooCommerce
if (class_exists('WooCommerce')) {
add_action('woocommerce_before_calculate_totals', function() {
$tracer = OpenTelemetry\API\Globals::tracerProvider()->getTracer('woocommerce');
$span = $tracer->spanBuilder('wc_calculate_totals')->startSpan();
$GLOBALS['wc_calc_span'] = $span;
});
add_action('woocommerce_after_calculate_totals', function() {
if (isset($GLOBALS['wc_calc_span'])) {
$GLOBALS['wc_calc_span']->end();
}
});
}
// Instrumentation ACF
if (function_exists('get_field')) {
add_filter('acf/load_value', function($value, $post_id, $field) {
$tracer = OpenTelemetry\API\Globals::tracerProvider()->getTracer('acf');
$span = $tracer->spanBuilder('acf_load_field')
->setAttribute('acf.field_name', $field['name'])
->setAttribute('acf.post_id', $post_id)
->startSpan();
// Logique de chargement...
$span->end();
return $value;
}, 10, 3);
}
Bon, soyons honnêtes : instrumenter chaque plugin à la main, c’est fastidieux. Mais concentrez-vous sur les plus gourmands en ressources. Un plugin de cache mal configuré peut facilement ajouter 200ms par page !
Bonnes pratiques pour éviter l’overhead :
- Utilisez un sampling intelligent (1% en production normale, 10% lors des investigations)
- Ne tracez que les opérations > 10ms
- Limitez les attributs des spans (maximum 10 par span)
- Désactivez l’instrumentation sur wp-admin si pas nécessaire
Et surtout : testez l’impact performance ! J’ai vu des sites ralentir de 50ms juste à cause d’une instrumentation trop agressive. L’observabilité, c’est bien, mais pas au détriment des performances utilisateur.
Configuration de Jaeger et analyse des traces
Maintenant que vous avez instrumenté votre code WordPress avec OpenTelemetry, il faut bien stocker et analyser toutes ces traces quelque part ! C’est exactement le rôle de Jaeger, qui va nous permettre de visualiser le comportement de notre application en détail.
Installation et déploiement de Jaeger
Bon, je vais être honnête : la première fois que j’ai installé Jaeger, j’ai galéré avec toutes les dépendances. Heureusement, Docker Compose simplifie grandement les choses !
Voici un fichier docker-compose.yml complet pour déployer Jaeger :
version: '3.8'
services:
jaeger-collector:
image: jaegertracing/jaeger-collector:latest
command:
- "--cassandra.keyspace=jaeger_v1_dc1"
- "--cassandra.servers=cassandra"
- "--collector.otlp.enabled=true"
ports:
- "14268:14268" # jaeger.thrift
- "14250:14250" # gRPC
- "4317:4317" # OTLP gRPC
- "4318:4318" # OTLP HTTP
depends_on:
- cassandra
jaeger-query:
image: jaegertracing/jaeger-query:latest
command:
- "--cassandra.keyspace=jaeger_v1_dc1"
- "--cassandra.servers=cassandra"
ports:
- "16686:16686"
depends_on:
- cassandra
cassandra:
image: cassandra:3.11
environment:
- CASSANDRA_CLUSTER_NAME=jaeger
Attention cependant : cette configuration utilise Cassandra comme backend de stockage, ce qui est parfait pour la production. Pour du développement, vous pouvez utiliser le mode « all-in-one » plus simple :
jaeger:
image: jaegertracing/all-in-one:latest
ports:
- "16686:16686" # Interface web
- "4317:4317" # OTLP gRPC
- "4318:4318" # OTLP HTTP
environment:
- COLLECTOR_OTLP_ENABLED=true
Le port 4317 (gRPC) ou 4318 (HTTP) correspondent aux endpoints OTLP que vous devez configurer dans votre application WordPress. Dans votre configuration OpenTelemetry, vous utiliserez donc http://localhost:4318/v1/traces comme endpoint.
Interface web et navigation dans les traces
Une fois Jaeger démarré, rendez-vous sur http://localhost:16686 pour accéder à l’interface web. Et là… c’est magique ! Vous allez voir toutes vos traces WordPress s’afficher.
L’interface principale se divise en plusieurs sections :
- Service : sélectionnez votre service WordPress (celui que vous avez défini dans la configuration)
- Operation : filtrez par opération spécifique (page d’accueil, admin, API, etc.)
- Tags : ajoutez des filtres avancés (user_id, post_type, etc.)
- Lookback : définissez la période d’analyse
Pour analyser une trace, cliquez dessus dans la liste. Vous obtenez alors une vue détaillée avec :
- Timeline view : visualisation chronologique de tous les spans
- Trace Graph : représentation des dépendances entre services
- Span Details : métadonnées et tags de chaque span
La vue timeline est particulièrement utile : chaque span est représenté par une barre horizontale. Plus la barre est longue, plus l’opération a pris du temps. Vous pouvez cliquer sur chaque span pour voir ses détails (durée, tags, logs, erreurs éventuelles).
Un conseil pratique : utilisez les tags pour filtrer efficacement. Par exemple, si vous avez tagué vos traces avec post_type:product, vous pouvez rapidement isoler les problèmes liés à WooCommerce.
Identification des goulots d’étranglement
C’est ici que ça devient vraiment intéressant ! Jaeger vous permet d’identifier précisément où votre site WordPress traîne.
Voici quelques patterns typiques que j’ai observés :
Plugin gourmand : vous voyez un span qui prend 2-3 secondes sur une durée totale de 4 secondes ? C’est probablement un plugin mal optimisé. Les spans enfants vous montreront exactement quelles fonctions posent problème.
Requête SQL lente : les spans wpdb::query qui dépassent 100ms méritent votre attention. Regardez le tag db.statement pour voir la requête exacte, puis optimisez-la (index manquant, requête N+1, etc.).
API tierce lente : les appels HTTP externes apparaissent clairement dans les traces. Si votre span wp_remote_get vers l’API de votre CRM prend 5 secondes, vous savez où agir (cache, timeout, requêtes asynchrones).
Pour optimiser, commencez toujours par les spans les plus longs. Jaeger calcule automatiquement le pourcentage de temps passé dans chaque span par rapport au total. Concentrez-vous sur ceux qui représentent plus de 20% du temps total.
Une technique que j’utilise souvent : comparez les traces avant/après optimisation. Créez des bookmarks dans Jaeger pour retrouver facilement vos traces de référence. Ainsi, vous pouvez mesurer objectivement l’impact de vos optimisations.
