Aller au contenu

Logs de Debug

⬇️ Télécharger cette page en Markdown


Vue d'ensemble

Le système de logs de debug permet de capturer l'intégralité du trafic HTTP et SQL à des fins d'investigation. Il est désactivé par défaut et ne génère aucun overhead quand inactif. Seul un utilisateur avec le rôle superadmin peut l'activer.

Usage production

Activez les logs uniquement le temps de l'investigation. Chaque requête génère plusieurs entrées en base — pensez à purger régulièrement.


Architecture

Architecture du logging de debug : init automatique, vérification debug.flag, capture requête et SQL, flush au shutdown

Composants

Composant Fichier Rôle
DebugLogger src/DebugLogger.php Classe singleton — capture, masquage, écriture
Database src/Database.php Instrumenté — appelle DebugLogger::logSql()
.user.ini public/.user.ini auto_prepend_file — chargement automatique
Table debug_logs DB Stockage des entrées
Interface superadmin public/superadmin_debug_logs.php Activation, filtres, visualisation

Activation / Désactivation

Via l'interface superadmin

/superadmin_debug_logs.php → bouton ▶ Activer le logging / ⏹ Désactiver

L'activation crée le fichier src/debug.flag. La désactivation le supprime. Effet immédiat sur toutes les requêtes suivantes.

Via shell (urgence)

# Activer
touch /var/www/html/src/debug.flag

# Désactiver
rm /var/www/html/src/debug.flag

Données capturées

Niveaux de log

Niveau Contenu Quand
request Méthode, endpoint, IP, user-agent, GET/POST/JSON, headers Début de chaque requête
sql Requête SQL, paramètres liés, durée (ms), nb lignes À chaque appel Database::*
info Statut HTTP, durée totale, pic mémoire, aperçu réponse Fin de requête (shutdown)
error Message + contexte, erreurs fatales PHP Exception ou E_ERROR

Paramètres configurables

Option Défaut Description
log_params ✅ GET/POST/corps JSON
log_sql ✅ Requêtes SQL + durée
log_headers ❌ Headers HTTP complets
log_responses ❌ Aperçu réponse (ob_start)
retention_days 7 Purge automatique

Champs masqués automatiquement

Les valeurs des champs dont la clé contient l'un de ces mots sont remplacées par [MASQUÉ] :

password, passwd, pwd, token, api_key, apikey, secret, authorization, x-api-key, credential

Troncature base64

Les données base64 (photos, vidéos) sont détectées (data:…;base64,) et remplacées par [BASE64_OMIS:Noctets] prefix… afin de ne pas saturer la base.


Corrélation des logs

Chaque requête HTTP reçoit un request_id UUID généré à l'initialisation. Toutes les entrées produites par cette requête (HTTP, SQL, erreurs, fin) partagent ce même request_id.

-- Reconstituer tout le flux d'une requête
SELECT level, sql_query, sql_params, sql_duration_ms,
       http_status, duration_ms, error_message, created_at
FROM debug_logs
WHERE request_id = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
ORDER BY id;

Dans l'interface, cliquer sur les 8 premiers caractères d'un request_id filtre automatiquement sur toute la requête.


Table debug_logs

CREATE TABLE debug_logs (
    id              BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    request_id      VARCHAR(36)   NOT NULL,
    level           ENUM('request','sql','error','info') NOT NULL,
    -- HTTP
    method          VARCHAR(10),
    endpoint        VARCHAR(500),
    ip_address      VARCHAR(45),
    user_agent      TEXT,
    user_id         INT,
    user_role       VARCHAR(50),
    -- Requête
    get_params      JSON,
    post_params     JSON,
    request_body    TEXT,
    request_headers JSON,
    -- SQL
    sql_query       TEXT,
    sql_params      JSON,
    sql_duration_ms FLOAT,
    sql_rows        INT,
    -- Réponse
    http_status     SMALLINT,
    response_preview TEXT,
    -- Méta
    duration_ms     FLOAT,
    memory_peak_kb  INT,
    error_message   TEXT,
    created_at      TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_request_id (request_id),
    INDEX idx_endpoint   (endpoint(100)),
    INDEX idx_level      (level),
    INDEX idx_created_at (created_at)
);

Instrumentation de Database.php

Les quatre méthodes publiques sont instrumentées avec un timer :

public function fetchAll(string $sql, array $params = []): array {
    $t    = microtime(true);
    $stmt = $this->pdo->prepare($sql);
    $stmt->execute($params);
    $rows = $stmt->fetchAll();
    if (class_exists('DebugLogger') && DebugLogger::isEnabled()) {
        DebugLogger::logSql($sql, $params, (microtime(true) - $t) * 1000, count($rows));
    }
    return $rows;
}

Le check class_exists('DebugLogger') garantit qu'aucune erreur ne survient si le logger n'est pas chargé (pages CLI, tests unitaires).


Anti-récursion

DebugLogger utilise une connexion PDO dédiée distincte du singleton Database, et un flag statique $writing qui empêche tout appel récursif lors de l'écriture en base.

Requête HTTP
  └─ Database::fetchAll()          → DebugLogger::logSql() (buffer)
  └─ shutdown()
       └─ DebugLogger::insertRow() → PDO interne (non instrumenté)

Interface superadmin

Accessible à /superadmin_debug_logs.php (rôle superadmin requis).

Fonctionnalités

  • Toggle on/off : activation instantanée sans redémarrage
  • Paramètres : granularité des données capturées, rétention
  • Filtres : niveau, endpoint (LIKE), IP, date, request_id exact
  • Tableau : clic sur une ligne → détail expandable (tous les champs)
  • Corrélation : clic sur un request_id → filtre sur toute la requête
  • Purge : par ancienneté ou purge totale (TRUNCATE)

Exemple d'investigation

1. Activer le logging
2. Reproduire le bug depuis l'app ou le navigateur
3. Désactiver le logging
4. Filtrer par endpoint (ex: /api/submit_incident.php) ou par IP
5. Cliquer sur le request_id pour voir la séquence complète :
   request → SQL Auth → SQL mairie → SQL types → SQL INSERT → info
6. Identifier l'étape qui échoue (http_status, error_message, sql_params)
7. Purger les logs après investigation

Sécurité

  • Accès restreint : page superadmin uniquement — $auth->requireRole(['superadmin'])
  • Données sensibles masquées : passwords, tokens, clés API jamais stockés en clair
  • Base64 tronqués : photos et vidéos ne saturent pas la base
  • Connexion isolée : DebugLogger a sa propre PDO, non loggée récursivement
  • Désactivation en prod : le flag file absent = overhead nul, aucune donnée collectée

Ne pas laisser actif en production

Les logs contiennent les paramètres des requêtes (adresses, descriptions d'incidents, etc.). Activez uniquement le temps de l'investigation, puis purgez.