細(xì)說(shuō) Java 主流日志工具庫(kù)

點(diǎn)關(guān)注,不迷路;持續(xù)更新Java相關(guān)技術(shù)及資訊?。?!

公眾號(hào):Java耕耘者

在項(xiàng)目開發(fā)中,為了跟蹤代碼的運(yùn)行情況,常常要使用日志來(lái)記錄信息。在 Java 世界,有很多的日志工具庫(kù)來(lái)實(shí)現(xiàn)日志功能,避免了我們重復(fù)造輪子。

我們先來(lái)逐一了解一下主流日志工具。

日志框架

java.util.logging (JUL)

JDK1.4 開始,通過(guò) java.util.logging 提供日志功能。

它能滿足基本的日志需要,但是功能沒(méi)有 Log4j 強(qiáng)大,而且使用范圍也沒(méi)有 Log4j 廣泛。

Log4j

Log4j 是 apache 的一個(gè)開源項(xiàng)目,創(chuàng)始人 Ceki Gulcu。

Log4j 應(yīng)該說(shuō)是 Java 領(lǐng)域資格最老,應(yīng)用最廣的日志工具。從誕生之日到現(xiàn)在一直廣受業(yè)界歡迎。

Log4j 是高度可配置的,并可通過(guò)在運(yùn)行時(shí)的外部文件配置。它根據(jù)記錄的優(yōu)先級(jí)別,并提供機(jī)制,以指示記錄信息到許多的目的地,諸如:數(shù)據(jù)庫(kù),文件,控制臺(tái),UNIX 系統(tǒng)日志等。

Log4j 中有三個(gè)主要組成部分:

loggers - 負(fù)責(zé)捕獲記錄信息。

appenders - 負(fù)責(zé)發(fā)布日志信息,以不同的首選目的地。

layouts - 負(fù)責(zé)格式化不同風(fēng)格的日志信息。

官網(wǎng)地址:

http://logging.apache.org/log4j/2.x/

Logback

Logback 是由 log4j 創(chuàng)始人 Ceki Gulcu 設(shè)計(jì)的又一個(gè)開源日記組件,目標(biāo)是替代 log4j。

logback 當(dāng)前分成三個(gè)模塊:logback-core、logback-classic 和 logback-access。

logback-core - 是其它兩個(gè)模塊的基礎(chǔ)模塊。

logback-classic - 是 log4j 的一個(gè) 改良版本。此外 logback-classic 完整實(shí)現(xiàn) SLF4J API 使你可以很方便地更換成其它日記系統(tǒng)如 log4j 或 JDK14 Logging。

logback-access - 訪問(wèn)模塊與 Servlet 容器集成提供通過(guò) Http 來(lái)訪問(wèn)日記的功能。

官網(wǎng)地址:

http://logback.qos.ch/

Log4j2

官網(wǎng)地址:

http://logging.apache.org/log4j/2.x/

按照官方的說(shuō)法,Log4j2 是 Log4j 和 Logback 的替代。

Log4j2 架構(gòu):

Log4j vs Logback vs Log4j2

按照官方的說(shuō)法,Log4j2 大大優(yōu)于 Log4j 和 Logback。

那么,Log4j2 相比于先問(wèn)世的 Log4j 和 Logback,它具有哪些優(yōu)勢(shì)呢?

Log4j2 旨在用作審計(jì)日志記錄框架。Log4j 1.x 和 Logback 都會(huì)在重新配置時(shí)丟失事件。Log4j 2 不會(huì)。在 Logback 中,Appender 中的異常永遠(yuǎn)不會(huì)對(duì)應(yīng)用程序可見。在 Log4j 中,可以將 Appender 配置為允許異常滲透到應(yīng)用程序。

Log4j2 在多線程場(chǎng)景中,異步 Loggers 的吞吐量比 Log4j 1.x 和 Logback 高 10 倍,延遲低幾個(gè)數(shù)量級(jí)。

Log4j2 對(duì)于獨(dú)立應(yīng)用程序是無(wú)垃圾的,對(duì)于穩(wěn)定狀態(tài)日志記錄期間的 Web 應(yīng)用程序來(lái)說(shuō)是低垃圾。這減少了垃圾收集器的壓力,并且可以提供更好的響應(yīng)時(shí)間性能。

Log4j2 使用插件系統(tǒng),通過(guò)添加新的 Appender、Filter、Layout、Lookup 和 Pattern Converter,可以非常輕松地?cái)U(kuò)展框架,而無(wú)需對(duì) Log4j 進(jìn)行任何更改。

由于插件系統(tǒng)配置更簡(jiǎn)單。配置中的條目不需要指定類名。

支持自定義日志等級(jí)。

支持 lambda 表達(dá)式。

支持消息對(duì)象。

Log4j 和 Logback 的 Layout 返回的是字符串,而 Log4j2 返回的是二進(jìn)制數(shù)組,這使得它能被各種 Appender 使用。

Syslog Appender 支持 TCP 和 UDP 并且支持 BSD 系統(tǒng)日志。

Log4j2 利用 Java5 并發(fā)特性,盡量小粒度的使用鎖,減少鎖的開銷。

日志門面

何謂日志門面?

日志門面是對(duì)不同日志框架提供的一個(gè) API 封裝,可以在部署的時(shí)候不修改任何配置即可接入一種日志實(shí)現(xiàn)方案。

common-logging

common-logging 是 apache 的一個(gè)開源項(xiàng)目。也稱Jakarta Commons Logging,縮寫 JCL。

common-logging 的功能是提供日志功能的 API 接口,本身并不提供日志的具體實(shí)現(xiàn)(當(dāng)然,common-logging 內(nèi)部有一個(gè) Simple logger 的簡(jiǎn)單實(shí)現(xiàn),但是功能很弱,直接忽略),而是在運(yùn)行時(shí)動(dòng)態(tài)的綁定日志實(shí)現(xiàn)組件來(lái)工作(如 log4j、java.util.loggin)。

官網(wǎng)地址:

http://commons.apache.org/proper/commons-logging/

slf4j

全稱為 Simple Logging Facade for Java,即 java 簡(jiǎn)單日志門面。

什么,作者又是 Ceki Gulcu!這位大神寫了 Log4j、Logback 和 slf4j,專注日志組件開發(fā)五百年,一直只能超越自己。

類似于 Common-Logging,slf4j 是對(duì)不同日志框架提供的一個(gè) API 封裝,可以在部署的時(shí)候不修改任何配置即可接入一種日志實(shí)現(xiàn)方案。但是,slf4j 在編譯時(shí)靜態(tài)綁定真正的 Log 庫(kù)。使用 SLF4J 時(shí),如果你需要使用某一種日志實(shí)現(xiàn),那么你必須選擇正確的 SLF4J 的 jar 包的集合(各種橋接包)。

官網(wǎng)地址:http://www.slf4j.org/

common-logging vs slf4j

slf4j 庫(kù)類似于 Apache Common-Logging。但是,他在編譯時(shí)靜態(tài)綁定真正的日志庫(kù)。這點(diǎn)似乎很麻煩,其實(shí)也不過(guò)是導(dǎo)入橋接 jar 包而已。

slf4j 一大亮點(diǎn)是提供了更方便的日志記錄方式:

不需要使用logger.isDebugEnabled()來(lái)解決日志因?yàn)樽址唇赢a(chǎn)生的性能問(wèn)題。slf4j 的方式是使用{}作為字符串替換符,形式如下:

logger.debug("id:?{},name:?{}?",id,name);

總結(jié)

綜上所述,使用 slf4j + Logback 可謂是目前最理想的日志解決方案了。

接下來(lái),就是如何在項(xiàng)目中實(shí)施了。

實(shí)施日志解決方案

使用日志解決方案基本可分為三步:

引入 jar 包

配置

使用 API

常見的各種日志解決方案的第 2 步和第 3 步基本一樣,實(shí)施上的差別主要在第 1 步,也就是使用不同的庫(kù)。

引入 jar 包

這里首選推薦使用 slf4j + logback 的組合。

如果你習(xí)慣了 common-logging,可以選擇 common-logging+log4j。

強(qiáng)烈建議不要直接使用日志實(shí)現(xiàn)組件(logback、log4j、java.util.logging),理由前面也說(shuō)過(guò),就是無(wú)法靈活替換日志庫(kù)。

還有一種情況:你的老項(xiàng)目使用了 common-logging,或是直接使用日志實(shí)現(xiàn)組件。如果修改老的代碼,工作量太大,需要兼容處理。在下文,都將看到各種應(yīng)對(duì)方法。

注:據(jù)我所知,當(dāng)前仍沒(méi)有方法可以將 slf4j 橋接到 common-logging。如果我孤陋寡聞了,請(qǐng)不吝賜教。

slf4j 直接綁定日志組件

slf4j + logback

添加依賴到 pom.xml 中即可。

logback-classic-1.0.13.jar 會(huì)自動(dòng)將 slf4j-api-1.7.21.jar 和 logback-core-1.0.13.jar 也添加到你的項(xiàng)目中。

ch.qos.logback

logback-classic

1.0.13

slf4j + log4j

添加依賴到 pom.xml 中即可。

slf4j-log4j12-1.7.21.jar 會(huì)自動(dòng)將 slf4j-api-1.7.21.jar 和 log4j-1.2.17.jar 也添加到你的項(xiàng)目中。

org.slf4j

slf4j-log4j12

1.7.21

slf4j + java.util.logging

添加依賴到 pom.xml 中即可。

slf4j-jdk14-1.7.21.jar 會(huì)自動(dòng)將 slf4j-api-1.7.21.jar 也添加到你的項(xiàng)目中。

org.slf4j

slf4j-jdk14

1.7.21

slf4j 兼容非 slf4j 日志組件

在介紹解決方案前,先提一個(gè)概念——橋接

什么是橋接呢

假如你正在開發(fā)應(yīng)用程序所調(diào)用的組件當(dāng)中已經(jīng)使用了 common-logging,這時(shí)你需要 jcl-over-slf4j.jar 把日志信息輸出重定向到 slf4j-api,slf4j-api 再去調(diào)用 slf4j 實(shí)際依賴的日志組件。這個(gè)過(guò)程稱為橋接。下圖是官方的 slf4j 橋接策略圖:

從圖中應(yīng)該可以看出,無(wú)論你的老項(xiàng)目中使用的是 common-logging 或是直接使用 log4j、java.util.logging,都可以使用對(duì)應(yīng)的橋接 jar 包來(lái)解決兼容問(wèn)題。

slf4j 兼容 common-logging

org.slf4j

jcl-over-slf4j

1.7.12

slf4j 兼容 log4j

org.slf4j

log4j-over-slf4j

1.7.12

slf4j 兼容 java.util.logging

org.slf4j

jul-to-slf4j

1.7.12

spring 集成 slf4j

做 java web 開發(fā),基本離不開 spring 框架。很遺憾,spring 使用的日志解決方案是 common-logging + log4j。(系統(tǒng)的學(xué)習(xí)spring全家桶,可以在Java知音公眾號(hào)內(nèi)回復(fù)“Springboot聚合”)

所以,你需要一個(gè)橋接 jar 包:logback-ext-spring。

ch.qos.logback

logback-classic

1.1.3

org.logback-extensions

logback-ext-spring

0.1.2

org.slf4j

jcl-over-slf4j

1.7.12

common-logging 綁定日志組件

common-logging + log4j

添加依賴到 pom.xml 中即可。

commons-logging

commons-logging

1.2

log4j

log4j

1.2.17

使用 API

slf4j 用法

使用 slf4j 的 API 很簡(jiǎn)單。使用LoggerFactory初始化一個(gè)Logger實(shí)例,然后調(diào)用 Logger 對(duì)應(yīng)的打印等級(jí)函數(shù)就行了。

importorg.slf4j.Logger;

importorg.slf4j.LoggerFactory;

publicclassApp{

privatestaticfinal?Loggerlog=?LoggerFactory.getLogger(App.class);

publicstaticvoidmain(String[]?args){

String?msg?="print?log,?current?level:?{}";

log.trace(msg,"trace");

log.debug(msg,"debug");

log.info(msg,"info");

log.warn(msg,"warn");

log.error(msg,"error");

}

}

common-logging 用法

common-logging 用法和 slf4j 幾乎一樣,但是支持的打印等級(jí)多了一個(gè)更高級(jí)別的:fatal。

此外,common-logging 不支持{}替換參數(shù),你只能選擇拼接字符串這種方式了。

importorg.apache.commons.logging.Log;

importorg.apache.commons.logging.LogFactory;

publicclassJclTest{

privatestaticfinal?Loglog=?LogFactory.getLog(JclTest.class);

publicstaticvoidmain(String[]?args){

String?msg?="print?log,?current?level:?";

log.trace(msg?+"trace");

log.debug(msg?+"debug");

log.info(msg?+"info");

log.warn(msg?+"warn");

log.error(msg?+"error");

log.fatal(msg?+"fatal");

}

}

log4j2 配置

log4j2 基本配置形式如下:

<?xml?version="1.0"?encoding="UTF-8"?>;

value

...

...

配置示例:

<?xml?version="1.0"?encoding="UTF-8"?>

packages="org.apache.logging.log4j.test">

target/test.log

<!--?class?and?line?number?-->

%d?%p?%C{1.}?[%t]?%m%n

logback 配置

<configuration>

作用:<configuration>是 logback 配置文件的根元素。

要點(diǎn):它有<appender>、<logger>、<root>三個(gè)子元素。


<appender>

作用:將記錄日志的任務(wù)委托給名為 appender 的組件。

要點(diǎn):可以配置零個(gè)或多個(gè);它有<file>、<filter>、<layout>、<encoder>四個(gè)子元素。

屬性:

name:設(shè)置 appender 名稱。

class:設(shè)置具體的實(shí)例化類。

<file>

作用:設(shè)置日志文件路徑。

<filter>

作用:設(shè)置過(guò)濾器。

要點(diǎn):可以配置零個(gè)或多個(gè)。

<layout>

作用:設(shè)置 appender。

要點(diǎn):可以配置零個(gè)或一個(gè)。

屬性:

class:設(shè)置具體的實(shí)例化類。

<encoder>

作用:設(shè)置編碼。

要點(diǎn):可以配置零個(gè)或多個(gè)。

屬性:

class:設(shè)置具體的實(shí)例化類。

<logger>

作用:設(shè)置 logger。

要點(diǎn):可以配置零個(gè)或多個(gè)。

屬性:

name

level:設(shè)置日志級(jí)別。不區(qū)分大小寫。可選值:TRACE、DEBUG、INFO、WARN、ERROR、ALL、OFF。

additivity:可選值:true 或 false。

<appender-ref>

作用:appender 引用。

要點(diǎn):可以配置零個(gè)或多個(gè)。

<root>

作用:設(shè)置根 logger。

要點(diǎn):只能配置一個(gè);除了 level,不支持任何屬性。level 屬性和<logger>中的相同;有一個(gè)子元素<appender-ref>,與<logger>中的相同。

完整的 logback.xml 參考示例

在下面的配置文件中,我為自己的項(xiàng)目代碼(根目錄:org.zp.notes.spring)設(shè)置了五種等級(jí):

TRACE、DEBUG、INFO、WARN、ERROR,優(yōu)先級(jí)依次從低到高。

因?yàn)殛P(guān)注 spring 框架本身的一些信息,我增加了專門打印 spring WARN 及以上等級(jí)的日志。

<?xml?version="1.0"?encoding="UTF-8"??>

<!--?logback中一共有5種有效級(jí)別,分別是TRACE、DEBUG、INFO、WARN、ERROR,優(yōu)先級(jí)依次從低到高?-->

<!--?將記錄日志打印到控制臺(tái)?-->

%d{HH:mm:ss.SSS}?[%thread]?[%-5p]?%c{36}.%M?-?%m%n

<!--?RollingFileAppender?begin?-->

<!--?根據(jù)時(shí)間來(lái)制定滾動(dòng)策略?-->

${user.dir}/logs/${DIR_NAME}/all.%d{yyyy-MM-dd}.log

30

<!--?根據(jù)文件大小來(lái)制定滾動(dòng)策略?-->

30MB

%d{HH:mm:ss.SSS}?[%thread]?[%-5p]?%c{36}.%M?-?%m%n

<!--?根據(jù)時(shí)間來(lái)制定滾動(dòng)策略?-->

${user.dir}/logs/${DIR_NAME}/error.%d{yyyy-MM-dd}.log

30

<!--?根據(jù)文件大小來(lái)制定滾動(dòng)策略?-->

10MB

ERROR

ACCEPT

DENY

%d{HH:mm:ss.SSS}?[%thread]?[%-5p]?%c{36}.%M?-?%m%n

<!--?根據(jù)時(shí)間來(lái)制定滾動(dòng)策略?-->

${user.dir}/logs/${DIR_NAME}/warn.%d{yyyy-MM-dd}.log

30

<!--?根據(jù)文件大小來(lái)制定滾動(dòng)策略?-->

10MB

WARN

ACCEPT

DENY

%d{HH:mm:ss.SSS}?[%thread]?[%-5p]?%c{36}.%M?-?%m%n

<!--?根據(jù)時(shí)間來(lái)制定滾動(dòng)策略?-->

${user.dir}/logs/${DIR_NAME}/info.%d{yyyy-MM-dd}.log

30

<!--?根據(jù)文件大小來(lái)制定滾動(dòng)策略?-->

10MB

INFO

ACCEPT

DENY

%d{HH:mm:ss.SSS}?[%thread]?[%-5p]?%c{36}.%M?-?%m%n

<!--?根據(jù)時(shí)間來(lái)制定滾動(dòng)策略?-->

${user.dir}/logs/${DIR_NAME}/debug.%d{yyyy-MM-dd}.log

30

<!--?根據(jù)文件大小來(lái)制定滾動(dòng)策略?-->

10MB

DEBUG

ACCEPT

DENY

%d{HH:mm:ss.SSS}?[%thread]?[%-5p]?%c{36}.%M?-?%m%n

<!--?根據(jù)時(shí)間來(lái)制定滾動(dòng)策略?-->

${user.dir}/logs/${DIR_NAME}/trace.%d{yyyy-MM-dd}.log

30

<!--?根據(jù)文件大小來(lái)制定滾動(dòng)策略?-->

10MB

TRACE

ACCEPT

DENY

%d{HH:mm:ss.SSS}?[%thread]?[%-5p]?%c{36}.%M?-?%m%n

<!--?根據(jù)時(shí)間來(lái)制定滾動(dòng)策略?-->

${user.dir}/logs/${DIR_NAME}/springframework.%d{yyyy-MM-dd}.log

30

<!--?根據(jù)文件大小來(lái)制定滾動(dòng)策略?-->

10MB

%d{HH:mm:ss.SSS}?[%thread]?[%-5p]?%c{36}.%M?-?%m%n

<!--?RollingFileAppender?end?-->

<!--?logger?begin?-->

<!--?本項(xiàng)目的日志記錄,分級(jí)打印?-->

<!--?SPRING框架日志?-->

<!--?logger?end?-->

log4j 配置

完整的 log4j.xml 參考示例

log4j 的配置文件一般有 xml 格式或 properties 格式。這里為了和 logback.xml 做個(gè)對(duì)比,就不介紹 properties 了,其實(shí)也沒(méi)太大差別。

<?xml?version="1.0"?encoding="UTF-8"?>

<!DOCTYPE?log4j:configuration?SYSTEM?"log4j.dtd">

value="%d{yyyy-MM-dd?HH:mm:ss,SSS\}?[%-5p]?[%t]?%c{36\}.%M?-?%m%n"/>

<!--過(guò)濾器設(shè)置輸出的級(jí)別-->

<!--?每天重新生成日志文件?-->

<!--?每小時(shí)重新生成日志文件?-->

<!--<param?name="DatePattern"?value="'-'yyyy-MM-dd-HH'.log'"/>-->

value="%d{yyyy-MM-dd?HH:mm:ss,SSS\}?[%-5p]?[%t]?%c{36\}.%M?-?%m%n"/>

<!--?指定logger的設(shè)置,additivity指示是否遵循缺省的繼承機(jī)制-->

<!--?根logger的設(shè)置-->

參考

http://www.slf4j.org/manual.html

http://logback.qos.ch/

http://logging.apache.org/log4j/1.2/

http://commons.apache.org/proper/commons-logging/

http://blog.csdn.net/yycdaizi/article/details/8276265

為了感謝支持我的朋友!整理了一份Java高級(jí)架構(gòu)資料、Spring源碼分析、Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式等資料可以進(jìn)群領(lǐng)取。

本號(hào)專注Java源碼分析。喜歡底層源碼的朋友可以來(lái)交流探討。交流群:818491202 驗(yàn)證:33

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 概述 在項(xiàng)目開發(fā)中,為了跟蹤代碼的運(yùn)行情況,常常要使用日志來(lái)記錄信息。在Java世界,有很多的日志工具庫(kù)來(lái)實(shí)現(xiàn)日志...
    靜默虛空閱讀 1,978評(píng)論 1 9
  • 前言 最近學(xué)習(xí)開java web服務(wù)器開發(fā),開始學(xué)習(xí)java,處理業(yè)務(wù)邏輯,但對(duì)其中的日志比較好奇,之前沒(méi)怎么接觸...
    九風(fēng)萍舟閱讀 3,427評(píng)論 1 6
  • log4j, log4j2, slf4j, logback關(guān)系 log4j是由Apache開發(fā)的一套元老級(jí)日志框架...
    rainybowe閱讀 1,776評(píng)論 0 4
  • 作為Java開發(fā)人員,對(duì)于日志記錄框架一定非常熟悉。而且?guī)缀踉谒袘?yīng)用里面,一定會(huì)用到各種各樣的日志框架用來(lái)記錄程...
    意識(shí)流丶閱讀 14,464評(píng)論 0 13
  • 在項(xiàng)目開發(fā)過(guò)程中,我們可以通過(guò) debug 查找問(wèn)題。而在線上環(huán)境我們查找問(wèn)題只能通過(guò)打印日志的方式查找問(wèn)題。因此...
    Java架構(gòu)閱讀 3,574評(píng)論 2 41

友情鏈接更多精彩內(nèi)容