Search code examples
spring-boothibernateapache-poilog4j2logback

Hibernate debug/trace logging when both logback and log4j are in classpath


Having:

  • Spring-boot:2.6.7
  • Hibernate:5.6.8
  • logback as default logging implementation
  • Apache POI poi-ooxml:5.2.3.

We need to log SQL queries and parameters. Usually this is enabled either from Spring logging configuration:

logging.level.org.hibernate.SQL=debug
logging.level.org.hibernate.type.descriptor.sql=trace

or directly in logback.xml configuration:

<logger name="org.hibernate.SQL" level="debug"/>
<logger name="org.hibernate.type.descriptor.sql" level="trace"/>

Both were working until recent POI update. Starting from POI 5.1.0 it requires log4j2 API and can not be excluded from classpath any more (otherwise XSSFWorkbook can't be initialized at runtime).

This leads that both logback and log4j2 API classes are in classpath.

At the same time Hibernate uses JBoss Logger provider (BasicExtractor, BasicBinder) which has log4j2 precedence.

Without log4j it works fine and prints SQL and and parameters, but as soon as log4j2 available, either Spring or logback.xml configurations are ignored and debug or traces are not printed any more.

I tried the following:

  • excluding log4j API from POI: leads to runtime exception as org.apache.logging.log4j.Logger is not available in XSSFWorkbook
  • including org.apache.logging.log4j:log4j-slf4j2-impl:2.20.0 and org.apache.logging.log4j:log4j-to-slf4j:2.20.0: doesn't help (logger provider is still Log4j2LoggerProvider and the Logger implementation ignores Spring or logback configuration
  • including org.slf4j:log4j-over-slf4j:2.0.9 - doesn't work either

Question: is it possible to configure the application to enable debug and trace for Hibernate classes if both logback and slf4j2 are in classpath?

(without having both logback.xml and log4j2.xml files in the classpath)


Solution

  • If you are using Spring Boot's starters you have nothing to do: every starter pulls in spring-boot-starter, which depends on spring-boot-starter-logging. The latter depends on:

    • logback-classic,
    • the right bridges between every major logging API and SLF4J (which is Logback's native API). Among them you have log4j-to-slf4j, which connects the Log4j API to SLF4J.

    Just remove all explicit logging dependencies and exclusions and you should be fine. You should especially remove log4j-slf4j2-impl: its naming is ambiguous, but it is actually a bridge from SLF4J to the Log4j API. If you deploy it together with log4j-to-slf4j it will issue a warning and deactivate itself to prevent an infinite recursion.

    Remark: Spring's version of JCL (cf. source code) also prefers the Log4j API over SLF4J.

    Edit: Might I provide some debugging tips:

    • XSSFWorkbook fails in your experiments if you forcibly exclude log4j-api. There is no need to do this. The log4j-api/log4j-core artifact pair works exactly as the slf4j-api/logback-classic pair: log4j-api and slf4j-api are APIs and they can be present at the same time, while log4j-core and logback-classic are their reference implementations and you want to replace one of them with a bridge to the other API,
    • to check if you don't have multiple Log4j API implementations on your classpath, set -Dlog4j2.debug=true and look at the standard error of the application,
    • to check if you don't have multiple SLF4J implementations, check the standard error.