Log4j 2的好處就不和你們說了,若是你搜了2,說明你對他已經有必定的瞭解,而且想用它,因此這裏直接就上手了。html
1. 去官方下載log4j 2,導入jar包,基本上你只須要導入下面兩個jar包就能夠了(xx是亂七八糟的版本號):java
log4j-core-xx.jar程序員
log4j-api-xx.jarapache
2. 導入到你的項目中:這個就不說了。api
3. 開始使用:app
咱們知道,要在某個類中使用log4j記錄日誌,只須要申明下面的成員變量(其實不必定要是成員變量,只是爲了方便調用而已)eclipse
private static Logger logger = LogManager.getLogger(MyApp.class.getName());
這裏getLogger有一個參數指定的是這個logger的名稱,這個名稱在配置文件裏面但是有須要的,這個待會兒再說。ide
聲明瞭Logger對象,咱們就能夠在代碼中使用他了。測試
4. 日誌的級別:idea
咱們如今要調用logger的方法,不過在這個Logger對象中,有不少方法,因此要先了解log4j的日誌級別,log4j規定了默認的幾個級別:trace<debug<info<warn<error<fatal等。這裏要說明一下:
1)級別之間是包含的關係,意思是若是你設置日誌級別是trace,則大於等於這個級別的日誌都會輸出。
2)基本上默認的級別沒多大區別,就是一個默認的設定。你能夠經過它的API本身定義級別。你也能夠隨意調用這些方法,不過你要在配置文件裏面好好處理了,不然就起不到日誌的做用了,並且也不易讀,至關於一個規範,你要徹底定義一套也能夠,不用沒多大必要。
3)這不一樣的級別的含義你們都很容易理解,這裏就簡單介紹一下:
trace: 是追蹤,就是程序推動如下,你就能夠寫個trace輸出,因此trace應該會特別多,不過不要緊,咱們能夠設置最低日誌級別不讓他輸出。
debug: 調試麼,我通常就只用這個做爲最低級別,trace壓根不用。是在沒辦法就用eclipse或者idea的debug功能就行了麼。
info: 輸出一下你感興趣的或者重要的信息,這個用的最多了。
warn: 有些信息不是錯誤信息,可是也要給程序員的一些提示,相似於eclipse中代碼的驗證不是有error 和warn(不算錯誤可是也請注意,好比如下depressed的方法)。
error: 錯誤信息。用的也比較多。
fatal: 級別比較高了。重大錯誤,這種級別你能夠直接中止程序了,是不該該出現的錯誤麼!不用那麼緊張,其實就是一個程度的問題。
5. 日誌調用:
這裏隨便寫個類,調用就是這麼簡單,log4j的核心在配置文件上。
import org.apache.logging.log4j.Level;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;public class Hello { static Logger logger = LogManager.getLogger(Hello.class.getName()); public boolean hello() { logger.entry(); //trace級別的信息,單獨列出來是但願你在某個方法或者程序邏輯開始的時候調用,和logger.trace("entry")基本一個意思 logger.error("Did it again!"); //error級別的信息,參數就是你輸出的信息 logger.info("我是info信息"); //info級別的信息 logger.debug("我是debug信息"); logger.warn("我是warn信息"); logger.fatal("我是fatal信息"); logger.log(Level.DEBUG, "我是debug信息"); //這個就是制定Level類型的調用:誰閒着沒事調用這個,也不必定哦! logger.exit(); //和entry()對應的結束方法,和logger.trace("exit");一個意思 return false; } }
若是沒有自定義配置文件,上面這個類在寫一個main方法,控制檯會輸入下面的樣子:
19:09:40.256 [main] ERROR cn.lsw.base.log4j2.Hello - Did it again!19:09:40.260 [main] FATAL cn.lsw.base.log4j2.Hello - 我是fatal信息
看到沒,只有>=ERROR的日誌輸出來了(這是由於Log4j有一個默認的配置,它的日誌級別是ERROR,輸出只有控制檯)。若是我已經定義好了日誌,我把日誌級別改爲了TRACE,輸出會變成下面這樣:
19:11:36.941 TRACE cn.lsw.base.log4j2.Hello 12 hello - entry19:11:36.951 ERROR cn.lsw.base.log4j2.Hello 13 hello - Did it again!19:11:36.951 INFO cn.lsw.base.log4j2.Hello 14 hello - 我是info信息19:11:36.951 DEBUG cn.lsw.base.log4j2.Hello 15 hello - 我是debug信息19:11:36.951 WARN cn.lsw.base.log4j2.Hello 16 hello - 我是warn信息19:11:36.952 FATAL cn.lsw.base.log4j2.Hello 17 hello - 我是fatal信息19:11:36.952 DEBUG cn.lsw.base.log4j2.Hello 18 hello - 我是debug信息19:11:36.952 TRACE cn.lsw.base.log4j2.Hello 19 hello - exit
全部的日誌都打印出來了,你們能夠對照上面的代碼看一看。
6. 配置文件:
如今開始正題了。
原本覺得Log4J 2應該有一個默認的配置文件的,不過好像沒有找到,下面這個配置文件等同於缺省配置(from http://blog.csdn.net/welcome000yy/article/details/7962668):
<?xml version="1.0" encoding="UTF-8"?> <configuration status="OFF"> <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="error"> <appender-ref ref="Console"/> </root> </loggers> </configuration>
而咱們只要把configuration>loggers>root的level屬性改成trace,就能夠輸出剛纔寫的全部信息了。相信用過Log4j的人對這個配置文件也不算陌生,Log4J傳統的配置一直是.properties文件,鍵值對的形式,那種配置方式很很差看,可是基本上咱們從這個配置文件也能看到Log4J 1的影子,無非是appender了,layout之類的,含義也基本同樣的。
這裏不許備仔細的講配置文件,沒什麼必要,你們只要知道一些基本的配置就能夠了。我這裏寫幾個配置文件,而且給了必定的註釋和講解,基本上能夠用了。
第一個例子:
<?xml version="1.0" encoding="UTF-8"?><configuration status="OFF"> <appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </Console> </appenders> <loggers> <!--咱們只讓這個logger輸出trace信息,其餘的都是error級別--> <!-- additivity開啓的話,因爲這個logger也是知足root的,因此會被打印兩遍。 不過root logger 的level是error,爲何Bar 裏面的trace信息也被打印兩遍呢 --> <logger name="cn.lsw.base.log4j2.Hello" level="trace" additivity="false"> <appender-ref ref="Console"/> </logger> <root level="error"> <appender-ref ref="Console"/> </root> </loggers></configuration>
先簡單介紹一下下面這個配置文件。
1)根節點configuration,而後有兩個子節點:appenders和loggers(都是複數,意思就是能夠定義不少個appender和logger了)(若是想詳細的看一下這個xml的結構,能夠去jar包下面去找xsd文件和dtd文件)
2)appenders:這個下面定義的是各個appender,就是輸出了,有好多類別,這裏也很少說(容易形成理解和解釋上的壓力,一開始也未必能聽懂,等於白講),先看這個例子,只有一個Console,這些節點可不是隨便命名的,Console就是輸出控制檯的意思。而後就針對這個輸出設置一些屬性,這裏設置了PatternLayout就是輸出格式了,基本上是前面時間,線程,級別,logger名稱,log信息等,差很少,能夠本身去查他們的語法規則。
3)loggers下面會定義許多個logger,這些logger經過name進行區分,來對不一樣的logger配置不一樣的輸出,方法是經過引用上面定義的logger,注意,appender-ref引用的值是上面每一個appender的name,而不是節點名稱。
這個例子爲了說明什麼呢?咱們要說說這個logger的name(名稱)了(前面有提到)。
7. name的機制:(能夠參考: http://logging.apache.org/log4j/2.x/manual/architecture.html)
咱們這裏看到了配置文件裏面是name很重要,沒錯,這個name可不能隨便起(其實能夠隨便起)。這個機制意思很簡單。就是相似於java package同樣,好比咱們的一個包:cn.lsw.base.log4j2。並且,能夠發現咱們前面生成Logger對象的時候,命名都是經過 Hello.class.getName(); 這樣的方法,爲何要這樣呢? 很簡單,由於有所謂的Logger 繼承的問題。好比 若是你給cn.lsw.base定義了一個logger,那麼他也適用於cn.lsw.base.lgo4j2這個logger。名稱的繼承是經過點(.)分隔的。而後你能夠猜想上面loggers裏面有一個子節點不是logger而是root,並且這個root沒有name屬性。這個root至關於根節點。你全部的logger都適用與這個logger,因此,即便你在不少類裏面經過 類名.class.getName() 獲得不少的logger,並且沒有在配置文件的loggers下面作配置,他們也都可以輸出,由於他們都繼承了root的log配置。
咱們上面的這個配置文件裏面還定義了一個logger,他的名稱是 cn.lsw.base.log4j2.Hello ,這個名稱其實就是經過前面的Hello.class.getName(); 獲得的,咱們爲了給他單獨作配置,這裏就生成對於這個類的logger,上面的配置基本的意思是隻有cn.lsw.base.log4j2.Hello 這個logger輸出trace信息,也就是他的日誌級別是trace,其餘的logger則繼承root的日誌配置,日誌級別是error,只能打印出ERROR及以上級別的日誌。若是這裏logger 的name屬性改爲cn.lsw.base,則這個包下面的全部logger都會繼承這個log配置(這裏的包是log4j的logger name的「包」的含義,不是java的包,你非要給Hello生成一個名稱爲「myhello」的logger,他也就無法繼承cn.lsw.base這個配置了。
那有人就要問了,他不是也應該繼承了root的配置了麼,那麼會不會輸出兩遍呢?咱們在配置文件中給瞭解釋,若是你設置了additivity="false",就不會輸出兩遍,不然,看下面的輸出:
這裏要在加入一個類作對比:
import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;public class Test { private static Logger logger = LogManager.getLogger(Test.class.getName()); public static void main(String[] args) { logger.trace("開始程序."); Hello hello= new Hello();// for (int i = 0; i < 10000;i++){ if (!hello.hello()) { logger.error("hello"); }// } logger.trace("退出程序."); } }
這裏先把配置文件改一下方便對照,一個是剛纔第一個logger的名稱仍是cn.lsw.base.log4j2.Hello,additivity去掉或改成true(由於默認是true,因此能夠去掉),第二是把root的level改成info方便觀察。
而後運行Test,看控制檯的日誌輸出:
2013-12-20 19:59:42.538 [main] INFO cn.lsw.base.log4j2.Test - test2013-12-20 19:59:42.541 [main] TRACE cn.lsw.base.log4j2.Hello - entry2013-12-20 19:59:42.541 [main] TRACE cn.lsw.base.log4j2.Hello - entry2013-12-20 19:59:42.542 [main] ERROR cn.lsw.base.log4j2.Hello - Did it again!2013-12-20 19:59:42.542 [main] ERROR cn.lsw.base.log4j2.Hello - Did it again!2013-12-20 19:59:42.542 [main] INFO cn.lsw.base.log4j2.Hello - 我是info信息2013-12-20 19:59:42.542 [main] INFO cn.lsw.base.log4j2.Hello - 我是info信息2013-12-20 19:59:42.542 [main] DEBUG cn.lsw.base.log4j2.Hello - 我是debug信息2013-12-20 19:59:42.542 [main] DEBUG cn.lsw.base.log4j2.Hello - 我是debug信息2013-12-20 19:59:42.542 [main] WARN cn.lsw.base.log4j2.Hello - 我是warn信息2013-12-20 19:59:42.542 [main] WARN cn.lsw.base.log4j2.Hello - 我是warn信息2013-12-20 19:59:42.542 [main] FATAL cn.lsw.base.log4j2.Hello - 我是fatal信息2013-12-20 19:59:42.542 [main] FATAL cn.lsw.base.log4j2.Hello - 我是fatal信息2013-12-20 19:59:42.542 [main] DEBUG cn.lsw.base.log4j2.Hello - 我是debug信息2013-12-20 19:59:42.542 [main] DEBUG cn.lsw.base.log4j2.Hello - 我是debug信息2013-12-20 19:59:42.543 [main] TRACE cn.lsw.base.log4j2.Hello - exit2013-12-20 19:59:42.543 [main] TRACE cn.lsw.base.log4j2.Hello - exit2013-12-20 19:59:42.543 [main] ERROR cn.lsw.base.log4j2.Test - hello
能夠看出,Test的trace日誌沒有輸出,由於他繼承了root的日誌配置,只輸出info即以上級別的日誌。Hello 輸出了trace及以上級別的日誌,可是每一個都輸出了兩遍。你能夠試一下,把第一個logger的level該爲error,那麼error以上的級別也是輸出兩遍。這時候,只要加上additivity爲false就能夠避免這個問題了。
固然,你能夠爲每一個logger 都在配置文件下面作不一樣的配置,也能夠經過繼承機制,對不一樣包下面的日誌作不一樣的配置。由於loggers下面能夠寫不少歌logger。
下面在看一個稍微複雜的例子:
<?xml version="1.0" encoding="UTF-8"?><configuration status="error"> <!--先定義全部的appender--> <appenders> <!--這個輸出控制檯的配置--> <Console name="Console" target="SYSTEM_OUT"> <!--控制檯只輸出level及以上級別的信息(onMatch),其餘的直接拒絕(onMismatch)--> <ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="DENY"/> <!--這個都知道是輸出日誌的格式--> <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/> </Console> <!--文件會打印出全部信息,這個log每次運行程序會自動清空,由append屬性決定,這個也挺有用的,適合臨時測試用--> <File name="log" fileName="log/test.log" append="false"> <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/> </File> <!--這個會打印出全部的信息,每次大小超過size,則這size大小的日誌會自動存入按年份-月份創建的文件夾下面並進行壓縮,做爲存檔--> <RollingFile name="RollingFile" fileName="logs/app.log" filePattern="log/$${date:yyyy-MM}/app-%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="50MB"/> </RollingFile> </appenders> <!--而後定義logger,只有定義了logger並引入的appender,appender纔會生效--> <loggers> <!--創建一個默認的root的logger--> <root level="trace"> <appender-ref ref="RollingFile"/> <appender-ref ref="Console"/> </root> </loggers></configuration>
說複雜,其實也不復雜,這一個例子主要是爲了講一下appenders。
這裏定義了三個appender,Console,File,RollingFile,看意思基本也明白,第二個是寫入文件,第三個是「循環」的日誌文件,意思是日誌文件大於閥值的時候,就開始寫一個新的日誌文件。
這裏咱們的配置文件裏面的註釋算比較詳細的了。因此就你們本身看了。有一個比較有意思的是ThresholdFilter ,一個過濾器,其實每一個appender能夠定義不少個filter,這個功能頗有用。若是你要選擇控制檯只能輸出ERROR以上的類別,你就用ThresholdFilter,把level設置成ERROR,onMatch="ACCEPT" onMismatch="DENY" 的意思是匹配就接受,不然直接拒絕,固然有其餘選擇了,好比交給其餘的過濾器去處理了之類的,詳情你們本身去琢磨吧。
爲何要加一個這樣的配置文件呢?其實這個配置文件我感受挺好的,他的實用性就在下面:
8. 一個實用的配置文件:
咱們用日誌一方面是爲了記錄程序運行的信息,在出錯的時候排查之類的,有時候調試的時候也喜歡用日誌。因此,日誌若是記錄的很亂的話,看起來也不方便。因此我可能有下面一些需求:
1)我正在調試某個類,因此,我不想讓其餘的類或者包的日誌輸出,不然會不少內容,因此,你能夠修改上面root的級別爲最高(或者謹慎起見就用ERROR),而後,加一個針對該類的logger配置,好比第一個配置文件中的設置,把他的level設置trace或者debug之類的,而後咱們給一個appender-ref是定義的File那個appender(共三個appender,還記得嗎),這個appender的好處是有一個append爲false的屬性,這樣,每次運行都會清空上次的日誌,這樣就不會由於一直在調試而增長這個文件的內容,查起來也方便,這個和輸出到控制檯就一個效果了。
2)我已經基本上部署好程序了,而後我要長時間運行了。我須要記錄下面幾種日誌,第一,控制檯輸出全部的error級別以上的信息。第二,我要有一個文件輸出是全部的debug或者info以上的信息,相似作程序記錄什麼的。第三,我要單獨爲ERROR以上的信息輸出到單獨的文件,若是出了錯,只查這個配置文件就行了,不會去處理太多的日誌,看起來頭都大了。怎麼作呢,很簡單。
>首先,在appenders下面加一個Console類型的appender,經過加一個ThresholdFilter設置level爲error。(直接在配置文件的Console這個appender中修改)
>其次,增長一個File類型的appender(也能夠是RollingFile或者其餘文件輸出類型),而後經過設置ThresholdFilter的level爲error,設置成File好在,你的error日誌應該不會那麼多,不須要有多個error級別日誌文件的存在,不然你的程序基本上能夠重寫了。
這裏能夠添加一個appender,內容以下:
<File name="ERROR" fileName="logs/error.log"> <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/> <PatternLayout pattern="%d{yyyy.MM.dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/> </File>
並在loggers中的某個logger(如root)中引用(root節點加入這一行做爲子節點)。
<appender-ref ref="ERROR" />
>而後,增長一個RollingFile的appender,設置基本上同上面的那個配置文件。
>最後,在logger中進行相應的配置。不過若是你的logger中也有日誌級別的配置,若是級別都在error以上,你的appender裏面也就不會輸出error一下的信息了。
還記得上面的Test類裏面有一個被註釋掉的for循環麼?這個是爲了作配置文件中RollingFile那個appender的配置的,取消註釋,運行商一次或幾回,看你的輸出配置文件的地方,他是怎麼「RollingFile」的,這裏給個我測試的截圖:(這裏你能夠把 <SizeBasedTriggeringPolicy size="50MB"/>這裏的size改爲2MB,要生成50MB的日誌仍是比較慢的。爲了方便觀察麼!而後把Console的ThresholdFilter的level設置成error這樣的較高級別,否則控制檯輸出東西太多了)
第一部分(圖中標識爲1),是我加入的jar包;
第二部分是File這個appender生成的日誌文件,你會發現你運行不少次,這個文件中的日誌是被覆蓋的。
第三部分是RollingFile 這個appender生成的配置文件,能夠發現,默認創建的是app.log這個日誌,每次超過2MB的時候,就會生成對應年-月的文件夾,和制定命名格式的log文件,並且是壓縮成gz格式文件,打開資源管理器發現這個文件只有11KB,解壓後就是2MB。
最後,但願這個教程可以幫到你們!