Log4J是Apache的一個開放源代碼項目(http://logging.apache.org/log4j/docs/),它是一個日志操作包。通過使用Log4J,可以指定日志信息輸出的目的地,控制每一條日志的輸出格式,定義日志信息的級別。所有這些功能通過一個配置文件靈活進行配置。

一、LOG4J組成

    LOG4J主要由三大組件組成:
    . Logger: 決定什么日志信息應該被輸出、什么日志信息應該被忽略;
    . Appender: 指定日志信息應該輸出到什么地方, 這些地方可以是控制臺、文件、網絡設備;
    . Layout: 指定日志信息的輸出格式;

    一個Logger可以有多個Appender,也就是說日志信息可以同時輸出到多個設備上,每個Appender對應
    一種Layout(示例見下圖)。

              ↗  Appender1  →  Layout
     /     
    Logger
     ﹨  
              ↘  Appender2  →  Layout


二、Logger組件

    1. Logger組件提供的方法:

       Logger組件是LOG4J的核心組件,它代表了Log4J的日志記錄器,它能夠對日志信息進行分類篩選。它由org.apache.log4j.Logger類實現,提供了如下方法:

 

java 代碼
  1. package org.apache.log4j;   
  2.   
  3. public class Logger {   
  4.   
  5.            // Creation & retrieval methods:   
  6.            public static Logger getRootLogger();   
  7.            public static Logger getLogger(String name);   
  8.   
  9.            // printing methods:   
  10.            public void debug(Object message);   
  11.            public void info(Object message);   
  12.            public void warn(Object message);   
  13.            public void error(Object message);   
  14.            public void fatal(Object message);   
  15.       
  16.            // generic printing method:   
  17.            public void log(Priority p, Object message);   
  18. }   

    2. 在配置文件中配置Logger組件

       可在Log4J配置文件中配置自己的Logger組件,示例:

       log4j.logger.myLogger=WARN

       以上代碼定義了一個Logger組件,名稱為myLogger,日志級別為WARN。
  
    3. 日志級別種類:

       一共有五種,級別由高到低依次是:fatal、error、warn、info、debug。獲得Logger實例后,我們可調用以下方法之一輸出日志信息:

       public void debug(Object message);          //輸出debug級別的日志信息;
       public void info(Object message);           //輸出info級別的日志信息;
       public void warn(Object message);           //輸出warn級別的日志信息;
       public void error(Object message);          //輸出error級別的日志信息;
       public void fatal(Object message);          //輸出fatal級別的日志信息;
       public void log(Priority p, Object message);//輸出參數Priority指定級別的日志信息;

       以上方法只有當它的級別大于或等于Logger組件配置的日志級別時才調用。以前面我們配置的myLogger為例,它的日志級別為WARN, 那么在程序中,它的warn()、error()、fatal()方法會被執行。對于log()方法,只有當它的參數Priority指定的日志級別大于或等于WARN時,它才會被執行。

    4. 為什么需要對日志進行分級?
    
       在寫程序的時候,為了調試程序,我們會在很多出錯的地方輸出大量的日志信息。當程序調試完,不需要這些信息時,將程序中這些輸出日志信息代碼刪除嗎?這樣費時費力,對于大型程序幾乎不可行。通過對日志分級,假如不想輸出WARN級別的日志信息,則Logger組件的級別調高即可,省時省心。

    5. Logger組件的繼承性

       Log4J提供了一個root Logger,它是所有Logger組件的“祖先”,它永遠存在,且不能通過名字檢索或引用,通過Logger.getRootLogger()方法取得它。配置root Logger代碼:

       log4j.rootLogger=INFO,console

       可在配置文件中方便地配置存在繼承關系的Logger組件,凡是在符號“.”后面的組件都會成為在符號“.”前面的Logger組件的子類。例如:

       log4j.apache.myLogger=WARN
       log4j.apache.myLogger.mySonLogger=,file

       以上代碼中, mySonLogger是myLogger的子類Logger組件。Logger組件的繼承關系:
       . 如果子類Logger組件沒有定義日志級別,則將繼承父類的日志級別;
       . 如果子類Logger組件定義了日志級別,就不會繼承父類的日志級別;
       . 黙認情況下,子類Logger組件會繼承父類所有的Appender,把它們加入到自己的Appener;
       . 如果把子類Logger組件的additivity標志設為false,那么它就不會繼承父類Appender。additivity標志 默認值為false;

       以上配置的三個Logger繼承關系示例如圖:
     
       root Logger: 日志級別=INFO  appender清單=console
                            ↑
       myLogger: 日志級別=WARN appender清單=null
                            ↑
       mySonLogger: 日志級別=null appender清單=file

       這三個Logger組件實際日志級別和Appender如下表:

       Logger組件          日志級別          Appender清單
       root Logger         INFO              console
       myLogger            WARN              console(繼承)
       mySonLogger         WARN(繼承)        file,console(繼承)
       
三、Appender組件

    Appender組件決定將日志信息輸出到什么地方。支持以下目的地:
    . 控制臺(Console);
    . 文件(File);
    . GUI組件(GUI component);
    . 套接口服務器(Remote socket server);
    . NT的事件記錄器(NT Event Logger);
    . UNIX Syslog守護進程(Remote UNIX Syslog daemon);

    一個Logger可同時對應多個Appender,示例:myLogger配置二個Appender: 一個file, 一個是console:

    log4j.logger.myAppender=WARN,file,console

    log4j.appender.file=org.apache.log4j.RollingFileAppender
    log4j.appender.file.File=log.txt

    log4j.apender.console=org.apache.log4j.ConsoleAppender

四、Layout組件

    Layout組件決定日志輸出格式,有以下幾種類型:
    . org.apache.log4j.HTMLLayout(以HTML表格形式布局);
    . org.apache.log4j.PatternLayout(可以靈活地指定布局模式);
    . org.apache.log4j.SimpleLayout(包含日志信息的級別和信息字符串);
    . org.apache.log4j.TTCCLayout(包含日志產生的時間、線程和類別等信息);
    
    為名稱為console的Appender配置SimpleLayout,代碼如下:

    log4j.appender.console.layout=org.apache.log4j.SimpleLayout

    輸出日志格式如下:

    WARN - This is a log message from the myLogger
    
    為名稱為file的Appender配置PatternLayout,代碼如下:

    log4j.appender.file.layout=org.apache.log4j.PatternLayout
    log4j.appender.file.layout.ConversionPattern=%t %p - %m%n

    輸出日志格式如下:

    THREAD-1 WARN - This is a log message from the myLogger

    PatternLayout讓開發者依照ConversionPattern定義輸出格式。ConversionPattern中一些指定日志內容和格式的預定義符號說明如下:

    符號         描述
    %r           自程序開始后消耗的毫秒數
    %t           表示日志記錄請求生成的線程
    %p           表示日專語句的優先級
    %r           與日志請求相關的類別名稱
    %c           日志信息所在的類名
    %m%n         表示日志信息的內容

五、Log4J的基本用法

    1. 定義配置文件
       Log4J支持二種配置文件格式:XML和Java屬性文件(采用“鍵=值”形式)。以下為Java屬性文件
       格式配置文件:
      
       . 配置Logger組件
         
         配置root Logger語法為:log4j.rootLogger=[priority],appenderName,appenderName,...
         配置自定義Logger組件語法為:log4j.logger.loggerName=[priority],appenderName,appenderName,...

         其中:priority為日志級別,可選值包括FATAL、ERROR、WARN、INFO、DEBUG、ALL;
               appenderName指定Appender組件,可指定多個;        

       . 配置Appender組件

         配置日志信息輸出目的地Appender, 語法為:
         log4j.appender.appenderName=fully.ualified.name.of.appender.class
         log4j.appender.appenderName.option1=value1
         ...
         log4j.appender.appenderName.optionN=valueN

         Log4J提供的Appender有以下幾種:

         a. org.apache.log4j.ConsoleAppender(控制臺);
         b. org.apache.log4j.FileAppender(文件);
         c. org.apache.log4j.DailyRollingFileAppender(每天產生一個日志文件);
         d. org.apache.log4j.RollingFileAppender(文件大小到指定尺寸產生一個新的文件);
         e. org.apache.log4j.WriteAppender(將日志信息以流格式發送到任意指定地方);

       . 配置Layout組件

         配置Layout組件語法為:
         log4j.appender.appenderName.layout=fully.ualified.name.of.appender.class
         log4j.appender.appenderName.layout.option1=value1
         ...
         log4j.appender.appenderName.layout.optionN=valueN

         下面為一配置文件示例,文件名為log4j.properties:

         ## LOGGERS ##

         #configure root logger
         log4j.rootLogger=INFO,console
         #define a logger named myLogger
         log4j.logger.myLogger=WARN
         #define a second logger that is a child to myLogger
         log4j.logger.myLogger.mySonLogger=,file

         ## APPENDERS ##

         #define an appender named console, which is set to be a ConsoleAppender
         log4j.appender.console=org.apache.log4j.ConsoleAppender

         # define an appender named file, which is set to be a RollingFileAppender
         log4j.appender.file=org.apache.log4j.FileAppender
         log4j.appender.file.File=log.txt

         ## LAYOUTS ##
         # assian a SimpleLayout to console appender
         log4j.appender.console.layout=org.apache.log4j.SimpleLayout

         # assian a PatternLayout to file appender
         log4j.appender.file.layout=org.apache.log4j.PatternLayout
         log4j.appender.file.layout.ConversionPattern=%t%p-%m%n
         
    2. 程序中使用Log4j

       . 獲得日志記錄器:

         獲得rootLogger:Logger rootLogger=Logger.getRootLogger();
         獲得自定義Logger:Logger myLogger = Logger.getLogger("log4j.logger.myLogger");

       . 讀取日志記錄器,配置Log4J環境;

         a. BasicConfigurator.configure(): 自動快速地使用默認Log4J環境;
         b. Property.configurator.configure(String configFilename): 讀取使用Java屬性格式的配置文件并配置Log4J環境;
         c. DOMConfigurator.configure(String filename): 讀取XML形式的配置文件并配置LOG4J環境;

       . 輸出日志信息;

         在程序代碼中需要生成日志的地方,調用Logger的各種輸出日志方法輸出不同級別的日志,例如:
         
         myLogger.debug("Thie is a log message from the " + myLogger.getName());

         下面為一使用Log4J的程序,程序名為Test.java:

java 代碼
  1.  import org.apache.log4j.Logger;   
  2.  import org.apache.log4j.PropertyConfigurator;   
  3.     
  4.  public class Test {   
  5.   
  6.    public static void main(String[] args) {   
  7.      //Get an instance of the myLogger   
  8.      Logger myLogger = Logger.getLogger("myLogger");   
  9.       
  10.      //Get an instance of the childLogger   
  11.      Logger mySonLogger = Logger.getLogger("myLogger.mySonLogger");   
  12.      //Load the proerties using the PropertyConfigurator   
  13.      PropertyConfigurator.configure("log4j.properties");   
  14.   
  15.      //Log Messages using the Parent Logger   
  16.      myLogger.debug("Thie is a log message from the " + myLogger.getName());   
  17.      myLogger.info("Thie is a log message from the " + myLogger.getName());   
  18.      myLogger.warn("Thie is a log message from the " +  myLogger.getName());   
  19.      myLogger.error("Thie is a log message from the " + myLogger.getName());   
  20.      myLogger.fatal("Thie is a log message from the " + myLogger.getName());   
  21.   
  22.      mySonLogger.debug("Thie is a log message from the " + mySonLogger.getName());   
  23.      mySonLogger.info("Thie is a log message from the " + mySonLogger.getName());   
  24.      mySonLogger.warn("Thie is a log message from the " +  mySonLogger.getName());   
  25.      mySonLogger.error("Thie is a log message from the " + mySonLogger.getName());   
  26.      mySonLogger.fatal("Thie is a log message from the " + mySonLogger.getName());   
  27.    }   
  28. }   

        程序運行結果為:

        WARN - Thie is a log message from the myLogger
        ERROR - Thie is a log message from the myLogger
        FATAL - Thie is a log message from the myLogger
        WARN - Thie is a log message from the myLogger.mySonLogger
        ERROR - Thie is a log message from the myLogger.mySonLogger
        FATAL - Thie is a log message from the myLogger.mySonLogger

        另在Test.class所在的目錄下看到一個log.txt文件,內容如下:

        WARN - Thie is a log message from the myLogger.mySonLogger
        ERROR - Thie is a log message from the myLogger.mySonLogger
        FATAL - Thie is a log message from the myLogger.mySonLogger

        如將配置文件log4j.properties中語句

 log4j.logger.myLogger.mySonLogger=,file

 改為

 log4j.logger.myLogger.mySonLogger=,file,console

 再次運行程序,結果如下:

        WARN - Thie is a log message from the myLogger
        ERROR - Thie is a log message from the myLogger
        FATAL - Thie is a log message from the myLogger
        WARN - Thie is a log message from the myLogger.mySonLogger
        WARN - Thie is a log message from the myLogger.mySonLogger
        ERROR - Thie is a log message from the myLogger.mySonLogger
        ERROR - Thie is a log message from the myLogger.mySonLogger
        FATAL - Thie is a log message from the myLogger.mySonLogger         
        FATAL - Thie is a log message from the myLogger.mySonLogger

        mySonLogger的日志在控制臺上輸出了二次,這是因為mySonLogger繼承了父類console Appender,
        本身又定義了一個console Appender, 因而有二個console Appender。

六、在web應用中使用Log4J

    創建一個Servlet,在它初始化方法中讀取Log4J配置文件并配置Log4J環境,這個Servlet在Web應用啟
    動時候被加載和初始化,然后就可在其它Web組件中獲取Logger對象并輸出日志。

    1. 創建用于配置Log4J環境的Servlet

java 代碼
  1. import javax.servlet.*;   
  2. import javax.servlet.http.*;   
  3. import java.io.*;   
  4. import java.util.*;   
  5.   
  6. import org.apache.log4j.PropertyConfigurator;   
  7.   
  8. public class Log4JServlet extends HttpServlet {   
  9.       public void init() throws ServletException {   
  10.            String path = getServletContext().getRealPath("/");   
  11.            //getInitParameter("propfile")方法從web.xml文件中讀取Log4J配置文件的名字"profile"。   
  12.            String propfile = path + getInitParameter("propfile");   
  13.            PropertyConfigurator.configure(propfile);   
  14.       }   
  15. }   
  16.   

      該Servlet在web.xml中的配置如下:

xml 代碼
  1. <servlet>  
  2.   <servlet-name>log4jServlet</servlet-name>  
  3.   <servlet-class>Log4JServlet</servlet-class>  
  4.   <init-param>  
  5.     <param-name>propfile</param-name>  
  6.     <param-value>/WEB-INF/log4j.properties</param-value>  
  7.   </init-param>  
  8.   <load-on-startup>1</load-on-startup>  
  9. </servlet>  

2. 在login.jsp中輸出日志
       <%@page import="org.apache.log4j.Logger"%>
       <html>
         <head>
           <title>login</title>
         </head>
         <body>
           <%
             Logger myLogger = Logger.getLogger("myLogger");
             Logger mySonLogger = Logger.getLogger("myLogger.mySonLogger");
             myLogger.debug("Thie is a log message from the " + myLogger.getName());
             myLogger.info("Thie is a log message from the " + myLogger.getName());
             myLogger.warn("Thie is a log message from the " +  myLogger.getName());
             myLogger.error("Thie is a log message from the " + myLogger.getName());
             myLogger.fatal("Thie is a log message from the " + myLogger.getName());

             mySonLogger.debug("Thie is a log message from the " + mySonLogger.getName());
             mySonLogger.info("Thie is a log message from the " + mySonLogger.getName());
             mySonLogger.warn("Thie is a log message from the " +  mySonLogger.getName());
             mySonLogger.error("Thie is a log message from the " + mySonLogger.getName());
             mySonLogger.fatal("Thie is a log message from the " + mySonLogger.getName());
           %>
           <br>
             <form name="loginForm" method="post" action="dispatcher">
             username: <input type="text" name="username">
             <br>
             password: <input type="text" name="password">
             <br>
             <input type="submit" name="submit" value="submit">
           </form>
         </body>
       </html>
               
    3. 發布運行使用Log4J的web應用
       1) 將Log4J的JAR文件拷貝至目錄:<WEB應用所在目錄>/WEB-INF/lib
       2) 創建Log4J的配置文件log4j.properties, 存放目錄為:<WEB應用所在目錄>/WEB-INF。內容同前面配置文件示例。
       3) 編譯Log4JServlet, 存放至目錄: <WEB應用所在目錄>/WEB-INF/classes
       4) 修改web.xml文件,加入以下內容:

xml 代碼
  1. <servlet>  
  2.   <servlet-name>log4jServlet</servlet-name>  
  3.   <servlet-class>Log4JServlet</servlet-class>  
  4.   <init-param>  
  5.     <param-name>profile</param-name>  
  6.     <param-value>/WEB-INF/log4j.properties</param-value>  
  7.   </init-param>  
  8.   <load-on-startup>1</load-on-startup>  
  9. </servlet>  


       5) 啟動服務器,訪問login.jsp頁面,在服務器控制臺上看到如下日志:
          WARN - Thie is a log message from the myLogger
          ERROR - Thie is a log message from the myLogger
          FATAL - Thie is a log message from the myLogger
          WARN - Thie is a log message from the myLogger.mySonLogger
          ERROR - Thie is a log message from the myLogger.mySonLogger
          FATAL - Thie is a log message from the myLogger.mySonLogger

          另在<WEB應用所在目錄>/WEB-INF目錄下看到一個log.txt文件,內容如下:

          WARN - Thie is a log message from the myLogger.mySonLogger
          ERROR - Thie is a log message from the myLogger.mySonLogger
          FATAL - Thie is a log message from the myLogger.mySonLogger