logging翻譯爲日誌記錄html
那問題是什麼是日誌?java
日誌其實是日記的一種,用於記錄某個時間點發生了什麼事情,好比大學老師的教學日誌,工做日誌等程序員
爲何要記錄日誌?web
在實際生活中記錄日誌主要爲了往後複查,數據庫
好比某個大學老師天天記錄本身講的什麼內容,後面有學生某科成績優異獲獎了,校長想要獎勵對應的老師,但因爲每一個老師教的班級都不少,並不必定記得是誰教的,這時候就能夠查看教學日誌來獲取須要的信息了apache
再好比,工廠的生產日誌,若是某個產品除了由於某個零件出現了故障,經過生成日誌,能夠找到與這個產品同批次的其餘產品,進行返工,或是經過日誌找到該零件的供應商,進行溝通解決!json
程序中的日誌api
咱們的程序開發完成後會被不一樣系統環境的用戶下載使用,期間可能就會出現問題,直接把錯誤信息展現給用戶看是沒有任何意義的,用戶看不懂也不會解決,那這時候就能夠將用戶執行的全部操做,以及代碼運行的過程,記錄到日誌中,程序員經過分析日誌內容,能夠快速的定位問題跨域
綜上: 日誌就是用來記錄發生的事件的app
日誌並不會當即產生做用,而是當程序出現了問題時在去分析日誌文件提取有用信息
門面是Facade(外觀模式)的實現,也稱爲門面模式,
是對內部多個子系統的封裝,並對外提供一套統一的使用接口,從而屏蔽各個子系統在使用上的不一樣,大大下降了系統的使用難度,同時提升了系統的可維護性和擴展性;
實際上真正幹活的仍是是內部的子系統;就像給這些子系統加了一層裝飾,Facede也得名於此;
圖示:
因其性能優越性,實際開發中log4j是使用最多一個日誌框架,也是咱們須要掌握的目標;
官方性能對比:
日誌級別:
日誌級別其實指的就是日誌信息應用場景,咱們的程序會在不一樣的環境中運行,某些日誌只有用在某些特殊場景中,例如:在開發階段,咱們爲了檢查錯誤,會輸出一些調試信息,可是這些信息在生產環境下是不須要的,固然.咱們能夠在發佈前刪除這些調試代碼,但這就顯得很是low了,經過對日誌信息區別對待,咱們能夠很方便的控制哪些日誌在哪些場景下正常輸出;
日誌級別也在後續的問題定位中發揮着重要做用,當程序出現了問題,咱們要根據日誌來定位問題,這時即可以經過日誌級別來快速過濾掉不須要的記錄;
log4j日誌級別:
log4j定義了8個級別,優先級從高到低依次爲:
OFF>FATAL> ERROR> WARN> INFO> DEBUG> TRACE> ALL
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.5</version> </dependency>
2.x日後的版本不在支持properties做爲配置文件,因其沒法表達較爲複雜的語法結構
log4j2會在classpath下查找配置文件,若是找不到則使用基礎配置(輸出到控制檯),log4j支持 xml,json,jsn三種格式的配置文件,並可爲測試環境和生產環境編寫不一樣的配置文件;如有多個配置文件log4j將按照如下順序讀取:
示例log4j2.xml:
<?xml version="1.0" encoding="UTF-8"?> <!-- status="WARN" 用於設置log4j框架自己的日誌級別--> <Configuration status="WARN"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </Console> </Appenders> <Loggers> <Root level="all"> <AppenderRef ref="Console"/> </Root> </Loggers> </Configuration>
測試代碼:
@Test public void test1(){ Logger myLogger = LogManager.getLogger("myLogger"); myLogger.debug("debug msg"); }
該節點配置日誌信息的輸出目的地,能夠是控制檯,文件,郵件或數據庫,控制檯和文件是表經常使用的兩個目的地;
上述案例既將日誌信息輸出到控制檯,其子節點PatternLayout用於設置日誌輸出的字符傳格式;
PatternLayout可用的格式化字符:
%d{HH:mm:ss.SSS} 表示輸出到毫秒的時間 %t 輸出當前線程名稱 %-5level 輸出日誌級別,-5表示左對齊而且固定輸出5個字符,若是不足在右邊補空格 %logger 輸出logger名稱,由於Root Logger沒有名稱 %msg 日誌文本 %n 換行 %F 輸出所在的類文件名,如Client.java %L 輸出行號 %M 輸出所在方法名 %C 產生log事件的java徹底限定類名 %l 輸出語句所在的行數, 包括類名、方法名、文件名、行數
輸出到文件:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger - %msg%n"/> </Console> <File name="fileAppender" fileName="logs/app.log" append="false"><!--默認以當前項目爲相對路徑--> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger - %msg%n"/> </File> </Appenders> <Loggers> <Root level="all"> <AppenderRef ref="Console"/> <AppenderRef ref="fileAppender"/><!--一個logger可配置對個appender輸出到不一樣位置--> </Root> </Loggers> </Configuration> <!--File屬性: name用於給appender指定名字,以便logger引用 fileName默認以當前項目爲相對路徑 append參數表示是否將是追加到文件末尾 默認爲true 爲false即直接覆蓋原文件-->
上面的配置會將全部日誌輸出到同一個文件,隨着時間的推移該文件會愈來愈大,甚至沒法打開,可是實際有用的日誌都是近期的產生的,過久遠的日誌大多數是無用的,這就用到了滾動日誌,其能夠幫助咱們實現日誌文件的切割,以及無用日誌的刪除操做;
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"> <!--自定義屬性信息--> <properties> <property name="LOG_HOME">logs</property> <property name="FILE_NAME">applog</property> </properties> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </Console> <!--滾動日誌配置 filePattern用於設置滾動文件的命名規則 若以.zip爲結尾則會自動歸檔日誌文件 也支持其餘的格式.gz, .zip, .bz2, 等--> <RollingRandomAccessFile name="RollingAppender" fileName="${LOG_HOME}/${FILE_NAME}.log" filePattern="${LOG_HOME}/$${date:yyyy-MM}/${FILE_NAME}-%d{yyyy-MM-dd HH-mm}-%i.log"> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> <Policies> <!--滾動時間間隔 該參數需結合filePattern中的時間格式 此時表示爲1分鐘更換一個新文件 若時間格式爲%d{yyyy-MM-dd HH}則表示每小時更換一個新文件--> <TimeBasedTriggeringPolicy interval="1"/> <!--單個日誌文件最大容量 --> <SizeBasedTriggeringPolicy size="1 MB"/> </Policies> <!--最大保留的日誌文件個數 默認爲7個 --> <DefaultRolloverStrategy max="20"/> </RollingRandomAccessFile> </Appenders> <Loggers> <Root level="all"> <AppenderRef ref="RollingAppender"/> </Root> </Loggers> </Configuration>
上述配置的總體含義:統一使用rootLogger,全部級別日誌都會被記錄到文件中,文件位於項目目錄下的logs中,當單個文件超過1MB或是時間超過1分鐘後則更換日誌文件,最多保存20個日誌文件;
補充:RollingFile也是作滾動日誌的,可是據官方說效率沒有RollingRandomAccessFile高;
需求:某個類或模塊中產生的須要同時輸出到控制檯和文件,其餘模塊則僅輸出到控制檯,當遇到相似需求時,就須要定義不一樣的logger了,而後在程序中根據名稱獲取所需的logger
若是在配置中找不到名稱匹配的logger時使用rootLogger;
logger配置:
注意:appender使用的仍是上面的例子中的
<Loggers> <Root level="all"> <AppenderRef ref="Console" /> </Root> <Logger name="fileAndConsole" level="all" additivity="false"> <AppenderRef ref="Console" /> <AppenderRef ref="RollingAppender" /> </Logger> </Loggers> <!-- additivity表示是否將日誌傳遞給root繼續輸出 默認爲true-->
測試代碼:
@Test public void test1(){ Logger myLogger = LogManager.getLogger("myLogger");//rootlogger Logger myLogger2 = LogManager.getLogger("fileAndConsole");//fileAndConsole for (int i = 0;i < 50;i++){ myLogger.debug("debug msg1"); } for (int i = 0;i < 50;i++){ myLogger2.debug("debug msg2"); } }
msg1將只出如今控制檯,而msg2同時出如今控制檯和日誌文件;
Filter用於對日誌進行過濾,一些狀況下咱們可能須要對日誌進行更加個性化的限制,
例如:
輸出日誌消息包含某個字符串的
按照時間不一樣輸出到不一樣文件
一個日誌事件(LogEvent)產生後到最終輸出到目的地會通過如下環節:
全局過濾器 -> logger過濾器 -> logger -> appender過濾器 -> appender->輸出
不管哪一個環節的過濾器,每一個過濾器在匹配或是不匹配時都要明確該日誌事件的處理方式,包含三種:
全局過濾器:評估結果爲接受時,其餘全局過濾器將不會再對該事件進行評估,且再也不交給Logger過濾器評估
Logger過濾器:評估爲拒絕時再也不交給Appdener過濾器
Appdener過濾器:最終決定改日誌是否輸出
一般須要根據實際需求來配置過濾器:
下例配置列出了三種過濾器的示例(無實意義):
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="TRACE" monitorInterval="5" packages="com.kanq.extend.cat.log4j2"> <Filters> <!-- 全局級別Filter --> <BurstFilter level="INFO" rate="16" maxBurst="100"/> </Filters> <Appenders> <RollingFile name="RollingFile" fileName="logs/app.log" filePattern="logs/app-%d{MM-dd-yyyy}.log.gz"> <!-- Appender級別的Filter --> <BurstFilter level="INFO" rate="16" maxBurst="100"/> <PatternLayout> <pattern>%d %p %c{1.} [%t] %m%n</pattern> </PatternLayout> <TimeBasedTriggeringPolicy /> </RollingFile> </Appenders> <Loggers> <!-- Logger級別的Filter --> <Root level="error"> <BurstFilter level="INFO" rate="16" maxBurst="100"/> <AppenderRef ref="RollingFile"/> </Root> </Loggers> </Configuration>
經過時間過濾器實現將白天和夜晚的是指寫入不一樣位置:
<Configuration status="WARN"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </Console> <File name="DayAppender" fileName="logs/appDay.log" append="true"> <TimeFilter start="06:00:00" end="24:00:00" onMatch="ACCEPT" onMismatch="DENY"/> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger - %msg%n"/> </File> <File name="NightAppender" fileName="logs/appNight.log" append="true"> <TimeFilter start="24:00:00" end="06:00:00" onMatch="ACCEPT" onMismatch="DENY"/> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger - %msg%n"/> </File> </Appenders> <Loggers> <Root level="all"> <AppenderRef ref="Console" /> <AppenderRef ref="DayAppender" /> <AppenderRef ref="NightAppender" /> </Root> </Loggers> </Configuration>
固然官網還有其餘的過濾器,如正則過濾等,你們根據需求選擇便可;地址:官方手冊
web環境下須要額外的依賴包:
<!-- web容器中須要添加log4j-web --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-web</artifactId> <version>2.5</version> </dependency>
controller中的使用:
@Controller @RequestMapping("/customer") public class CustomerController { //爲controller添加屬性 用於獲取一個日誌記錄器(Logger) private Logger logger = LogManager.getLogger(this.getClass().getPackage().getName()); @RequestMapping("/list") public String getCustomerList(Model model, SearchInfo searchInfo){ logger.info("request this /list interface"); //... } }
若配置文件名稱不是默認的跨域經過如下代碼來加載:
File file = new File("/Users/jerry/LOGfj/src/main/resources/log4j3.xml"); BufferedInputStream in = new BufferedInputStream(new FileInputStream(file)); ConfigurationSource source = new ConfigurationSource(in); Configurator.initialize(null, source);