vendredi 25 septembre 2026

À propos

Contact

Extensions

Journaliser proprement dans une extension WordPress : niveaux et rotation

error_log tout court finit toujours par produire un fichier illisible de douze mégaoctets. Une extension de synchronisation bancaire m'a forcé à concevoir un vrai petit système de journalisation.

Par Clément Hadrot • 22 septembre 2022 • 4 min de lecture • Aucun commentaire
Journaliser proprement dans une extension WordPress : niveaux et rotation

Une extension chargée de synchroniser quotidiennement les écritures comptables d’un cabinet d’expertise avec son logiciel bancaire produisait, en cas d’échec, des messages noyés dans le fichier error_log général du serveur, partagé avec des dizaines d’autres messages PHP sans rapport. Après quelques mois de fonctionnement, ce fichier avait atteint douze mégaoctets, rendant toute recherche d’un incident précis pénible. Il fallait un système de journalisation dédié, avec ses propres niveaux et sa propre rotation.

Une classe de log minimale

class Kaolin_Logger {

    const DEBUG   = 'debug';
    const INFO    = 'info';
    const WARNING = 'warning';
    const ERROR   = 'error';

    private static $niveau_minimum = self::INFO;

    public static function log( $niveau, $message, $contexte = array() ) {
        if ( ! self::doit_journaliser( $niveau ) ) {
            return;
        }

        $ligne = sprintf(
            "[%s] [%s] %s %s\n",
            current_time( 'mysql' ),
            strtoupper( $niveau ),
            $message,
            ! empty( $contexte ) ? wp_json_encode( $contexte ) : ''
        );

        self::ecrire( $ligne );
    }

    private static function doit_journaliser( $niveau ) {
        $ordre = array( self::DEBUG => 0, self::INFO => 1, self::WARNING => 2, self::ERROR => 3 );
        return $ordre[ $niveau ] >= $ordre[ self::$niveau_minimum ];
    }
}

Séparer les niveaux dès la conception permet de garder debug et info silencieux en production, tout en conservant automatiquement les warning et error qui méritent une attention immédiate, sans devoir commenter ou décommenter du code selon l’environnement.

Écrire dans un fichier protégé, pas dans les uploads publics

L'essentiel à retenir : Une classe de log minimale sépare les niveaux debug, info, warning et error ; Écrire dans un fichier protégé du répertoire uploads évite l'exposition publique ; La rotation des fichiers empêche un journal de grossir indéfiniment

Le répertoire wp-content/uploads est, par défaut, entièrement accessible publiquement via HTTP. Y écrire un journal contenant potentiellement des identifiants de transaction ou des messages d’erreur techniques serait une fuite d’information évitable. La solution retenue combine un sous-répertoire dédié et un fichier .htaccess qui en interdit l’accès direct.

private static function ecrire( $ligne ) {
    $upload_dir = wp_upload_dir();
    $dossier    = trailingslashit( $upload_dir['basedir'] ) . 'kaolin-logs';

    if ( ! file_exists( $dossier ) ) {
        wp_mkdir_p( $dossier );
        file_put_contents( $dossier . '/.htaccess', "Deny from all\n" );
        file_put_contents( $dossier . '/index.php', "<?php\n// Silence is golden.\n" );
    }

    $fichier = $dossier . '/synchro-' . gmdate( 'Y-m-d' ) . '.log';
    error_log( $ligne, 3, $fichier );
}

Le fichier index.php vide complète la protection sur les configurations serveur où .htaccess ne serait pas pris en compte (Nginx par exemple), en évitant qu’un listage de répertoire n’expose la liste des journaux disponibles.

Un fichier par jour, pour une rotation naturelle

Plutôt que d’écrire indéfiniment dans un unique fichier, nommer chaque fichier de journal avec la date du jour (synchro-2022-09-22.log) offre une rotation naturelle, sans dépendance à un outil externe comme logrotate, pas toujours accessible sur un hébergement mutualisé.

add_action( 'kaolin_nettoyer_vieux_journaux', 'kaolin_supprimer_journaux_anciens' );

function kaolin_supprimer_journaux_anciens() {
    $upload_dir = wp_upload_dir();
    $dossier    = trailingslashit( $upload_dir['basedir'] ) . 'kaolin-logs';
    $fichiers   = glob( $dossier . '/synchro-*.log' );
    $limite     = strtotime( '-30 days' );

    foreach ( (array) $fichiers as $fichier ) {
        if ( filemtime( $fichier ) < $limite ) {
            unlink( $fichier );
        }
    }
}

if ( ! wp_next_scheduled( 'kaolin_nettoyer_vieux_journaux' ) ) {
    wp_schedule_event( time(), 'daily', 'kaolin_nettoyer_vieux_journaux' );
}

Une conservation de trente jours s’est avérée suffisante pour ce cabinet comptable : largement assez pour investiguer un incident signalé avec retard, sans laisser les journaux s’accumuler indéfiniment sur le serveur.

Désactiver le niveau debug en production

Le niveau minimum de journalisation ne doit jamais rester à DEBUG en production : le volume de lignes générées deviendrait rapidement disproportionné par rapport à leur utilité réelle. Un filtre dédié permet d’ajuster ce seuil sans modifier le code de la classe elle-même.

add_filter( 'kaolin_logger_niveau_minimum', function ( $niveau ) {
    return defined( 'WP_DEBUG' ) && WP_DEBUG ? Kaolin_Logger::DEBUG : Kaolin_Logger::INFO;
} );

Cette bascule automatique, calquée sur la constante WP_DEBUG déjà présente dans le fichier wp-config.php, évite d’introduire un réglage supplémentaire à gérer manuellement pour chaque environnement de déploiement.

Ce que ce système ne remplace pas

Ce mécanisme reste un journal applicatif simple, pas un système de monitoring. Pour une alerte en temps réel en cas d’échec répété de la synchronisation bancaire, une notification par courriel ou l’intégration d’un outil de supervision externe reste nécessaire en complément : lire un fichier de log après coup ne suffit jamais à réagir dans l’urgence.

En résumé

Un système de journalisation minimal, avec niveaux, stockage protégé et rotation quotidienne, tient en une centaine de lignes de code et évite les deux écueils les plus fréquents : un error_log général illisible, et un journal exposé publiquement par mégarde dans le répertoire des uploads. Pour ce cabinet comptable, ce système a transformé un débogage de plusieurs heures en une recherche de quelques minutes dans le fichier du jour concerné.

Partager :

À propos de l'auteur

Clément Hadrot

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi