背景:
業(yè)務上面的代碼,肯定都是需要打印日志的甲献,不論是之后定位問題還是其他什么的宰缤。
最基礎的訴求就是能夠將不同級別的日志打印到不同的文件中,能夠按天來區(qū)分晃洒。這些log4j2都有慨灭,并且支持異步處理。雖然我沒有用過logback和log4j锥累,但是通過博客中得出的結論就是log4j2有他們都有的優(yōu)點缘挑,也有他們沒有的優(yōu)點集歇。
本文并沒有仔細鉆研l(wèi)og4j2的底層桶略,暫時只是出于用日志的地步。其實有日志也可以玩出很多玩意诲宇,比如小米的lcs际歼,就可以通過log4j2來講一些數(shù)據(jù)異步上傳到服務器中,來完成一些數(shù)據(jù)打點姑蓝。
日志配置
先來一個簡單的日志配置
依賴:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.4.2</version>
</dependency>
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="error">
<!--先定義所有的appender -->
<appenders>
<!--這個輸出控制臺的配置 -->
<!-- onMatch="ACCEPT" 表示匹配該級別及以上-->
<!-- onMatch="DENY" 表示不匹配該級別及以上-->
<!-- onMatch="NEUTRAL" 表示該級別及以上的鹅心,由下一個filter處理,如果當前是最后一個纺荧,則表示匹配該級別及以上-->
<!-- onMismatch="ACCEPT" 表示匹配該級別以下-->
<!-- onMismatch="NEUTRAL" 表示該級別及以下的旭愧,由下一個filter處理颅筋,如果當前是最后一個,則不匹配該級別以下的-->
<!-- onMismatch="DENY" 表示不匹配該級別以下的-->
<Console name="Console" target="SYSTEM_OUT">
<!-- 控制臺只輸出level及以上級別的信息(onMatch)输枯,其他的直接拒絕(onMismatch) -->
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
<!-- 這個都知道是輸出日志的格式 -->
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
</Console>
<!--文件會打印出所有信息议泵,這個log每次運行程序會自動清空,由append屬性決定桃熄,這個也挺有用的先口,適合臨時測試用 -->
<!--append為TRUE表示消息增加到指定文件中,false表示消息覆蓋指定的文件內容瞳收,默認值是true -->
<File name="log" fileName="D:/logs/log4j2.log" append="true">
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
</File>
<!--添加過濾器ThresholdFilter,可以有選擇的輸出某個級別以上的類別 onMatch="ACCEPT" onMismatch="DENY"意思是匹配就接受,否則直接拒絕 -->
<File name="ERROR" fileName="D:/logs/error.log">
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="%d{yyyy.MM.dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
</File>
<!--這個會打印出所有的信息碉京,每次大小超過size,則這size大小的日志會自動存入按年份-月份建立的文件夾下面并進行壓縮螟深,作為存檔 -->
<RollingFile name="RollingFile" fileName="D:/logs/web.log"
filePattern="logs/$${date:yyyy-MM}/web-%d{MM-dd-yyyy}-%i.log.gz">
<PatternLayout pattern="%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
<SizeBasedTriggeringPolicy size="2MB"/>
</RollingFile>
</appenders>
<!--然后定義logger谐宙,只有定義了logger并引入的appender,appender才會生效 -->
<loggers>
<AsyncRoot level="info" includeLocation="true">
<appender-ref ref="RollingFile"/>
<appender-ref ref="Console"/>
<appender-ref ref="log"/>
<appender-ref ref="ERROR" />
</AsyncRoot>
</loggers>
</configuration>
測試程序
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Test {
private static Logger logger= LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
@org.junit.Test
public void Test(){
System.out.println(1);
logger.info("info");
logger.error("error");
}
}
=========================================================
上面中重要的配置標簽有3個界弧,一個是全局的Configuration, 然后是appender, 然后是logger.
下面這段話是copy過來的卧惜。
Logger是最常使用的類,用于打印日記的接口夹纫,通過LogManager類指定名字獲得咽瓷。LogManager定位LoggerContext并從它那獲得Logger。如果Logger被創(chuàng)建舰讹,Logger會被關聯(lián)一個LoggerConfig茅姜,該LoggerConfig可能與Logger同名,或同父package名或為root LoggerConfig(涉及Level Inheritance)(這邊可以結合測試程序來看)月匣。
使用Logger可以打印不同級別的日志钻洒,這些日志會被包裝為LogEvent。LogEvent會被派送到LoggerConfig上锄开。LoggerConfig在xml配置文件中由Logger元素配置的(我們日志中的應該就是rootlog)素标,LoggerConfig含有日志級別(Log Level)信息,對應0到多個Appender萍悴。LoggerConfig根據(jù)自己的日志級別配置與LogEvent的級別头遭,決定是否允許進一步的處理。如果NO則丟棄癣诱,如果Yes則傳給Appender计维。
LoggerConfig中的日記級別只是一個種定義好了的過濾器(Filter),還可以在Logger元素中為LoggerConfig配置過濾器撕予,進行更細致的控制鲫惶。
Appender負責將LogEvent派送到目的地,可以有很多目的地实抡,如console欠母,文件欢策、遠程服務器或數(shù)據(jù)庫等等。一個loggerConfig可以對應很多Appender赏淌,loggerConfig含有父(或祖先)loggerConfig的引用猬腰。因此loggerConfig不僅將LogEvent發(fā)送給自己的所有Appender,還發(fā)給它的父(或祖先)LoggerConfig的appender猜敢,然后遞歸向上姑荷,這種行為被稱為Additivity。
appender只關心如何將LogEvent送到目的地缩擂,而Layout負責格式化LogEvent鼠冕。log4j中含有不同種Layout,用于不同的用途胯盯,如JSON懈费,XML,HTML等等博脑。
每個Logger都有自己的名字憎乙,通常使用Logger所處類的全限定名作為Logger的名字。
在log4j中必定存在root LoggerConfig叉趣,即使沒有手動配置泞边,也會使用默認的,保證Logger能夠關聯(lián)到LoggerConfig疗杉。
==================================================
(這邊有一個疑惑阵谚,logger的日志級別設置和appender中的ThresholdFilter日志級別設置)
問題解答:經(jīng)過我本地的測試,其實這邊消息會經(jīng)過多種過濾烟具。首先在logger中會根據(jù)日志級別將消息傳到所有滿足的logger上(當有多個logger的時候)梢什,然后logger會傳送給appender, appender如果設置了ThresholdFilter, 就會篩選出符合對應日志級別的信息朝聋,床送到目的地中
學習的有些片面嗡午,剛會使用的地步,但是在調用異步的時候冀痕,程序開始報錯了荔睹,明天需要好好探究一下原因。 原因居然是因為少加了一個依賴=-=,也是醉了金度,算了应媚,明天再寫吧
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.4.2</version>
</dependency>
3個標簽:
Configuration
Configuration元素一些重要的屬性如下:
status:log4j框架內部要輸出到console的LogEvent的級別〔录可選值:trace", “debug”, “info”, “warn”, “error” and “fatal”。貌似默認warn消玄。
dest:輸出到console具體的流跟伏《撸可選值:“err”,“out”,文件或url。默認out受扳。
monitorInterval:多少秒掃描一下配置文件
Appenders
<appenders>主要有3種類型的子標簽携龟,console(控制臺), File 普通文件勘高, RollingFile 一種可以自動調節(jié)的文件
Console節(jié)點用來定義輸出到控制臺的Appender.
File節(jié)點用來定義輸出到指定位置的文件的Appender.
RollingFile節(jié)點用來定義超過指定大小自動刪除舊的創(chuàng)建新的的Appender.
其中滾動策略可以做成時間和大小雙重滾動峡蟋,配置如下:
<!--此處舉例為每小時滾動一個文件且每500M滾動一個文件,控制每小時最多保留20個文件华望,總的文件保留3天-->
<!--具體需要根據(jù)應用的日志量和希望保留日志大小以及磁盤空間進行評估-->
<RollingRandomAccessFile name="APPINFO_APPENDER" fileName="${baseLogDir}/appinfo.log"
filePattern="${baseLogDir}/appinfo.log.%d{yyyyMMddHH}.%i.gz">
<PatternLayout>
<Pattern>${pattern}</Pattern>
</PatternLayout>
<Policies>
<SizeBasedTriggeringPolicy size="500MB" />
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
</Policies>
<Filters>
<!-- 當前appender只打印info日志蕊蝗,warn及以上日志忽略,由后面的錯誤日志記錄 -->
<ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL" />
<ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY" />
</Filters>
<!-- max=20表示一小時內最多保留20個日志文件 -->
<DefaultRolloverStrategy max="20">
<!-- 對于指定的路徑下的指定后綴的文件赖舟,只保留3天的日志文件蓬戚,那么最多會有3天*24小時*20個日志文件 -->
<!-- 注意應用需要根據(jù)業(yè)務需求和磁盤大小評估需要保留的日志個數(shù),對于500M的日志文件來說宾抓,要根據(jù)應用日志的情況子漩,觀察單個日志壓縮后文件大小,并計算總大小需要的空間 -->
<Delete basePath="${baseLogDir}" maxDepth="1">
<IfFileName glob="*.gz" />
<IfLastModified age="3d" />
</Delete>
</DefaultRolloverStrategy>
</RollingRandomAccessFile>
具體標簽石洗,看配置文件應該是可以看懂的幢泼,之后的例子都可以這樣子設置
Logger
Loggers標簽中常見同步的有兩種:Root和Logger,異步有AsyncRoot 讲衫,和 AsyncLogger旭绒。
log4j2支持同步,異步焦人,混合模式挥吵。
Root節(jié)點用來指定項目的根日志,如果沒有單獨指定Logger花椭,那么就會默認使用該Root日志輸出
Logger節(jié)點用來單獨指定日志的形式忽匈,比如要為指定包下的class指定不同的日志級別等。
自定義的Logger(子Loggger)繼承自rootLogger矿辽,如果存在繼承丹允,那么他們也會繼承他們的父類中的appender,這個就是上面所說的這種行為被稱為Additivity。
總結:
對目前來說袋倔,會用就行雕蔽,不要搞出都不知道日志打印到了哪邊,日志怎么不輸出的玩笑出來宾娜。
參考博客: