標籤:
log4j入門(轉)Log4j實在是很熟悉,幾乎所有的Java項目都用它啊。但是我確一直沒有搞明白。終於有一天我受不了了,定下心去看了一把文檔,才兩個小時,我終於搞明白了。一般情況下Log4j總是和Apache Commons-logging一起用的,我也就一起介紹吧。多了個東西不是更麻煩,而是更簡單!在Log4J中存在幾個概念首先介紹一下,最最重要的兩個是Logger和Appender(請參考Log4J手冊),其實是繼承層次以及輸出控制。首先Log4J中總是存在一個rootLogger,即使沒有顯示配置也是存在的,並且預設輸出層級為DEBUG。其它的logger都繼承自這個rootLogger(如果其他logger未單獨定義其輸出層級)。Log4J中的層次是用‘.‘來分隔的,如log4j.logger.com.example.test,這裡並不是說log4j.logger後面一定是具體的包名乃至類名,這個名稱可以自訂,我們甚至可以定義一個log4j.logger.A.B.C, 在com.example.test中的類裡取名稱為A.B的logger,如Logger logger = Logger.getLogger("A.B")上例中我們建立了3個logger執行個體,它們分別是"A"、"A.B"、"A.B.C"。每次我們在系統中取得logger時,並不是建立執行個體,這些執行個體是系統啟動的時候就按照設定檔初始化好的(也可能時第一次引用的時候建立的,然後緩衝其執行個體供以後使用,這部分還沒有時間研究)。限制appender疊加性例1:log4j.rootLogger=DEBUG, Consolelog4j.logger.A=DEBUG, Consolelog4j.logger.A.B=INFO, Console對於logger A.B輸出的任何日誌會往控制台輸出三次,原因是A.B繼承A的以及A的父logger的所有appender,這種繼承關係僅僅是把父logger的appender添加到自己的appender列表中,父logger的輸出level不會影響子logger的輸出。例2:限制appender疊加log4j.rootLogger=DEBUG, Consolelog4j.logger.A=DEBUG, Consolelog4j.logger.A.B=INFO, Consolelog4j.additivity.A.B=falselogger A.B的日誌僅會輸出到自己Console中,不會繼承任何父logger的appender。控制appender的輸出層級若想對輸出到appender中的記錄層級進行限制的話,就需要用到threshold來控制。log4j.threshold=ERROR 用來控制所有的appender,即輸出到所有appender的日誌,不管原來是什麼層級的,都不能低於threshold所規定的層級。log4j.appender.Console.threshold=ERROR 用來控制指定的appender的輸出層級。Log4j的簡單思想Log4j真的很簡單,簡單到令人髮指的地步。不是要記錄日誌嗎?那就給你一個Log,然後你用Log來寫東西就行了,先來一個完整類樣本:package test; import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory; public class Test { static Log log = LogFactory.getLog(Test.class); public void log(){ log.debug("Debug info."); log.info("Info info"); log.warn("Warn info"); log.error("Error info"); log.fatal("Fatal info"); } /** * @param args */ public static void main(String[] args) { Test test = new Test(); test.log(); }}別怕,看完這篇文章你就會覺得很簡單了。 Log4j預設把日誌資訊分為五個等級 all<debug < info < warn < error < fatal<off雖然可以自己添加等級,但是我覺得沒有必要,五個夠用了吧!你要寫入資訊的時候就把資訊歸為五個等級中的一個,然後調用相應的函數即可。 分五個等級到底有什麼用呢?日誌資訊到底寫到哪裡去了? “LogFactory.getLog(Test.class)”又是什麼意思捏?接著往下看吧!(現在用這個Logger.getLogger(Test.class)吧)Log4j的關鍵之處在於它的繼承思想。也就是一個Log可以繼承另外一個Log的屬性(輸出到哪裡,日誌等級,日誌格式等等)。怎麼繼承?Log4j是根據Log的名字來判斷繼承關係的,比如:名字為“com.zhlmmc.lib”的Log就是“com.zhlmmc.lib.log”的parent,明白了吧!Log4j還有一個rootLogger,相當於Java的Object。回過頭來看“LogFactory.getLog(Test.class)”這裡的“Test.class”事實上傳進去的是Test這個類的完整路徑(包名+類名),“test.Test”。這樣如果存在“test”這個Log那麼Test這個Log就繼承它,否則就繼承rootLogger。 那具體的Log屬性是在哪裡定義的呢? 關於logger的兩點說明用同名參數調用Logger.getLogger(String name)將返回同一個logger的引用。故可以在一個地方配置logger,在另外一個地方獲得配置好的logger,而無須相互間傳遞logger的引用。logger的建立可以按照任意的順序,即,父logger可以後於子logger被建立。log4j將自動維護logger的繼承樹。 常見的設定檔雖然可以用xml或者在運行時用Java來配置Log4j,但還是properties檔案好用啊!log4j.rootLogger=info, stdoutlog4j.appender.stdout=org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.layout=org.apache.log4j.PatternLayout# Pattern to output the caller‘s file name and line number.log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n分析一下:第一行,配置log4j.rootLogger你明白吧。應為它是根,總得配置一下,否則別的Log繼承什麼啊。其他的Log可以配置也可以不配置。等號後面的第一個參數表示記錄層級,可以填五個層級中的一種,後面的參數都是讓Log知道輸出到哪裡,如果你想讓日誌輸出到兩個地方就加兩個輸出參數,比如:log4j.rootLogger=info, stdout, file這裡的info表示,該Log的記錄層級為info,所有層級小於info的日誌都不會被記錄。比如使用這個設定檔的話,我剛開始舉的那個類中log.debug("Debug info.");這句話是不起作用的,因為debug的層級小於info。這樣就很容易控制什麼資訊在調試的時候要顯示,什麼資訊在發布的時候要去掉。這些都不用改代碼,很方便吧。 但,stdout和file又是什麼呢?接著往下看,就是配置stdout了,這個名字是隨便取的,你可以叫它A:log4j.appender.A=org.apache.log4j.ConsoleAppender那麼上面的rootLogger的參數stdout也要改成A,其他用到的地方當然也要改。這裡的關鍵不是名字,而是appender類型,比如這裡的“ConsoleAppender”,看明白了吧,輸出到Console。後面兩行都是設定日誌格式的,一般情況下你就照抄吧。既然是最簡入門關注於理解Log4j的工作原理,我就不介紹file類型的appender了,一搜一大把。在實際的項目開發中,很可能遇到所引用的包用Log4j來記錄日誌,比如Hibernate。那麼在這裡你可以很容易的控制這個包如何記錄日誌。比如在上面的設定檔中加一行:log4j.logger.org.hibernate=fatal 那麼所有org.hibernate包下面的類就只會顯示很少的資訊,因為fatal的層級最高啊。部署別怕,這可不是部署Tomcat。把log4j的包和commons-logging的包(加在一起才兩個)放到classpath下面。然後把設定檔儲存為log4j.properties,也放在classpath下面(如果用Eclipse的話,放在src目錄下即可)。然後你就可以跑了。 預設的log4j初始化過程Logger類的靜態初始化塊(static initialization block)中對log4j的環境做預設的初始化。注意:如果程式員已經通過設定系統屬性的方法來配置了log4j環境,則不需要再顯式地調用XXXConfigurator.configure()方法來配置log4j環境了。Logger的靜態初始化塊在完成初始化過程時將檢查一系列log4j定義的系統屬性。它所做的事情如下:檢查系統屬性log4j.defaultInitOverride,如果該屬性被設定為false,則執行初始化;否則(只要不是false,無論是什麼值,甚至沒有值,都是否則),跳過初始化。把系統屬性log4j.configuration的值賦給變數resource。如果該系統變數沒有被定義,則把resource賦值為"log4j.properties"。注意:在apache的log4j文檔中建議使用定義log4j.configuration系統屬性的方法來設定預設的初始設定檔案是一個好方法。試圖把resource變數轉化成為一個URL對象url。如果一般的轉化方法行不通,就調用org.apache.log4j.helpers.Loader.getResource(resource, Logger.class)方法來完成轉化。如果url以".xml"結尾,則調用方法DOMConfigurator.configure(url)來完成初始化;否則,則調用方法PropertyConfigurator.configure(url)來完成初始化。如果url指定的資源不能被獲得,則跳出初始化過程。 Log4j的編碼習慣讓每個類都擁有一個private static的Logger對象,用來輸出該類中的全部日誌資訊使用xml檔案來完成對log4j環境的配置。在項目的main class中的靜態初始化塊裡放log4j環境的配置代碼。注意:在一個項目中,log4j環境只需要被配置一次,而不是在每個使用了logger的類裡都需要調用一次用MyClass.class作為參數建立該類的靜態Logger對象
log4j入門(轉) --- 很詳細 也很簡單容易懂