[Proposal / RFC] Bridging SLF4J 2.x from `javaSettings.maven` into Lucee's Log4j 2 engine

(note I got Antigravity/Gemini Flash 3.8 to help me write this up)

Context
Lucee 6/7’s native Maven dependency integration in Application.cfc (javaSettings.maven) and mavenLoad() is a fantastic capability that makes bringing modern Java libraries into CFML seamless.

In modern Java development, virtually every major library (AWS SDK v2, WebAuthn, Stripe, Nimbus OIDC, Apache HttpClient 5) logs through the SLF4J 2.x facade.


The Problem Today

When an application loads any Java dependency using SLF4J:

  1. Startup Warning: Because Lucee’s dynamic Maven classloader does not provide an SLF4J provider, SLF4J emits this warning to stderr on first use:
    SLF4J(W): No SLF4J providers were found.
    SLF4J(W): Defaulting to no-operation (NOP) logger implementation
    SLF4J(W): See https://www.slf4j.org/codes.html#noProviders for further details.
    
  2. Lost Diagnostics: Once SLF4J defaults to NOP, all subsequent log messages (including warnings and critical errors) from that library are permanently discarded. They never surface in Lucee’s application.log, console, or <cflog>.
  3. Manual Workaround: To suppress the warning or control logging today, developers have to manually hunt down and add an SLF4J provider (e.g. "org.slf4j:slf4j-nop:2.0.17") to their javaSettings.maven.

Existing Precedents in Lucee

Lucee has already encountered and solved this exact classloader/facade problem for older logging frameworks:

  • Apache commons-logging (LDEV-5688): Lucee implemented LuceeLoaderLogFactory in the loader to intercept commons-logging calls from Maven JARs and route them into Lucee’s logging subsystem.
  • Hibernate / JBoss Logging (LDEV-6159): Lucee created LuceeJBossLoggerProvider so Hibernate logs pipe directly into Lucee’s native orm.log.
  • Quartz Extension (LDEV-6662): Gian noted in the plan: “Quartz’s SLF4J output should not go to an unconfigured log4j; route it through Lucee logging, or at least to a silent no-op binding”.

SLF4J 2.x is currently the missing bridge in the trio.


Proposed Solution

Since Lucee core already runs natively on Log4j 2 (Log4j2Engine):

  1. Provide an SLF4J 2.x Provider:
    Apache already maintains the official bridge: org.apache.logging.log4j:log4j-slf4j2-impl. If Lucee provides this bridge (or a lightweight custom SLF4JServiceProvider) on the parent classloader for javaSettings:
    • All logger.info(), warn(), and error() calls from Maven libraries automatically flow into Lucee’s Log4j 2 system (e.g. into application.log or a dedicated java.log).
    • Clean, zero-warning boot on modern JVMs.
  2. Application Control:
    Could Lucee allow configuring third-party Java log levels or targets via Application.cfc (similar to how ormSettings configures Hibernate logging)?

Curious to hear the core team’s thoughts on bridging SLF4J 2.x into Lucee core as the natural next step for javaSettings.maven.

Thanks @philsw, this is a well put together proposal, and the NOP fallback silently swallowing errors from Maven-loaded libraries is a real problem. A quick correction on the precedents: LDEV-5688 (the commons-logging LogFactory in the loader) is still open, so commons-logging isn’t bridged yet either. ORM logging (LDEV-6159) is the one that already goes through Lucee logging. I’ll discuss with the team how we want to handle SLF4J 2.x for javaSettings.maven, keeping in mind that logging is moving into an extension for Lucee 9, and I’ll come back here with a ticket once we’ve settled on the approach.

Quick update: the SLF4J 2.x bridge is now merged into 8.0 as LDEV-6664. SLF4J output from libraries loaded via javaSettings/Maven goes to the application log (configurable via lucee.slf4j.log / LUCEE_SLF4J_LOG, disable with -Dlucee.slf4j.bridge=false). It will be in the next 8.0 snapshot.

1 Like