Activation et persistance des logs SQL avec Spring Boot et MyBatis-Plus

Lors de l'intégration de MyBatis-Plus dans un projet Spring Boot, il est fréquent de devoir auditer ou déboguer les requêtes SQL générées. Cet article explore la configuration adéquate pour capturer ces requêtes et leurs paramètres, non seulement dans la console, mais aussi dans les fichiers de log persistants.

Pour cet exemple, nous utilisons Spring Boot 2.7.x et MyBatis-Plus 3.5.x. Voici la dépendance Maven de base :

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.3</version>
</dependency>

Le piège de la configuration standard (StdOutImpl)

Une solution couramment trouvée sur internet pour afficher les requêtes SQL consiste à modifier la configuration de l'implémentation du logger :

mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

Avec cette configuration, les requêtes s'affichent correctement dans la console de l'IDE :

SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2a4b1c] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@8834f2 wrapping com.mysql.cj.jdbc.ConnectionImpl@1b4e2a] will not be managed by Spring
==>  Preparing: SELECT id, username, email, created_at FROM client_account WHERE username = ? 
==> Parameters: john_doe(String)
<==    Columns: id, username, email, created_at
<==        Row: 1, john_doe, john@example.com, 2023-10-01 12:00:00
<==      Total: 1
Closing non transactional SqlSession

Cependant, une fois l'application déployée sous forme de JAR exécutable en production, le fichier de log (par exemple application.log) ne contient aucune trace de ces requêtes SQL. Seuls les logs de démarrage du serveur Tomcat sont présents :

2023-10-24 10:15:30.112  INFO 12450 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http)
2023-10-24 10:15:30.145  INFO 12450 --- [main] c.e.d.ApiApplication                     : Started ApiApplication in 4.5 seconds

La raison est simple : la classe StdOutImpl utilise directement System.out.println(). Elle contourne donc complètement le framework de journalisation de Spring Boot (Logback par défaut) et n'écrit rien dans les fichiers configurés via logback-spring.xml.

Migration vers SLF4J et gestion des niveaux de log

Pour que les logs SQL soient correctement routés vers les fichiers, il faut utiliser l'implémentation SLF4J fournie par MyBatis :

mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.slf4j.Slf4jImpl

Après un redémarrage, on constate souvent avec surprise qu'aucun log SQL n'apparaît, ni dans la console ni dans les fichiers. En analysant le code source de MyBatis-Plus (notamment les optimiseurs comme JsqlParserCountOptimize ou les proxies de mapper), on remarque que l'émission des logs est conditionnée par une vérification du niveau de debug :

if (logger.isDebugEnabled()) {
    logger.debug("Executing SQL: {} with parameters: {}", sql, params);
}

Contrairement à StdOutImpl qui force l'affichage, Slf4jImpl respecte la configuration des niveaux de log de Logback. Par défaut, le niveau est configuré sur INFO, ce qui masque les messages DEBUG.

Pour résoudre ce problème, il est nécessaire d'abaisser le niveau de log à DEBUG pour le package contenant vos interfaces Mapper, ou pour le package interne de MyBatis-Plus. En format YAML, cela donne :

logging:
  level:
    # Activer le debug pour les mappers de votre projet
    com.example.project.mapper: DEBUG
    # Optionnel : activer le debug pour le moteur interne de MyBatis-Plus
    com.baomidou.mybatisplus: DEBUG

Avec cette configuration finale, les requêtes SQL, les paramètres bindés et les résultats seront correctement interceptés par Logback et persistés dans vos fichiers de log, tout en restant visibles dans la console lors du développement.

Étiquettes: spring-boot MyBatis-Plus logback slf4j sql-logging

Publié le 2 octobre à 02h05