常見的框架日志有:log4j,log4j2,logback,common-logging(JCL),java-util-logging(JUL)和slf4j等。
而日志框架主要分兩類:
- 日志門面(抽象)如:jboss-logging,slf4j,JCL
- 日志實現(實現)如:log4j,log4j2,logback,JUL
對於日志實現,JUL實現簡陋,很多地方被開發者吐槽,所以排除;log4j和logback是同一個作者開發的,且logback是log4j的升級版,比log4j會更好點,排除log4j;log4j2不是log4j的升級版,因為太過於優秀,部分框架對其的支持有限,所以排除。
所以日志實現選中logback。
對於日志門面,jboss-logging很久未更新,而slf4j的作者就是log4j和logback的作者,所以選用slf4j和logback會比較合得來....
所以日志門面選用slf4j。並且在springboot中也是使用的 slf4j + logback。
簡單使用
首先導入slf4j的jar包和logback的jar包
在開發的時候,日志記錄方法的調用不應該直接調用日志的實現類,而是調用日志抽象層里面的方法。
參考官方文檔:https://www.slf4j.org/manual.html
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorld {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger(HelloWorld.class);
logger.info("Hello World");
}
}
如何讓系統中的所有的日志都統一到slf4j
在系統中,自己使用了slf4j+logback,但是Spring默認的是commons-logging;如果集成Hibernate,他又自帶了jboss-logging;如果集成mybatis,他又有自己的日志系統。
想統一日志框架,都使用slf4j輸出日志,可以參考slf4j官網 https://www.slf4j.org/legacy.html
slf4j提供了解決方案:
-
將系統中的其他日志框架排除出去(刪除其他日志框架的jar包,如:commons-logging日志的jar包等);
-
然后使用中間包來替代原有的日志框架(如上圖的jcl-over-slf4j.jar replaces commons-logging.jar,log4j-over-slf4j.jar replaces log4j.jar等);
-
導入slf4j其他日志包的實現;
那些中間包實際上提供了原有包的功能,但是也對slf4j進行了實現。就像log4j-to-slf4j.jar下面的路徑還是和log4j一樣,但是里面的日志記錄的功能使用的是slf4j:
Spring Boot的日志關系
新建一個springboot項目,然后打開pom文件,查看依賴(右鍵>Diagrams>Show...)
看到SpringBoot依賴spring-boot-starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.1.7.RELEASE</version>
<scope>compile</scope>
</dependency>
而spring-boot-starter依賴spring-boot-starter-logging,所以springboot使用它來做日志功能。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<version>2.1.7.RELEASE</version>
<scope>compile</scope>
</dependency>
看一下spring-boot-starter-logging:
所以springboot底層是使用slf4j+logback的方式進行日志記錄的,並把其他日志替換成了slf4j;
使用和配置
- 修改日志級別
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBoot03LoggingApplicationTests {
Logger logger = LoggerFactory.getLogger(SpringBoot03LoggingApplicationTests.class);
@Test
public void contextLoads() {
//日記級別:
//從低到高:trace<debug<info<warn<error
//可以調整輸出的日志級別;日志就只在這個級別和之后的高級別生效
logger.trace("這是trace日志");
logger.debug("這是debug日志"); //調試日志
//springboot默認的日志級別是info,所以運行時只會打印info級別和高於info級別的日志信息
logger.info("這是info日志"); //
logger.warn("這是warn日志"); //警告日志
logger.error("這是error日志"); //錯誤日志
}
}
所以打印是:
但是可以通過properties等配置文件修改日志級別:
logging.level.com.wangd = trace
修改指定位置文件的日志級別后打印如下:
-
生成日志文件
指定logging.file
logging.level.com.wangd = trace
# 不指定路徑和文件的情況下,只在控制台打印日志信息
# 若指定了logging.file,而無論是否指定logging.path,都只在指定文件中保存日志信息,而不會在路徑中保存日志
# 對於logging.path,若指定了目錄,則會在這個目錄中自動生成spring.log保存日志信息
#logging.path=/spring/log
logging.file=spring.log
指定logging.path=/spring/log
logging.level.com.wangd = trace
# 不指定路徑和文件的情況下,只在控制台打印日志信息
# 若指定了logging.file,而無論是否指定logging.path,都只在指定文件中保存日志信息,而不會在路徑中保存日志
# 對於logging.path,若指定了目錄,則會在當前磁盤的這個目錄中自動生成spring.log保存日志信息
logging.path=/spring/log
#logging.file=spring.log
-
修改日志輸出格式
# 日志輸出格式: # %d:日期時間 # %thread:線程名 # %-5level:級別從左顯示5個字符寬度 # %logger{50}:表示logger名字最長50個字符,否則按照句點切割 # %msg:日志消息 # %n:換行符 # 在控制台輸出日志的格式 logging.pattern.console=%d{yyyy-MM-dd} [%thread] %-2level %logger{5} - %msg%n # 在日志文件中輸出日志的格式 logging.pattern.file=%d{yyyy-MM-dd} === [%thread] %-5level %logger{50} - %msg%n
-
使用@Slf4j注解
在使用類名的時候,每個類都需要自己編寫
Logger mLogger = LoggerFactory.getLogger(XXX.class);
會很不方便,所以可以通過一個注解(@Slf4j)來幫我們實現,該注解就可以幫我們自動創建一個 log對象。
但是 如果使用 @Slf4j 注解 需要兩點,
-
安裝lombok插件,參考idea安裝插件
-
添加 lombok的依賴
<!--添加lombok依賴--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>
就可以使用@Slf4j注解了。
@RunWith(SpringRunner.class) @SpringBootTest @Slf4j public class SpringBoot03LoggingApplicationTests { @Test public void contextLoads() { log.info("這是info日志"); // log.warn("這是warn日志"); //警告日志 log.error("這是error日志"); //錯誤日志 } }
-
-
指定日志配置文件
-
logback.xml可以被日志框架直接識別;
-
logback-spring.xml無法被日志框架識別,但是可以由springboot識別,可以使用springboot的高級Profile功能。
<!-- 如在logback-spring.xml中加入--> <springProfile name="dev"> <!-- 可以指定某段配置只在某個環境下生效--> <pattern>%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX} %level [%thread] [%logger{100}.%method:%line] - %msg%n</pattern> </springProfile>, <!--然后修改properties配置文件的profile為dev--> spring.profiles.active=dev 就可以在啟動環境為dev時,日志打印的格式為對應配置的格式
所以logback[-spring].xml,格式需要自己查詢。
另外logback.xml文件中配置了springProfile的話,運行會報錯。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
<springProfile name="dev">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d -- %msg%n</pattern>
</layout>
</springProfile>
<springProfile name="test">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d -----== %msg%n</pattern>
</layout>
</springProfile>
</appender>
<appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--要攔截的日志級別-->
<level>ERROR</level>
<!--如果匹配,則禁止-->
<onMatch>DENY</onMatch>
<!--如果不匹配,則允許記錄-->
<onMismatch>ACCEPT</onMismatch>
</filter>
<encoder>
<pattern>%d -- %msg%n</pattern>
</encoder>
<!--滾動策略-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--路徑-->
<fileNamePattern>d:/info-%d.log</fileNamePattern>
</rollingPolicy>
</appender>
<appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--添加 范圍 過濾-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<encoder>
<pattern>%d -- %msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>d:/error-%d.log</fileNamePattern>
</rollingPolicy>
</appender>
<root level="info">
<appender-ref ref="consoleLog" />
<appender-ref ref="fileInfoLog"/>
<appender-ref ref="fileErrorLog"/>
</root>
</configuration>