背景:日常開發使用的是spring-boot框架,日誌配置方式基本都是各個倉庫相互copy的配置,究其爲何如此配置不知原因,大多數都是嘗試操作。
問題list:
日誌整體理解很難,闡述一下要求證的問題,明確一下學習的邊界。
1.spring-boot-starter-logging裏使用的是什麼日誌,是如何生效的。
2.spring-boot 項目裏如何配置logging
3.常見的日誌框架或者api之間的關係:spring-boot-starter-logging, java.util.logging, slf4j, org.apache.commons.logging,logback, log4j,log4j2,slf4j2
4.lombok裏的和日誌相關的註解代表什麼?和對應的日誌框架是如何配置使用的。
5.以其中一個log框架爲例,梳理其和spring-boot 和lombok的組合使用方式.
學習過程:
1. spring-boot-starter-logging.jar 基本解釋
我們發現spring-boot-starter-logging.jar裏只有 META-INF/MANIFEST.MF
Manifest-Version: 1.0
Implementation-Title: Spring Boot Logging Starter
Automatic-Module-Name: spring.boot.starter.logging
Implementation-Version: 2.1.3.RELEASE
Built-By: Spring
Created-By: Apache Maven 3.6.0
Build-Jdk: 1.8.0_202
以及對應的pom依賴:
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.11.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.7.25</version>
<scope>compile</scope>
</dependency>
</dependencies>
關於spring-boot-starter-*格式:https://juejin.im/post/5d9f41eae51d4578034d2db2
針對於spring-boot-starter-logging 總結起來就是:
(1)pom 文件裏引入了相關依賴(具體的第三方實現);
(2) MANIFEST.MF Automatic-Module-Name 指定了logging入口相關的在 spring-boot-autoconfigure.jar包org.springframework.boot.autoconfigure下對應的目錄(logging)
(3) spring-boot-autoconfigure/META-INF/spring.factories中聲明瞭logging starter的入口類
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
2.spring-boot-logging-starter 代碼分析
類:org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
LogFactory,LogAdapter都是spring-jcl裏內容
public class ConditionEvaluationReportLoggingListener implements ApplicationContextInitializer<ConfigurableApplicationContext> {
private final Log logger = LogFactory.getLog(getClass());
/** */
}
public abstract class LogFactory {
/** */
public static Log getLog(Class<?> clazz) {
return getLog(clazz.getName());
}
/** */
public static Log getLog(String name) {
return LogAdapter.createLog(name);
}
/***/
}
final class LogAdapter {
private static final String LOG4J_SPI = "org.apache.logging.log4j.spi.ExtendedLogger";
private static final String LOG4J_SLF4J_PROVIDER = "org.apache.logging.slf4j.SLF4JProvider";
private static final String SLF4J_SPI = "org.slf4j.spi.LocationAwareLogger";
private static final String SLF4J_API = "org.slf4j.Logger";
private static final LogApi logApi;
static {
if (isPresent(LOG4J_SPI)) {
if (isPresent(LOG4J_SLF4J_PROVIDER) && isPresent(SLF4J_SPI)) {
// log4j-to-slf4j bridge -> we'll rather go with the SLF4J SPI;
// however, we still prefer Log4j over the plain SLF4J API since
// the latter does not have location awareness support.
logApi = LogApi.SLF4J_LAL;
}
else {
// Use Log4j 2.x directly, including location awareness support
logApi = LogApi.LOG4J;
}
}
else if (isPresent(SLF4J_SPI)) {
// Full SLF4J SPI including location awareness support
logApi = LogApi.SLF4J_LAL;
}
else if (isPresent(SLF4J_API)) {
// Minimal SLF4J API without location awareness support
logApi = LogApi.SLF4J;
}
else {
// java.util.logging as default
logApi = LogApi.JUL;
}
}
public static Log createLog(String name) {
switch (logApi) {
case LOG4J:
return Log4jAdapter.createLog(name);
case SLF4J_LAL:
return Slf4jAdapter.createLocationAwareLog(name);
case SLF4J:
return Slf4jAdapter.createLog(name);
default:
return JavaUtilAdapter.createLog(name);
}
}
/**/
}
到這一步基本搞懂了spring-boot-starter-logging是怎麼處理日誌的?
1. 日誌的入口在autoconfigure
2.autoconfigure 裏和日誌相關的依賴
3.spring-jcl自己包了一層,支持slf4j 系列 ,log4j 系列,java原生日誌記錄
4.spring-boot-starter-logging 日誌引入了相關的日誌實現。
http://www.slf4j.org/images/legacy.png
這個圖沒理解,待看