也就是說slf4j僅僅是一個爲Java程序提供日誌輸出的統一接口,並非一個具體的日誌實現方案,就好比JDBC同樣,只是一種規則而已。必須搭配具體的log實現方案好比說log4j jdklogging等等,中間須要適配層作橋接,例如slf4j與log4j的橋接包:slf4j-log4j12-1.6.1.jar。html
代碼中的用法通常以下: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對象去執行處理的;
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 ,輸出到任意地方 |
1.Logger:
繼承Category(一種日誌類),提供不一樣級別的日誌接口(例:logger.info,logger.error等);當調用方調用了info, error等方法記錄日誌時,調用的是Log4jLoggerAdapter的方法,而後Log4jLoggerAdapter又將調用轉給Logger對象去執行;
2.Appender:
appender就是日誌輸出地;日誌的記錄輸出抽象,大體有控制檯輸出,文件輸出等;
Logger對象在記錄日誌時,會遍歷Logger對象上註冊的全部Appender以及父類上註冊的Appender,而後依次調用全部Appender的appendLoopOnAppenders方法記錄日誌;
主要實現類有WriteAppender,ConsoleAppender,FileAppender;WriterAppender將日誌寫入Java IO中,它繼承自SkeletonAppender類。它引入了三個字段:immediateFlush,指定每寫完一條日誌後,即將日誌內容刷新到設備中,於是通常推薦將該值設置爲true,即默認值;econding用於定義日誌文本的編碼方式;qw定義寫日誌的writer,它能夠是文件或是控制檯等Java IO支持的流;
FileAppender的子類主要有DailyRollingFileAppender和RollingFileAppender:DailyRollingFileAppender會在每隔一段時間能夠生成一個新的日誌文件,不過這個時間間隔是能夠設置的,不只僅只是每隔一天。時間間隔經過setDatePattern()方法設置,datePattern必須遵循SimpleDateFormat中的格式;RollingFileAppender則是基於文件大小做爲閥值。當日志文件超過指定大小,日誌文件會被重命名成」日誌文件名.1」,若此文件已經存在,則將此文件重命名成」日誌文件名.2」,一次類推。若文件數已經超過設置的可備份日誌文件最大個數,則將最舊的日誌文件刪除。若是要設置不刪除任何日誌文件,能夠將maxBackupIndex設置成Integer最大值。
3.Layout:
實現了OptionHandler的抽象類;主要是對日誌行的格式進行限定,經常使用有PatternLayout和HTMLLayout;
4.LoggerRepository:
常見的Hirearchy爲其實現類,封裝了框架的默認配置,還有Logger工廠,事件源,封裝了一些列事件。
5.LoggingEvent:
封裝了消息內容、級別、記錄器類名的全名稱等信息;當記錄日誌時,會將日誌內容封裝成LoggingEvent對象並調用Logger對象進行記錄;
一、調用方調用LoggerFactory.getLogger(XXXX.class)時,首先獲取具體日誌實現框架的LoggerFactory類Log4jLoggerFactory,在Log4jLoggerFactory.getLogger(XXXX.class)時,首先從hashMap裏面去獲取,若是獲取不到則建立,建立時首先獲取getLoggerRepository(也就是Hierarchy),而後在Hierarchy的hashMap裏面去獲取,若是找到則直接返回,不然建立新的Logger對象並添加到hashMap裏面後返回;
二、記錄日誌時調用的info, debug, error等方法都是調用的適配器對象Log4jLoggerAdapter裏面的方法,Log4jLoggerAdapter會將調用轉到Logger對象上;接着判斷Logger實例對應的日誌記錄級別(每一個Logger實例都有本身的Level)是否要比請求的級別低→如果則調用forcedLog記錄日誌;
三、接着建立LoggingEvent實例→將LoggingEvent實例傳遞給appender,Appender調用Layout實例格式化日誌消息;最後Appender將格式化後的日誌信息寫入改Appender對應的日誌輸出中。
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對象上;
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