用Java统一Logger到SLF4J + Logback的聪明方法/ build.gradle的编写方式/ 2021年
本文是为了那些想要使用SLF4J的人而写的。
-
- log4j 2.x を使っていない事を確かにしたい (2021年12月追記)
-
- SLF4J に統一したはずなのに、たまにコンソールに謎ログが出てる。時刻が出ないとかある(実は log4j 1.x 経由でログがでてる)
あるいは log4j:WARN No appenders could be found for logger (com.example.Log4j1).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info. みたいなログが出る。
Class path contains multiple SLF4J bindings. SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation. なるログが出る
ERROR StatusLogger Log4j2 could not find a logging implementation. Please add log4j-core to the classpath. Using SimpleLogger to log to the console… なるログができる
gradle/maven で exclude すると除外できるのは知ってるけど、新規ライブラリを追加したタイミングで log4j の実装が混入してログがでなくなったりしている
まとめて log4j や commons-logging を取り除きたい
更新
- Spring Boot 2.0 でだいぶ世界観が変わったので書き直しました
提示
关于除外的问题
可以使用以下语法一次性排除:
可以使用下面的句式一起排除。
configurations.all {
exclude
}
依存版本统一
3.2. 单独使用Spring Boot的依赖管理非常方便。
即使没有使用Spring Boot,使用Gradle Plugin并将其视为好方法似乎是明智的。
plugins {
id("org.springframework.boot") version "2.6.5" apply false
}
apply {
plugin("io.spring.dependency-management")
}
dependencyManagement {
imports {
mavenBom(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)
}
}
用这个,你就不需要在实际使用时单独写版本号了。
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
}
当类路径中含有多个SLF4J绑定时会报错”Class path contains multiple SLF4J bindings.”
似乎是 IntelliJ 的一个问题,当在依赖库中使用 SLF4J 并在运行时引入另一个版本的库时,通过 IntelliJ 内部进行调试/运行时,会出现两个 Jar 都被包含在 Classpath 中的问题。
基本上,只要进行依赖管理就可以了。
太长不看
第一种模式
在所有项目中,只需加入所需的各种日志库 > SLF4J 的模块,并排除各种日志库的实现即可。
buildscript {
repositories {
maven {
url("https://plugins.gradle.org/m2/")
}
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:2.6.5")
}
}
subprojects {
apply {
plugin("org.gradle.java")
plugin("io.spring.dependency-management")
}
repositories {
mavenCentral()
}
dependencyManagement {
imports {
mavenBom(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES) {
extra["log4j2.version"] = "2.15.0"
// Force update log4j2 from latest spring-boot preferred version.
// It's not required to avoid CVE-2021-44228 because we don't use log4j2,
// but seeing log4j-api < 2.15.0 is confusing.
}
}
}
dependencies {
// Used compile/coding time.
implementation("org.springframework.boot:spring-boot-starter-logging") // 実際は starter-web の依存とかに入ってることが多い
// Used Runtime
runtimeOnly("org.slf4j:log4j-over-slf4j")
// log4j 1.x だけ個別にルーティングする必要がある
// 2015 年に EOL のため 2017 年に spring-boot-starter-logging からも取り除かれている
// https://github.com/spring-projects/spring-boot/issues/11148
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
configurations.all {
// We are using logback for logging implementation (formatting & appenders).
// Other logging implementation and "from slf4j bridge" are not necessary.
// Let's remove those.
exclude(group = "log4j") // = Old Log4j (1.x) implementation. Replaced by log4j-over-slf4j.
exclude(module = "slf4j-log4j12") // = SLF4J -> Log4J Implementation by SLF4J. Not used (or cyclic dependences lol).
exclude(module = "slf4j-jdk14") // = SLF4J -> JDK14 Binding. Not used.
exclude(module = "slf4j-jcl") // = SLF4J -> Commons Logging. Not used.
exclude(module = "commons-logging") // Because bridged by org.slf4j:jcl-over-slf4j.
exclude(module = "commons-logging-api") // Replaced by org.slf4j:jcl-over-slf4j.
exclude(group = "org.apache.logging.log4j", module = "log4j-core") // Remove log4j 2.x implementation. org.apache.logging.log4j:log4j-to-slf4j (Included in spring-boot-starter-logging) proxies log4j-api:2.x to slf4j.
}
}
模式 2
建议创建一个专门的日志项目,其中包括日志设置等内容。
待会再写