作為Java開發人員,對于日志記錄架構一定非常熟悉。而且幾乎在所有應用裡面,一定會用到各種各樣的日志架構用來記錄程式的運作資訊。而對于一個成熟的Java應用,這個是必不可少的。在開發和調試階段,日志可以幫助我們更快的定位問題;而在應用的運維過程中,日志系統又可以幫助我們記錄大部分的異常資訊,通常很多企業會通過收集日志資訊來對系統的運作狀态進行實時監控預警。
總體概覽
image.png
目前的日志架構有JDK自帶的
logging
,
log4j1
、
log4j2
logback
,這些架構都自己定制了日志 API ,并且有相應的實作;目前用于實作日志統一的架構
Apache commons-logging
slf4j
,遵循面向接口程式設計的原則,這兩大架構可以讓使用者在程式運作期間去選擇具體的日志實作系統(
log4j1\log4j2\logback
等)來記錄日志,是統一抽象出來的一些接口。
日志級别
log4j
定義了8個級别的log(除去OFF和ALL,可以說分為6個級别),
優先級從高到低依次為:OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE、 ALL。
ALL
最低等級的,用于打開所有日志記錄。
TRACE
很低的日志級别,一般不會使用。
DEBUG
指出細粒度資訊事件對調試應用程式是非常有幫助的,主要用于開發過程中列印一些運作資訊。
INFO
消息在粗粒度級别上突出強調應用程式的運作過程。這個可以用于生産環境中輸出程式運作的一些重要資訊。
WARN
表明會出現潛在錯誤的情形,有些資訊不是錯誤資訊,但是也要給開發者的一些提示。
ERROR
指出發生錯誤的資訊,可能會導緻系統出錯或是當機等,必須要避免
FATAL
指出每個嚴重的錯誤事件将會導緻應用程式的退出。這個級别比較高了。重大錯誤,這種級别你可以直接停止程式了。
OFF
最高等級,用于關閉所有日志記錄。
Log4j
官網位址:
https://logging.apache.org/log4j/1.2/簡介:
Apache 的一個開放源代碼項目,通過使用Log4j,我們可以控制日志資訊輸送的目的地是控制台、檔案、GUI元件、甚至是套接口伺服器、NT的事件記錄器、UNIX Syslog守護程序等;使用者也可以控制每一條日志的輸出格式;通過定義每一條日志資訊的級别,使用者能夠更加細緻地控制日志的生成過程。這些可以通過一個 配置檔案來靈活地進行配置,而不需要修改程式代碼。
在JDK 1.3及以前,Java打日志依賴
System.out.println()
,
System.err.println()
或者
e.printStackTrace()
,Debug日志被寫到
STDOUT
流,錯誤日志被寫到
STDERR
流。這樣打日志有一個非常大的缺陷,即無法定制化,且日志粒度不夠細。log4j是在這樣的環境下誕生的,它是一個裡程碑式的架構,它定義的
Logger
Appender
Level
等概念如今已經被廣泛使用。
在
https://mvnrepository.com/中可以查到,log4j1從2005年11月更新到2012年3月,後面就沒再更新了
最新的依賴(May 26, 2012)
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2015年8月5日,項目管理委員會宣布
Log4j 1.x
已達到使用壽命。建議使用者使用
Log4j 1
更新到
Apache Log4j 2
Log4j2
官網位址:
https://logging.apache.org/log4j/2.x/Log4j2
是
Log4j1
的更新版本。
Log4j2
基本上把
Log4j1
版本的核心全部重構掉了,而且基于
Log4j1
做了很多優化和改變。并提供了
Logback
中可用的許多改進,同時修複了
Logback
架構中的一些固有問題。
Log4j2最新的依賴(Mar 11, 2018)
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.0</version>
</dependency>
SpringBoot也有Log4j2相關的依賴
不過
SpringBoot
自帶的
jar
包已經夠用了
引入依賴(Jun 14, 2018)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
引入之後可以看到外部jar包多了三個關于log4j2的
關于上面的包
log4j-to-slf4j
将
log4j2
的接口适配到
slf4j
上,不能和
log4j-slf4j-impl
同時存在
log4j-api
包含
.class
但是隻是一堆接口而已,實際使用需要
log4j
log4j-core
.class
與
.java
也就是源碼
jul
指的是
java.util.logging
,是
java
内置的日志子產品
簡介:受
Log4j
啟發,Sun在
Java1.4
版本中引入了
java.util.logging
,但是
jul
功能遠不如
log4j
完善,開發者需要自己編寫
Appenders
(Sun稱之為
Handlers
),且隻有兩個
Handlers
可用(
Console
和
File
),
jul
Java1.5
以後性能和可用性才有所提升。
不是SpringBoot項目需要引用
jul
的話可以加
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jul</artifactId>
<version>2.11.0</version>
</dependency>
Log4j2的使用
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class SpringcloudEurekaApplication {
static Logger logger = LogManager.getLogger(SpringcloudEurekaApplication.class);
public static void main(String[] args) {
logger.info("Current Time: {}", System.currentTimeMillis());
logger.info("Current Time: " + System.currentTimeMillis());
logger.info("Current Time: {}", System.currentTimeMillis());
logger.trace("trace log");
logger.warn("warn log");
logger.debug("debug log");
logger.info("info log");
logger.error("error log");
}
}
啟動項目後控制台輸出為
SLF4J
https://www.slf4j.org/SLF4J(Simple Logging Facade for Java)用作各種日志架構(java.util.logging,logback,log4j)的簡單外觀或抽象,允許最終使用者在部署 時插入所需的日志架構。
最新依賴(Mar 21, 2018)
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.8.0-beta2</version>
</dependency>
Springboot項目不需要引入任何依賴都可以使用
用法
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SpringcloudEurekaApplication{
private static final Logger logger = LoggerFactory.getLogger(SpringcloudEurekaApplication.class);
public static void main(String[] args) {
logger.info("Current Time: {}", System.currentTimeMillis());
logger.info("Current Time: " + System.currentTimeMillis());
logger.info("Current Time: {}", System.currentTimeMillis());
logger.trace("trace log");
logger.warn("warn log");
logger.debug("debug log");
logger.info("info log");
logger.error("error log");
}
}
通常輸出日志開銷非常大,
SLF4J
通過
{}
作為占位符的方式輸出字元串,相比字元串拼接的方式,效率有顯著的提升。
logback
https://logback.qos.ch/logback
log4j
是同一個作者創作,它是
log4j
的更新版
Logback的體系結構足夠通用,以便在不同情況下應用。
logback分為三個子產品: logback-core
logback-classic
logback-access
。
logback-core
logback-classic
logback-access
logback-core
子產品為其他兩個子產品奠定了基礎。
logback-classic
子產品可以被同化為
log4j
的顯着改進版本。
logback-classic
本身實作了
SLF4J API
,是以您可以在
logback
和其他日志架構(如
log4j
或
java.util.logging(JUL)
)之間來回切換。
logback-access
子產品與
Servlet
容器(如Tomcat和Jetty)內建,以提供
HTTP
通路日志功能。可以在
logback-core
之上輕松建構自己的子產品。
Logback的核心對象:Logger、Appender、Layout
Logback主要建立于
Logger
Appender
Layout
這三個類之上。
Logger
:日志的記錄器,把它關聯到應用的對應的
context
上後,主要用于存放日志對象,也可以定義日志類型、級别。
Logger
對象一般多定義為靜态常量.
Appender
:用于指定日志輸出的目的地,目的地可以是控制台、檔案、遠端套接字伺服器、
MySQL
PostreSQL
Oracle
和其他資料庫、
JMS
和遠端
UNIX Syslog
守護程序等。
Layout
:負責把事件轉換成字元串,格式化的日志資訊的輸出。
具體使用
引入依賴(Feb 11, 2018),分别對應
logback
上的三個子產品
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.3.0-alpha4</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.3.0-alpha4</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
<version>1.3.0-alpha4</version>
</dependency>
注:如果在SpringBoot下是不需要引入的
Spring Boot内部日志系統使用的是
Commons Logging
,但開放底層的日志實作。預設為會
Java Util Logging, Log4J, Log4J2和Logback
提供配置。每種情況下都會預先配置使用控制台輸出,也可以使用可選的檔案輸出。
因為在SpringBoot中本身就内置了日志功能,在
spring-boot-starter
依賴中
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
logback的配置介紹
如果沒有配置檔案,那麼
logback
預設地會調用
BasicConfigurator
,建立一個最小化配置。最小化配置由一個關聯到根
logger
的
ConsoleAppender
組成。輸出用模式為
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
PatternLayoutEncoder
進行格式化。
root
logger
預設級别是
DEBUG
官方推薦
官方推薦使用的
xml
名字的格式為:
logback-spring.xml
而不是
logback.xml
,因為帶
spring
字尾的可以使用
<springProfile>
這個标簽。
Logback配置檔案的基本結構
以
<configuration>
開頭,後面有任意個
<appender>
元素,有任意個
<logger>
元素,有最多一個
<root>
元素。
Logback
配置檔案的文法非常靈活。正因為靈活,是以無法用
DTD XML schema進行定義。
1、根節點 <configuration>
,包含下面三個屬性:
<configuration>
scan
: 當此屬性設定為
true
時,配置檔案如果發生改變,将會被重新加載,預設值為
true
scanPeriod
: 設定監測配置檔案是否有修改的時間間隔,如果沒有給出時間機關,預設機關是毫秒。當
scan
為
true
時,此屬性生效。預設的時間間隔為1分鐘。
debug
true
時,将列印出
logback
内部日志資訊,實時檢視
logback
運作狀态。預設值為
false
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!--省略其他配置-->
</configuration>
2.子節點,分别有<appender>,<root>,<logger>,<property>,<contextName>,<conversionRule>,<springProfile>
1.子節點 <appender>
:Logback将執行日志事件輸出的元件稱為Appender,實作的 Appender
必須繼承 ch.qos.logback.core.Appender
接口
<appender>
Appender
ch.qos.logback.core.Appender
它有兩個必要屬性
name
class
name
指定
appender
名稱,
class
appender
的全限定名
注:
class="ch.qos.logback.core.rolling.RollingFileAppender"
常見的日志輸出到檔案,随着應用的運作時間越來越長,日志也會增長的越來越多,将他們輸出到同一個檔案并非一個好辦法。
RollingFileAppender
用于切分檔案日志
<appender>
有四個子節點
<appender>
<encoder>
:對日志進行格式化。必須指定,否則不會往檔案輸出内容
%d{HH: mm:ss.SSS}
——日志輸出時間
%thread
——輸出日志的程序名字,這在Web應用以及異步任務進行中很有用
%-5level
——日志級别,并且使用5個字元靠左對齊
%logger{36}
——日志輸出者的名字
%msg
——日志消息
%n
——平台的換行符
<rollingPolicy>
:循環政策:基于時間建立日志檔案。當發生日志切換時,
RollingFileAppender
的切換行為。例如日志檔案名的修改
常用子節點
<maxHistory>
表示隻保留最近天數的日志,最好設定下,以防止日志填滿整個磁盤空間。
<timeBasedFileNamingAndTriggeringPolicy>
中
<maxFileSize>
是對日志大小進行切割,設定每個日志檔案的最大值
<filter>
:過濾器,執行一個過濾器會有傳回個枚舉值。
傳回
DENY
,日志将立即被抛棄不再經過其他過濾器;
NEUTRAL
,有序清單裡的下個過濾器過接着處理日志;
ACCEPT
,日志會被立即處理,不再經過剩餘過濾器。
<Appender>
添加一個或多個過濾器後,可以用任意條件對日志進行過濾。
<Appender>
有多個過濾器時,按照配置順序執行。
最常用的過濾器
LevelFilter
: 級别過濾器,根據日志級别進行過濾。如果日志級别等于配置級别,過濾器會根據
onMath
onMismatch
接收或拒絕日志。
有以下子節點:
<level>
:設定過濾級别
<onMatch>
:用于配置符合過濾條件的操作
<onMismatch>
:用于配置不符合過濾條件的操作
<file>
:指定正在記錄的日志檔案的路徑及檔案名。
注意在
windows
當中,反斜杠
\
需要轉義,或直接使用
/
也可以。例如
c:/temp/test.log
c:\\temp\\test.log
都可以。可以是相對目錄,也可以是絕對目錄,沒有預設值,如果上層目錄不存在,
FileAppender
會自動建立。
我測試時放在日志檔案是放在E盤下log檔案夾(目錄設定下文有提到)
<appender>
節點定義示例
<!-- 時間滾動輸出 level為 INFO 日志 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在記錄的日志檔案的路徑及檔案名 -->
<file>${log.path}/log_info.log</file>
<!--日志檔案輸出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志記錄器的滾動政策,按日期,按大小記錄 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志歸檔路徑以及格式 -->
<fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志檔案保留天數-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志檔案隻記錄info級别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
2.子節點 <property>
:用來定義變量值,它有兩個屬性 name
value
,通過 <property>
定義的值會被插入到 logger
上下文中,可以使“${}”來使用變量。
<property>
name
value
<property>
logger
<property name="log.path" value="E:/log" />
在上面定義檔案路徑中有使用到
${log.path}
3.子節點 <contextName>
:用來設定上下文名稱,每個 logger
都關聯到 logger
上下文,預設上下文名稱為 default
。但可以使用<contextName>設定成其他名字,用于區分不同應用程式的記錄。一旦設定,不能修改。
<contextName>
logger
logger
default
<contextName>myAppLogBack</contextName>
4.子節點 <logger>
:用來設定某一個包或具體的某一個類的日志列印級别、以及指定 <appender>
<logger>
<appender>
<logger>
僅有一個
name
屬性,一個可選的
level
和一個可選的
addtivity
屬性。
name
:用來指定受此
logger
限制的某一個包或者具體的某一個類。
level
:用來設定列印級别,大小寫無關:
TRACE
DEBUG
INFO
WARN
ERROR
ALL
OFF
addtivity
: 是否向上級
logger
傳遞列印資訊。預設是
true
<logger name="org.springframework.web" level="info" addtivity="true"/>
5.子節點 <root>
:它也是 <logger>
元素,但是它是根 logger
,是所有 <logger>
的上級。
<root>
<logger>
logger
<logger>
root
節點是必選節點,用來指定最基礎的日志輸出級别,隻有一個
level
屬性,因為
name
已經被命名為
root
,且已經是最上級了。
level
:用來設定列印級别,不能設定為
INHERITED
或者同義詞
NULL
。預設是
DEBUG
可以包含零個或多個元素,辨別這個
appender
将會添加到這個
logger
<root level="all">
<appender-ref ref="CONSOLE" />
<appender-ref ref="DEBUG_FILE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="WARN_FILE" />
<appender-ref ref="ERROR_FILE" />
</root>
6.子節點 <springProfile>
: Spring profile
Spring 3
引入的概念,主要用在項目多環境運作的情況下,通過激活方式實作多環境切換,省去多環境切換時配置參數和檔案的修改,相比較 Maven profile
簡單實用,易于上手。并且 Spring profile
提供了多種激活方法,例如配置檔案,注解, jvm
參數設定等等
<springProfile>
Spring profile
Spring 3
Maven profile
Spring profile
jvm
據不同環境(
prod
:生産環境,
test
:測試環境,
dev
:開發環境)來定義不同的日志輸出,在
logback-spring.xml
中使用
springProfile
節點來定義,方法如下:
<!-- 測試環境+開發環境. 多個使用逗号隔開. -->
<springProfile name="test,dev">
<logger name="com.example.springcloudeureka" level="info" />
</springProfile>
<!-- 生産環境. -->
<springProfile name="prod">
<logger name="com.example.springcloudeureka" level="ERROR" />
</springProfile>
可以啟動服務的時候指定
profile
,springboot的話可以在配置檔案
yaml
中設定
spring.profiles.active
7.子節點 <conversionRule>
:logback 自定義Pattern模闆
<conversionRule>
例如需要在每條日志都輸出
logback output
字元串,可以這樣做
寫一個轉換器類,繼承
ClassicConvert
public class LogbackConvert extends ClassicConverter {
@Override
public String convert(ILoggingEvent iLoggingEvent) {
return "logback output";
}
}
實作裡面的方法,傳回的都是
String
類型
logback
配置檔案中中注冊該轉換器,并自定義轉換符
<conversionRule conversionWord="logback"
converterClass="com.example.springcloudeureka.LogbackConvert"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender" >
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg %logback %n</pattern>
</appender>
<appender>
中自定義
Pattern
模闆,用
%轉換器名
即可
效果
都列印出
logback output
字元串
Apache Commons Logging
官方位址:
https://commons.apache.org/proper/commons-logging/Jakarta Commons-logging(JCL)是
apache
最早提供的日志的門面接口。提供簡單的日志實作以及日志解耦功能。
commons-logging
Apache commons
類庫中的一員。
Apache commons
類庫是一個通用的類庫,提供了基礎的功能,比如說
commons-fileupload
commons-httpclient
commons-io
commons-codes
等。
commons-logging
能夠選擇使用
Log4j
還是
JDK Logging
,但是不依賴
Log4j
JDK Logging
API
。如果項目的
classpath
中包含了
log4j
的類庫,就會使用
log4j
,否則就使用
JDK Logging
。使用
commons-logging
能夠靈活的選擇使用那些日志方式,而且不需要修改源代碼。
不過現在
Apache Commons Logging
也不更新了,最新的依賴(Jul 05, 2014)
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
具體實作
JCL有兩個基本的抽象類:Log( 基本記錄器 ) 和 LogFactory( 負責建立 Log 執行個體 )
public class SpringbootApplication {
public static Log LOG= LogFactory.getLog(SpringbootApplication.class);
public static void main(String[] args) {
LOG.debug("debug()...");
LOG.info("info()...");
LOG.error("error()...");
}
}
控制台顯示
SpringBoot已經預設內建了
log4j
關于commons-logging日志解耦可以參考文章:
https://blog.csdn.net/sakurainluojia/article/details/53534949總結:
commons-logging
slf4j
都是日志的接口,供使用者使用,而沒有提供實作。
log4j
logback
等才是日志的真正實作,日志是接口+具體實作的方式來使用。
目前應用比較廣泛的是
Log4j2
logback
,而
logback
作為後起之秀,以替代
log4j
為目的,整體性能比
log4j
較佳,
log4j
log4j2
也是有諸多亮點
選擇使用
logback
Spring Boot
預設的日志系統,假如對日志沒有特殊要求,可以完全零配置(當然也可以自定義
logback-spring.xml
)使用
SLF4J(Simple Logging Facade For Java)
logback
來輸出日志。
個人推薦使用
log4j2
Log4j2
Log4j
的更新版,與之前的版本
Log4j 1.x
相比、有重大的改進,在修正了
Logback
固有的架構問題的同時,改進了許多
Logback
所具有的功能。關于
Log4j2
的新特性可以在其官網首頁檢視
關于 log4j2
的性能使用可以參考
https://www.jianshu.com/p/570b406bddcd https://blog.csdn.net/u011054333/article/details/54412360 https://blog.csdn.net/yjh1271845364/article/details/70888262 log4j2