使用 SLF4J 想同时写控制台和文件,通常需要的是一个日志后端配置多个 Appender,不是同时绑定 Logback 和 Log4j2。门面、实现和输出目的地是三层不同概念。

Binding 与 Provider 要按代际看

SLF4J 是日志 API,后端负责实际输出。1.x 常见静态 Binder 机制;2.x 使用 ServiceLoader 发现 Provider。针对 1.7 的绑定不能直接当作 2.x Provider。

多实现提示会列出候选来源,并可能选定其中一个;不能一概说成“JVM 不允许同名类,所以一定抛异常”。选中哪一个不应依赖偶然的类路径顺序。SLF4J 错误和警告说明

排查先看 slf4j-api、后端及桥接适配器的实际版本。Log4j 接入中,log4j-slf4j-impl 面向旧代 API,log4j-slf4j2-impl 面向 SLF4J 2;不要只看名字里都含 slf4j 就互换。Log4j API、实现与桥接

一个 Logback 后端,两个输出

以下 logback.xml 展示控制台与文件输出;前提是应用已经选定兼容的 Logback 依赖,而不是再引入另一套 SLF4J 后端:

<configuration>
  <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%d{HH:mm:ss} %-5level %logger - %msg%n</pattern>
    </encoder>
  </appender>
  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>logs/example.log</file>
    <append>true</append>
    <encoder>
      <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger - %msg%n</pattern>
    </encoder>
  </appender>
  <root level="INFO">
    <appender-ref ref="CONSOLE"/>
    <appender-ref ref="FILE"/>
  </root>
</configuration>

相对路径取决于进程工作目录,文件输出需有写权限。长期运行还应配置滚动、保留时间和容量限制,不能让示例文件无限增长。Appender 负责输出,Encoder 或 Layout 决定格式。Logback Appender

Profile 是构建选择,不是运行中切换

Maven 的 -P 可以选择构建时依赖,但这不等于进程运行中热切换日志框架。多个 Profile 还可能同时激活,仍需确认最终打包结果,而不是只检查某一段 pom。

可先查看只读依赖树,再根据实际来源排除重复后端:

mvn dependency:tree -Dincludes=org.slf4j:*,ch.qos.logback:*,org.apache.logging.log4j:*

删包应依据依赖角色,不是看到多个日志相关 JAR 就全部当作冲突实现。

桥接还要检查方向

log4j-over-slf4j 把旧 Log4j 调用导向 SLF4J;jul-to-slf4j 面向 JUL,还需要相应安装步骤。它们不是“第二个日志后端”。

尤其不能同时装上互相反向的桥接,例如把 Log4j API 导向 SLF4J,又把 SLF4J 导回 Log4j,形成循环。先画清调用最终落到哪个实现,再决定所需桥接与配置。