Log4j源碼分析

1、slf4jlog4j的關係:

 

也就是說slf4j僅僅是一個爲Java程序提供日誌輸出的統一接口,並非一個具體的日誌實現方案,就好比JDBC同樣,只是一種規則而已。必須搭配具體的log實現方案好比說log4j jdklogging等等,中間須要適配層作橋接,例如slf4jlog4j的橋接包:slf4j-log4j12-1.6.1.jarhtml

 

2、log4j加載過程:

代碼中的用法通常以下:java

Logger myLog = LoggerFactory.getLogger(XXXX.class);\mysql

myLog.info(「this is info log text」);sql

myLog.error(「this is error log text」);數據庫

一、獲取Logger對象步驟:apache

(1) 獲取StaticLoggerBinder的單例對象;api

(2) StaticLoggerBinder對象裏有一個Log4jLoggerFactory對象,Log4jLoggerFactory對象裏面有一個存儲了Logger對象的hash表:app

loggerMap = new ConcurrentHashMap<String, Logger>()框架

 

(3) getLogger(XXXX.class)時首先查這個hash表,若是查詢到則直接返回,不然建立Log4jLoggerAdapter對象並添加到這個hash表中;函數

 

二、日誌記錄:

(1) Log4jLoggerAdapter對象做爲Logger對象的代理對象,全部記錄日誌的info, error等方法都是傳遞到Logger對象去執行處理的;

 

3、Log4j配置文件解析過程:

Log4jLoggerFactory在構造函數中會調用LogManager的getRootLogger方法,LogManager的靜態初始方法塊中會檢查配置文件並加載,能夠是指定的Class類,也能夠是xml格式配置文件,也能夠是properties格式的配置文件;對於properties格式的配置文件,使用PropertyConfigurator類來讀取和解析配置信息;

Properties格式的log4j的配置文件說明:

#Log4J配置文件實現了輸出到控制檯、文件、回滾文件、自定義標籤,數據庫等功能。僅供參考。  

log4j.rootLogger=DEBUG,CONSOLE,FILE,DLOGFILE,ROLLING_FILE,MYSQL_LOG  

log4j.addivity.org.apache=true  

  

#應用於控制檯  

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender  

log4j.appender.CONSOLE.Threshold=DEBUG  

log4j.appender.CONSOLE.Target=System.out  

log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout  

log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyyMMdd-HH:mm:ss} %t %c %m%n  

  

#應用於文件  

log4j.appender.FILE=org.apache.log4j.FileAppender  

log4j.appender.FILE.File=d:\\file.log  

log4j.appender.FILE.Append=false  

log4j.appender.FILE.layout=org.apache.log4j.PatternLayout  

log4j.appender.FILE.layout.ConversionPattern=%d{yyyyMMdd-HH:mm:ss} %t %c %m%n  

  

#應用於按日期生成文件  

log4j.appender.DLOGFILE=org.apache.log4j.DailyRollingFileAppender  

log4j.appender.DLOGFILE.File=d:\\test.log  

log4j.appender.DLOGFILE.Threshold=INFO  

log4j.appender.DLOGFILE.DatePattern='.'yyyy-MM-dd  

log4j.appender.DLOGFILE.layout=org.apache.log4j.PatternLayout  

log4j.appender.DLOGFILE.layout.ConversionPattern=%d{yyyyMMdd-HH:mm:ss} %t %c %m%n  

  

#應用於文件回滾  

log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender  

log4j.appender.ROLLING_FILE.Threshold=INFO  

log4j.appender.ROLLING_FILE.File=d:\\rolling.log  

log4j.appender.ROLLING_FILE.Append=true  

log4j.appender.ROLLING_FILE.MaxFileSize=1KB  

log4j.appender.ROLLING_FILE.MaxBackupIndex=1  

log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout  

log4j.appender.ROLLING_FILE.layout.ConversionPattern=%d{yyyyMMdd-HH:mm:ss} %t %c %m%n  

  

# 數據庫輸出  

log4j.appender.MYSQL_LOG=org.apache.log4j.jdbc.JDBCAppender  

log4j.appender.MYSQL_LOG.driver=com.mysql.jdbc.Driver  

log4j.appender.MYSQL_LOG.URL=jdbc:mysql://127.0.0.1:3306/txl  

log4j.appender.MYSQL_LOG.Threshold=ERROR  

log4j.appender.MYSQL_LOG.user=root  

log4j.appender.MYSQL_LOG.password=  

log4j.appender.MYSQL_LOG.sql=insert into log_monitor(level,category,thread,time,location,note) values('%p','%c','%t','%d{yyyy-MM-dd HH:mm:ss:SSS}','%l','%m')  

log4j.appender.MYSQL_LOG.layout=org.apache.log4j.PatternLayout  

#雖然以上佈局 沒啥效果,可是能夠減小告警提示  

  

#自定義Appender ,輸出到任意地方  

 

4、Log4j組件:

1.Logger:

繼承Category(一種日誌類),提供不一樣級別的日誌接口(例:logger.infologger.error等);當調用方調用了info, error等方法記錄日誌時,調用的是Log4jLoggerAdapter的方法,而後Log4jLoggerAdapter又將調用轉給Logger對象去執行;

 

2.Appender:

appender就是日誌輸出地;日誌的記錄輸出抽象,大體有控制檯輸出,文件輸出等;

Logger對象在記錄日誌時,會遍歷Logger對象上註冊的全部Appender以及父類上註冊的Appender,而後依次調用全部AppenderappendLoopOnAppenders方法記錄日誌;

主要實現類有WriteAppenderConsoleAppenderFileAppenderWriterAppender將日誌寫入Java IO中,它繼承自SkeletonAppender類。它引入了三個字段:immediateFlush,指定每寫完一條日誌後,即將日誌內容刷新到設備中,於是通常推薦將該值設置爲true,即默認值;econding用於定義日誌文本的編碼方式;qw定義寫日誌的writer,它能夠是文件或是控制檯等Java IO支持的流;

FileAppender的子類主要有DailyRollingFileAppenderRollingFileAppenderDailyRollingFileAppender會在每隔一段時間能夠生成一個新的日誌文件,不過這個時間間隔是能夠設置的,不只僅只是每隔一天。時間間隔經過setDatePattern()方法設置,datePattern必須遵循SimpleDateFormat中的格式;RollingFileAppender則是基於文件大小做爲閥值。當日志文件超過指定大小,日誌文件會被重命名成」日誌文件名.1」,若此文件已經存在,則將此文件重命名成」日誌文件名.2」,一次類推。若文件數已經超過設置的可備份日誌文件最大個數,則將最舊的日誌文件刪除。若是要設置不刪除任何日誌文件,能夠將maxBackupIndex設置成Integer最大值。

 

3.Layout:

實現了OptionHandler的抽象類;主要是對日誌行的格式進行限定,經常使用有PatternLayoutHTMLLayout

 

4.LoggerRepository

常見的Hirearchy爲其實現類,封裝了框架的默認配置,還有Logger工廠,事件源,封裝了一些列事件。

 

5.LoggingEvent

封裝了消息內容、級別、記錄器類名的全名稱等信息;當記錄日誌時,會將日誌內容封裝成LoggingEvent對象並調用Logger對象進行記錄;

 

5、流程圖:

一、調用方調用LoggerFactory.getLogger(XXXX.class)時,首先獲取具體日誌實現框架的LoggerFactoryLog4jLoggerFactory,在Log4jLoggerFactory.getLogger(XXXX.class)時,首先從hashMap裏面去獲取,若是獲取不到則建立,建立時首先獲取getLoggerRepository(也就是Hierarchy),而後在HierarchyhashMap裏面去獲取,若是找到則直接返回,不然建立新的Logger對象並添加到hashMap裏面後返回;

二、記錄日誌時調用的info, debug, error等方法都是調用的適配器對象Log4jLoggerAdapter裏面的方法,Log4jLoggerAdapter會將調用轉到Logger對象上;接着判斷Logger實例對應的日誌記錄級別(每一個Logger實例都有本身的Level)是否要比請求的級別低→如果則調用forcedLog記錄日誌;

三、接着建立LoggingEvent實例→將LoggingEvent實例傳遞給appenderAppender調用Layout實例格式化日誌消息;最後Appender將格式化後的日誌信息寫入改Appender對應的日誌輸出中。

 

6、相關問題:

1.如何實現log4j和slf4j的解耦:也即如何實現將log4j的實現綁定到slf4j的接口定義上?

LoggerFactory的綁定:

LoggerFactory是一個定義在slf4j-api中的類,其getLogger經過StaticLoggerBinder的單實例對象獲取到ILoggerFactory對象,StaticLoggerBinder是在slf4j-log4j插件裏面定義的;最後獲取Logger對象是在LogManager中建立Logger對象並返回的,LogManager和Logger對象都是在實現jar包log4j裏面實現的;

 

2.Appender是如何註冊到Logger上的?

PropertyConfigurator類的parseCategory方法解析配置文件log4j.properties的代碼:

void parseCategory(Properties props, Logger logger, String optionKey,

     String loggerName, String value) {

...................

 

    // Begin by removing all existing appenders.

    logger.removeAllAppenders();

 

    Appender appender;

    String appenderName;

    while(st.hasMoreTokens()) {

      appenderName = st.nextToken().trim();

      if(appenderName == null || appenderName.equals(","))

continue;

      LogLog.debug("Parsing appender named \"" + appenderName +"\".");

      appender = parseAppender(props, appenderName);

      if(appender != null) {

logger.addAppender(appender);

      }

    }

  }

LogManager的靜態代碼中檢測到配置文件log4j.properties的路徑並加載這個配置文件,而後執行parseCategory方法解析配置文件;上面加粗部分,parseAppender會根據log4j.properties配置文件生成appender對象,而後將其添加到logger對象上;

 

7、參考資料:

https://my.oschina.net/xianggao/blog/518059

https://www.cnblogs.com/zeng-wei/archive/2012/08/28/2660363.html

https://blog.csdn.net/m0_37652164/article/details/80487522

https://blog.csdn.net/u011794238/article/details/50736331/

http://wiki.10101111.com/pages/viewpage.action?pageId=190240215

 

http://www.cnblogs.com/question-sky/p/7425069.html

http://www.cnblogs.com/question-sky/p/7429548.html

http://www.cnblogs.com/question-sky/p/7469596.html

http://www.javashuo.com/article/p-faqefoxc-hy.html

 

http://www.blogjava.net/DLevin/archive/2012/06/28/381667.html

http://www.blogjava.net/DLevin/archive/2012/11/04/390755.html

相關文章
相關標籤/搜索