前言:
日誌文件是用於記錄系統操作事件的記錄文件或者是文件集合,可以分爲事件日誌和消息日誌。具有處理歷史數據、診斷問題的追蹤以及理解系統的活動等重要作用。日誌框架就是更好的記錄日誌時使用的,記錄日誌是爲了我們在工作中更好的查找相應的問題,也算是對我們操作的留痕吧。剛剛開始學習Java的時候我們都是使用System.out.prinfln()的方式在控制檯進行打印的,而且這樣的方式伴隨了我們很長的一段時間,後來使用debug打斷點的方式進行調試,但是不論是哪一種方式,也不論這樣的日誌是否有用,都應該去記錄。
一、日誌框架
市面上有許多的日誌框架,比如 JUL( java.util.logging), JCL( Apache Commons Logging), Log4j, Log4j2, Logback、 SLF4j、 jboss-logging等等。
Spring Boot 2.x默認採用了slf4j+logback的形式 ,slf4j是個通用的日誌門面,logback就是個具體的日誌框架了,我們記錄日誌的時候採用slf4j的方法去記錄日誌,底層的實現就是根據引用的不同日誌jar去判定了。所以Spring Boot也能自動適配JCL、JUL、Log4J等日誌框架,它的內部邏輯就是通過特定的JAR包去適配各個不同的日誌框架。
二、Logback的使用
Spring Boot 2.x默認採用了slf4j+logback的形式,我們就對Logback進行簡單學習,在application.properties文件中進行相關的配置:
如果我們僅僅在application.properties文件中進行相關的配置,實際上是不能滿足我們在項目中的實際要求的,所以我們可以使用logback自帶的日誌配置文件,在Resource目錄下創建一個logback.xml(也可命名爲logback-spring.xml )文件:
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!--定義日誌保存的路徑-->
<!--
1.更改默認的logback.xml爲logback-spring.xml,SpringBoot當看到logback-spring.xml文件存在的時候,纔會啓動日誌的環境切換,logback.xml文件沒法做到
2. 在需要切換的環境上增加springProfile標籤
-->
<springProfile name="dev">
<property name="LOG_HOME" value="d:/logs/dev/" />
</springProfile>
<springProfile name="prd">
<property name="LOG_HOME" value="d:/logs/prd/" />
</springProfile>
<!--定義一個控制檯輸出器,名爲console-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<!--按pattern指定的格式輸出日誌,編碼爲UTF-8-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{30} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--定義一個日滾動(每天生成一份)的日誌文件-->
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--按pattern指定的格式輸出日誌,編碼爲UTF-8-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{30} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 定義保存的文件名 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--%d{yyyy-MM-dd}代表每天生成一個新的日誌-->
<fileNamePattern>${LOG_HOME}/mysprintboot_%d{yyyy-MM-dd}.log.zip</fileNamePattern>
<!--日誌最多保存90天,也就是90份-->
<maxHistory>90</maxHistory>
<!--總大小-->
<totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>
<!-- 級別過濾:在日滾動文件中,強制只保存錯誤級別以上信息 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 定義日誌全局最低輸出級別是INFO,同時向控制檯和日滾動文件輸出 -->
<root level="INFO">
<appender-ref ref="console" />
<appender-ref ref="file" />
</root>
<loger name="com.setalone.myspringboot.MyspringbootApplicationTests"/>
</configuration>
1、根節點<cofiguration>
- scan:當此屬性設置爲true時,配置文件如果發生改變,將會被重新加載,默認值爲true
- scanPeriod:設置監測配置文件是否有修改的時間間隔,如果沒有給出時間單位,默認單位是毫秒。當scan爲true時,此屬性生效。默認的時間間隔爲1分鐘
- debug:當此屬性設置爲true時,將打印出logback內部日誌信息,實時查看logback運行狀態。默認值爲false
2、設置變量<property>
- 用來定義變量值的標籤, 有兩個屬性,name和value;其中name的值是變量的名稱,value的值時變量定義的值。通過定義的值會被插入到logger上下文中。定義變量後,可以使“${}”來使用變量
3、子節點<appender>
- appender用來格式化日誌輸出節點,有倆個屬性name和class,class用來指定哪種輸出策略,常用就是控制檯輸出策略和文件輸出策略
4、<filter>
- filter是一個過濾器,表示對輸出到控制檯的日記進行過濾。有兩種過濾器,分別爲LevelFilter 和ThresholdFilter。執行一個過濾器會有返回個枚舉值,即DENY,NEUTRAL,ACCEPT其中之一。返回DENY,日誌將立即被拋棄不再經過其他過濾器;返回NEUTRAL,有序列表裏的下個過濾器接着處理日誌;返回ACCEPT,日誌會被立即處理,不再經過剩餘過濾器。
- 其中LevelFilter 爲級別過濾器,根據日誌級別進行過濾。其下有三個子節點,level表示過濾的級別,用於配置符合過濾條件的操作,ACCEPT符合級別的輸出到控制檯,用於配置不符合過濾條件的操作,DENY不符合的拒絕輸出到控制檯。
- ThresholdFilter爲臨界值過濾器,過濾掉低於指定臨界值的日誌。當日志級別等於或高於臨界值時,過濾器返回NEUTRAL;當日志級別低於臨界值時,日誌會被拒絕。
5、對日誌進行格式化
- %d{HH:mm:ss.SSS} :日誌的輸出時間
- %contextName : 上下文名稱
- %thread : 輸出日誌的進程名字,這在Web應用以及異步任務處理中很有用
- %-5level : 日誌級別,並且使用5個字符靠左對齊
- %logger{30} : 日誌輸出者的名字(一般爲類名),名字最長30個字符,否則按照句點分割
- %msg : 具體的日誌消息
- %n :換行符
6、字節點root
- root節點是必選節點,用來指定最基礎的日誌輸出級別,只有一個level屬性,默認是DEBUG
- 其中可以包含零個或多個元素,表示我們定義的appender將會添加到我們定義的loger子節點中
7、字節點logger
- <loger>用來設置某一個包或者具體的某一個類的日誌打印級別、以及指定<appender>
- <loger>僅有一個name屬性,一個可選的level和一個可選的addtivity屬性
name:用來指定受此loger約束的某一個包或者具體的某一個類。
level:用來設置打印級別,如果未設置此屬性,那麼當前loger將會繼承上級的級別。
addtivity:是否向上級loger傳遞打印信息。默認是true。
3、<loger> 的實際使用有兩種情況
三、Log4j2的使用
Spring Boot雖然默認使用Logback日誌框架,但其內部也集成了Log4j2框架。要知道的是,在Java中,Log4j2框架的性能是最強的,所以我們一般在程序中使用Log4j2框架。下面介紹一下Log4j2的使用及其內部屬性的含義。如果我們要使用Log4j2,還是要先去除logbcak的包,引入Log4j2的包。
引包結束之後,創建一個log4j2.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<!--日誌級別以及優先級排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration後面的status,這個用於設置log4j2自身內部的信息輸出,可以不設置,當設置成trace時,你會看到log4j2內部各種詳細輸出-->
<!--monitorInterval:Log4j能夠自動檢測修改配置 文件和重新配置本身,設置間隔秒數-->
<configuration status="WARN" monitorInterval="30">
<Properties>
<Property name="log.path">log</Property>
</Properties>
<!--先定義所有的appender-->
<appenders>
<!--這個輸出控制檯的配置-->
<console name="Console" target="SYSTEM_OUT">
<!--輸出日誌的格式-->
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
</console>
<File name="log" fileName="${log.path}/test.log" append="false">
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
</File>
<RollingFile name="RollingFileInfo" fileName="${log.path}/info.log"
filePattern="${log.path}/logs/${date:yyyy-MM}/info-%d{yyyy-MM-dd}.log.zip">
<!--只輸出level及以上級別的信息(onMatch),其他的直接拒絕(onMismatch)-->
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
<Policies>
<TimeBasedTriggeringPolicy modulate="true" interval="1"/>
</Policies>
</RollingFile>
</appenders>
<!--然後定義logger,只有定義了logger並引入appender,appender纔會生效-->
<loggers>
<!--過濾掉spring和mybatis的一些無用的DEBUG信息-->
<logger name="org.springframework" level="INFO"/>
<logger name="org.mybatis" level="INFO"/>
<logger name="com.baiding" level="INFO"/>
<root level="info">
<appender-ref ref="Console"/>
<appender-ref ref="RollingFileInfo"/>
</root>
</loggers>
</configuration>
1、 根節點屬性
- 根節點Configuration有兩個屬性,status和monitorinterval
- status : status用來指定log4j2本身的日誌的級別
- monitorinterval : monitorinterval用於指定log4j自動重新配置的監測間隔時間,單位是s,最小是5s
2、 Properties 標籤
- 在xml文件中,可以使用Properties 標籤來自定義變量,方便其他地方的引用。
3、Appenders 節點
和logback一樣,Appender是用來定義日誌輸出點的,一般常用有三個子節點,分別爲Console、RollingFile、File。
Console節點用來定義輸出到控制檯的Appender:
- name : 指定Appender的名字,用於Logger節點引用
- target : SYSTEM_OUT 或 SYSTEM_ERR,一般設置爲:SYSTEM_OUT
- PatternLayout : 指定日誌輸出格式,默認爲%m%n
File節點用來定義輸出到指定位置的文件的Appender:
- name : 指定Appender的名字,用於Logger節點引用
- fileName : 指定輸出日誌的目的文件帶全路徑的文件名
- append : 是否追加,默認爲ture。ture是將新日誌追加到原日誌文件尾部,false則是刪除已有文件,重建新文件
- PatternLayout : 指定日誌輸出格式,默認爲%m%n
RollingFile節點用來定義輸出到指定位置的文件的Appender,但其記錄的內容可拆分:
- File對文件的約束很簡單,而RollingFile則比較靈活,其可根據文件大小來分拆,還可以根據時間來分拆
- name : 指定Appender的名字,用於Logger節點引用
- fileName : 指定輸出日誌的目的文件帶全路徑的文件名
- filePattern:指定拆分出去的日誌文件的全路徑的文件名以及格式
- PatternLayout : 指定日誌輸出格式,默認爲%m%n
- Policies : 指定滾動日誌的策略,就是什麼時候進行新建日誌文件輸出日誌.
- TimeBasedTriggeringPolicy : 基於時間進行日誌的滾動
- SizeBasedTriggeringPolicy : 基於文件大小進行日誌的滾動
- ThresholdFilter : 日誌過濾器
這裏說一下TimeBasedTriggeringPolicy這個滾動策略的屬性interval,它是指日誌進行滾動的間隔,那麼它的單位具體是什麼呢?關鍵點在於filePattern的日誌文件名所含有的日期格式%d{yyyy-MM-dd},這裏日期格式具體到了天,那麼以天爲單位,若是日期具體到%d{yyyy-MM-dd-HH-mm}分鐘的話,那麼就是以分鐘爲單位。
這裏還提到了日誌過濾器,Log4j提供了許多的日誌過濾器,具體可以看下文檔 Filters。但我們一般採用ThresholdFilter,這個過濾器一般用來過濾掉所有級別低於它定義的級別的日誌。
4、Loggers節點
Loggers節點下一般有root和logger節點:root節點用來指定項目的根日誌,如果沒有單獨指定logger,那麼就會默認使用該root日誌輸出。
- level :日誌輸出級別,共有8個級別,按照從低到高爲:All < Trace < Debug < Info < Warn < Error < Fatal < OFF.
- appender-ref :root的子節點,用來指定該日誌輸出到哪個Appender
Logger節點用來單獨指定日誌的形式,比如要爲某個包下所有的class或者某個具體的class指定不同的日誌級別等。
- level : 日誌輸出級別
- name : 用來指定該Logger所適用的類或者包.
- AppenderRef :Logger的子節點,用來指定該日誌輸出到哪個Appender,如果沒有指定,就會默認繼承自Root
- additivity :是否向上級傳遞日誌 true(默認)或false
若我們爲logger指定了AppenderRef ,別忘了將logger的additivity 屬性設置爲false,要不然日誌可能會在指定的Appender中輸出兩遍
四、Log4j2異步輸出日誌
Log4j2有個突出的功能就是支持高效低延遲的異步化寫日誌。日誌異步輸出的好處在於,使用單獨的進程來執行日誌打印的功能,可以提高日誌執行效率,減少日誌功能對正常業務的影響。
日誌的異步輸出使用了disruptor這個開源的併發框架,所以首先得導入disruptor.jar包
異步輸出分爲兩種情況,一種爲全異步模式,一種爲異步和非異步混合輸出模式。通過官方的性能對比,一般線程數在2-16之間的話,混合使用同步和異步的logger來打印日誌,性能是最好的。
異步和非異步混合模式
這種模式的啓用,主要在於兩個節點的使用,分別爲AsyncRoot和AsyncLogger,這兩個節點可以和Root 或 Logger節點混合使用。在這裏修改一下上述的log4j2.xml文件中Loggers節點就可以了。
<loggers>
<AsyncRoot level="info">
<appender-ref ref="Console"/>
<appender-ref ref="RollingFileInfo"/>
</AsyncRoot>
<AsyncLogger name="com.baiding" level="INFO" />
<AsyncLogger name="org.mybatis" level="INFO" />
<AsyncLogger name="org.springframework" level="INFO" />
</loggers>