commons-logging與log4j的區別與聯繫

1、Apache通用日誌接口(commons-logging.jar)介紹

Apache Commons包中的一個,包含了日誌功能,必須使用的jar包。這個包本身包含了一個Simple Logger,但是功能很弱。在運行的時候它會先在CLASSPATH找log4j,如果有,就使用log4j,如果沒有,就找JDK1.4帶的 Java.util.logging,如果也找不到就用Simple Logger。commons-logging.jar的出現是一個歷史的的遺留的遺憾,當初Apache極力遊說Sun把log4j加入JDK1.4,然而JDK1.4項目小組已經接近發佈JDK1.4產品的時間了,因此拒絕了Apache的要求,使用自己的java.util.logging,這個包的功能比log4j差的很遠,性能也一般。後來Apache就開發出來了commons-logging.jar用來兼容兩個logger。因此用 commons-logging.jar寫的log程序,底層的Logger是可以切換的,你可以選擇log4j,java.util.logging或者它自帶的Simple Logger。不過我仍然強烈建議使用log4j,因爲log4j性能很高,log輸出信息時間幾乎等於System.out,而處理一條log平均只需要5us。

Apache通用日誌包提供一組通用的日誌接口,用戶可以自由選擇實現日誌接口的第三方軟件
通用日誌目前支持以下日誌實現
Log4j日誌器
JDK1.4Logging
SimpleLog日誌器
NoOpLog日誌器

1.1、Log 接口
Common-logging的應用程序編程接口主要在org.apache.commons.logging.log接口中定義,這個接口主要定義了兩類操作: 一類是級別判斷,用於減少不必要的日誌操作的參數計算從而提高性能。另一類是日誌登記,按照級別登記日誌信息。
通用日誌包把日誌消息分爲6種級別Fatal,Error,Warn,Info,Debug和Trace

org.apache.commons.logging.Log接口代表日誌器,它提供了一組輸出日誌的方法,日誌登記操作分又爲兩小類:一個參數的日誌信息登記操作和兩個參數的日誌信息登記操作。前者對三類用戶都適用,後者用於打印日誌登記處的出錯堆棧信息,所以更適用於開發人員調式與維護使用
       fatal(Object message);
       error(Object message);
       warn (Object message);
       info (Object message);
       debug(Object message);
       trace(Object message);

       debug(Object message, Throwable t); 
       trace(Object message, Throwable t);
       ......
      這裏需要注意的是,只有當輸出日誌的級別大於等於日誌器配置的日誌級別時,這個方法纔會真正被執行.例如日誌器設置日誌級別爲Warn,那麼程序中,它的
      fatal(),error(),warn()方法會被執行,而info(),debug(),trace()
      不會被執行.
      Log接口還提供了一組判斷是否允許輸出特定級別日誌消息的方法

       isFatalEnable();
       isErrorEnable();
       isWarnEnable();
       isInfoEnable();
       isDebugEnable();
       isTraceEnable();
1.2、LogFactory接口
      org.apache.commons.logging.LogFactory接口提供了獲得日誌器實例的兩個靜態方法
       public static Log getLog(String name)throws LogConfigurationException
       public static Log getLog(Class class)throws LogConfigurationException
       public static Log getLog(Class class)
       {
        getLog(class.getName());
       }

2、Log4J介紹

Log4j是Apache的一個開放源代碼項目,通過使用Log4j,我們可以控制日誌信息輸送的目的地是控制檯、文件、GUI組件、甚至是套接口服務器、NT的事件記錄器、UNIX Syslog守護進程等;我們也可以控制每一條日誌的輸出格式;通過定義每一條日誌信息的級別,我們能夠更加細緻地控制日誌的生成過程。這些可以通過一個配置文件來靈活地進行配置,而不需要修改應用的代碼。

2.1、Log4J配置說明: 

log4j配置文件有三個主要的組件:Logger,Appender和Layout,分別爲日誌類型,日誌輸出目的地,日誌輸出格式. 
跟proxool類似,log4j支持兩種類型的配置文件,xml和properties 。log4j.properties配置文件如下:(需要把log4j的配置文件放在classpath下)

2.1.1 log4j.rootLogger =INFO, stdout , R

此句爲將等級爲INFO的日誌信息輸出到stdout和R這兩個目的地,其語法爲:

log4j.rootLogger = [ level ] , appenderName, appenderName, …

其中,level 是日誌記錄的優先級,分爲OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者自定義的級別。Log4j建議只使用四個級別,優先級從高到低分別是ERROR、WARN、INFO、DEBUG。通過在這裏定義的級別,您可以控制到應用程序中相應級別的日誌信息的開關。比如在這裏定義了INFO級別,只有等於及高於這個級別的才進行處理,則應用程序中所有DEBUG級別的日誌信息將不被打印出來。ALL:打印所有的日誌,OFF:關閉所有的日誌輸出。 appenderName就是指定日誌信息輸出到哪個地方。可同時指定多個輸出目的地。  

2.1.2 log4j.appender.stdout=org.apache.log4j.ConsoleAppender

此句爲定義名爲stdout的輸出端是哪種類型

 

Appender 負責控制日誌記錄操作的輸出。

  其語法爲:

  log4j.appender.appenderName = fully.qualified.name.of.appender.class

  log4j.appender.appenderName.option1 = value1

  …

  log4j.appender.appenderName.optionN = valueN

  這裏的appenderName爲在①裏定義的,可任意起名。

  其中,Log4j提供的appender有以下幾種:

  org.apache.log4j.ConsoleAppender(控制檯),

  org.apache.log4j.FileAppender(文件),

  org.apache.log4j.DailyRollingFileAppender(每天產生一個日誌文件),

  org.apache.log4j.RollingFileAppender(文件大小到達指定尺寸的時候產生一個新的文件),可通過log4j.appender.R.MaxFileSize=100KB設置文件大小,還可通過 log4j.appender.R.MaxBackupIndex=1設置爲保存一個備份文件

  org.apache.log4j.WriterAppender(將日誌信息以流格式發送到任意指定的地方)

  例如:log4j.appender.stdout=org.apache.log4j.ConsoleAppender

  定義一個名爲stdout的輸出目的地,ConsoleAppender爲控制檯。

2.1.3配置日誌信息的格式(佈局)Layout

  Layout 負責格式化Appender的輸出。

  其語法爲:

  log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class

  log4j.appender.appenderName.layout.option1 = value1

  …

  log4j.appender.appenderName.layout.optionN = valueN

  其中,Log4j提供的layout有以下幾種:

  org.apache.log4j.HTMLLayout(以HTML表格形式佈局),

  org.apache.log4j.PatternLayout(可以靈活地指定佈局模式),

  org.apache.log4j.SimpleLayout(包含日誌信息的級別和信息字符串),

  org.apache.log4j.TTCCLayout(包含日誌產生的時間、線程、類別等等信息)

2.1.4格式化日誌信息
Log4J採用類似C語言中的printf函數的打印格式格式化日誌信息,打印參數如下:

  %m 輸出代碼中指定的消息

  %p 輸出優先級,即DEBUG,INFO,WARN,ERROR,FATAL

  %r 輸出自應用啓動到輸出該log信息耗費的毫秒數

  %c 輸出所屬的類目,通常就是所在類的全名

  %t 輸出產生該日誌事件的線程名

  %n 輸出一個回車換行符,Windows平臺爲“rn”,Unix平臺爲“n”

  %d 輸出日誌時間點的日期或時間,默認格式爲ISO8601,也可以在其後指定格式,比如:%d{yyyy MMM dd HH:mm:ss,SSS},輸出類似:2002年10月18日 22:10:28,921

  %l 輸出日誌事件的發生位置,包括類目名、發生的線程,以及在代碼中的行數

2.2、關於Log4j比較全面的配置

2.2.1 應用於控制檯

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender    log4j.appender.Threshold=DEBUG    log4j.appender.CONSOLE.Target=System.out    log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout    log4j.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n    #log4j.appender.CONSOLE.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD] n%c[CATEGORY]%n%m[MESSAGE]%n%n

2.2.2應用於文件

log4j.appender.FILE=org.apache.log4j.FileAppender    log4j.appender.FILE.File=file.log    log4j.appender.FILE.Append=false log4j.appender.FILE.layout=org.apache.log4j.PatternLayout    log4j.appender.FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n    # Use this layout for LogFactor 5 analysis

2.2.3 應用於回滾文件

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

log4j.appender.ROLLING_FILE.Threshold=ERROR  

log4j.appender.ROLLING_FILE.File=rolling.log  

log4j.appender.ROLLING_FILE.Append=true

log4j.appender.ROLLING_FILE.MaxFileSize=10KB  

log4j.appender.ROLLING_FILE.MaxBackupIndex=1

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

log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n 

2.2.4應用於socket

log4j.appender.SOCKET=org.apache.log4j.RollingFileAppender    log4j.appender.SOCKET.RemoteHost=localhost    log4j.appender.SOCKET.Port=5001 log4j.appender.SOCKET.LocationInfo=true # Set up for Log Facter 5 log4j.appender.SOCKET.layout=org.apache.log4j.PatternLayout    log4j.appender.SOCET.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD]%n%c[CATEGORY]%n%m[MESSAGE]%n%n    # Log Factor 5 Appender    log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender    log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000

2.2.5應用於郵件

log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender    log4j.appender.MAIL.Threshold=FATAL    log4j.appender.MAIL.BufferSize=10 [email protected]    log4j.appender.MAIL.SMTPHost=www.wusetu.com    log4j.appender.MAIL.Subject=Log4J Message    [email protected]    log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout    log4j.appender.MAIL.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

2.2.6應用於數據庫

log4j.appender.DATABASE=org.apache.log4j.jdbc.JDBCAppender    log4j.appender.DATABASE.URL=jdbc:mysql://localhost:3306/test  log4j.appender.DATABASE.driver=com.mysql.jdbc.Driver    log4j.appender.DATABASE.user=root    log4j.appender.DATABASE.password=    log4j.appender.db.sql=INSERT INTO SS_LOG4J_LOG (PRIORITY,LOGDATE,CLASS,METHOD,MSG) VALUES('%p','%d{yyyy-MM-dd HH:mm:ss}','%C','%M','%m')   log4j.appender.db.layout=org.apache.log4j.PatternLayout log4j.appender.DATABASE.layout=org.apache.log4j.PatternLayout    log4j.appender.DATABASE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n <pre name="code" class="java">

3、Log4J的使用

3.1、在application中的使用:

將log4j.jar和common-logging.jar加入到build path中即可。

3.2 在web應用中使用log4j

  3.2.1 創建一個集成httpservlet的servlet文件,在init中對log4j進行初始化

public class log4jInit extends HttpServlet {

    
    @Override
    public void init() throws ServletException {
        Log log = LogFactory.getLog(this.getClass().getName());
        //Logger logger = Logger.getLogger(this.getClass());        
        String prefix = this.getServletContext().getRealPath("/");
        System.out.println(prefix);
        String file = this.getServletConfig().getInitParameter("log4j-init-file");
        if(file!=null)
            PropertyConfigurator.configure(prefix+file);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
    }

}

   3.2.2 在web.xml中定義這個servlet,並在應用啓動時啓動

<servlet>
    <servlet-name>log4jInit</servlet-name>
    <servlet-class>com.highsoft.log4j.log4jInit</servlet-class>
    <init-param>
        <param-name>log4j-init-file</param-name>
        <param-value>/WEB-INF/classes/log4j1.properties</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

3.3 在spring中集成log4j

3.3.1 在web.xml中集成

<!--如果不設,默認爲web.root,但最好設置,以免項目間衝突—>

<!--如果應用服務器下有不止一個的應用在使用spring的Log4jConfigListener,需要修改web環境中webAppRootKey值(這樣log4j的配置文件裏就可以用${myAppfuse.root}來表示剛剛設進去的系統變量,例如:log4j.appender.logfile.File=${myAppfuse.root}/logs/mylog.log)。否則兩個默認值web.root在環境變量中就會有衝突導致第二個應用啓動失敗。—>

<context-param>     
    <param-name>webAppRootKey</param-name>      
    <param-value>myappfuse.root</param-value> 
</context-param>

<!--在這裏定位配置文件,需要的是從root開始的絕對路徑—>
<context-param>   
    <param-name>log4jConfigLocation</param-name>   
    <param-value>/WEB-INF/classes/log4j.properties</param-value>
</context-param>

<!--Spring默認刷新Log4j配置文件的間隔,單位爲millisecond-->
<context-param>
       <param-name>log4jRefreshInterval</param-name>
       <param-value>60000</param-value>
</context-param>


<listener>   
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>

<!--這裏用listener,也可以用下面的servlet—>

<servlet>
   <servlet-name>log4j</servlet-name>
   <servlet-class>org.springframework.web.util.Log4jConfigServlet</servlet-class>
   <load-on-startup>1</load-on-startup>
</servlet>

 

3.3.2 在代碼中使用Log4j
我們在需要輸出日誌信息的類中做如下的三個工作:

  1、導入所有需的commongs-logging類:

  import org.apache.commons.logging.Log;

  import org.apache.commons.logging.LogFactory;

  2、在自己的類中定義一個org.apache.commons.logging.Log類的私有靜態類成員:

  private final Log log = LogFactory.getLog(getClass());

  LogFactory.getLog()方法的參數使用的是當前類的class。

  3、使用org.apache.commons.logging.Log類的成員方法輸出日誌信息:

  if (log.isDebugEnabled()){

  log.debug("111");

  }

  if (log.isInfoEnabled()){

  log.info("222");

  }

  if (log.isWarnEnabled()){

  log.warn("333");

  }

  if (log.isErrorEnabled()){

  log.error("444");

  }

  if (log.isFatalEnabled()){

  log.fatal("555")

  }

4、SLF4j介紹

準確的說,slf4j並不是一種具體的日誌系統,而是一個用戶日誌系統的facade,允許用戶在部署最終應用時方便的變更其日誌系統。

4.1、使用方式:
       在系統開發中,統一按照slf4j的API進行開發,在部署時,選擇不同的日誌系統包,即可自動轉換到不同的日誌系統上。比如:選擇JDK自帶的日誌系統,則只需要將slf4j-api-1.5.10.jar和slf4j-jdk14-1.5.10.jar放置到classpath中即可,如果中途無法忍受JDK自帶的日誌系統了,想換成log4j的日誌系統,僅需要用slf4j-log4j12-1.5.10.jar替換slf4j- jdk14-1.5.10.jar即可(當然也需要log4j的jar及配置文件)
4.2、使用場景:
        我們開發的是類庫或者嵌入式組件,可以考慮使用slf4j,因爲我們並不能決定用戶選擇哪種日誌系統(不同軟件開發公司會鍾情於不同的日誌系統);但是如果我們開發獨立應用,面向的是最終客戶,則無需考慮slf4j,因爲最終客戶只關心功能實現,不會在意開發公司具體使用什麼日誌系統的。
4.3、應用舉例:  
import org.slf4j.Logger;   
import org.slf4j.LoggerFactory;   
/**  
* @author chb  
*  
*/  
public class TestSlf4j {   
        Logger log = LoggerFactory.getLogger(TestSlf4j.class);   
        public void testLog(){   
                log.info("this is a test log");   
        }   
        /**  
         * @param args  
         */  
        public static void main(String[] args) {   
                TestSlf4j slf = new TestSlf4j();   
                slf.testLog();   
        }   
}

1>JDK自帶的log輸出
       首先,我們在classpath中加入slf4j-api-1.5.10.jar和slf4j-jdk14-1.5.10.jar兩個包,然後運行main函數,輸出信息如下:
view plaincopy to clipboardprint?
2010-1-5 21:44:47 chb.test.slf4j.TestSlf4j testLog   
信息: this is a test log  
2010-1-5 21:44:47 chb.test.slf4j.TestSlf4j testLog
信息: this is a test log 
2>slg4j提供的simple log
      然後,我們用slf4j-simple-1.5.10.jar替換slf4j-jdk14-1.5.10.jar,選擇使用slf4j提供的simple log,輸出信息如下:
view plaincopy to clipboardprint?
0 [main] INFO chb.test.slf4j.TestSlf4j - this is a test log  
0 [main] INFO chb.test.slf4j.TestSlf4j - this is a test log 
3>log4j日誌輸出
    再然後,我們再用slf4j-log4j12-1.5.10.jar替換slf4j-simple-1.5.10.jar(記得classpath也需要增加log4j依賴jar包),同時增加一個log4j.properties文件,我們再稍微修改一下main函數,加載一下log4j.properties,如;
view plaincopy to clipboardprint?
public static void main(String[] args) {   
        PropertyConfigurator.configure("D:\\log4j.properties");  
        TestSlf4j slf = new TestSlf4j();   
        slf.testLog();   

4.4、原理介紹--靜態綁定
        大家看到要使用哪種日誌系統,只需要將對應的日誌系統所需要的jar包文件(包括slf4j提供的jar包和日誌系統自身依賴的jar包,例如:slf4j-log4j12-1.5.10.jar和log4j.1.2.jar)放入classpath即可,slf4j可以自動探測具體使用哪種日誌系統,這種技術被稱爲靜態綁定。
       在實際使用中,我們通過LoggerFactory.getLogger()獲得logger,查看LoggerFactory的源代碼會發現如下兩點,
LoggerFactory通過StaticLoggerBinder.getSingleton().getLoggerFactory()獲得LogFactory,然後再通過該LogFactory來獲取logger的 
但是StaticLoggerBinder類並不在slf4j-api-1.5.10.jar中,分析與具體日誌系統相關的jar包,會發現每個jar包都有一個StaticLoggerBinder類的實現(如slf4j-log4j12-1.5.10.jar、slf4j-simple- 1.5.10.jar、slf4j-jdk14-1.5.10.jar均有StaticLoggerBinder類實現),這就很明白了,slf4j在啓動時會動態到classpath中查找StaticLoggerBinder類,找到之後就可以生成對應日誌系統的日誌文件了。 
    這裏就有一個問題了,slf4j是如何將自己的通用日誌格式轉成不同的日誌系統的格式的呢?
    我們再分析每個日誌系統相關的源代碼,會發現不同日誌系統包都會有一個Adapter,用來在slf4j和不同日誌系統之間做轉換。

4.5、與common-logging的區別

Apache Common-Logging是廣泛使用的Java日誌門面庫。我以前一直都使用它和log4j編寫日誌。
Apache Common-Logging通過動態查找的機制,在程序運行時自動找出真正使用的日誌庫。
Apache Common-Logging一直都運作得很好。直到最近,我寫OSGI插件時,它不能工作了。
原因是Apache Common-Logging使用了ClassLoader尋找和載入底層的日誌庫。而OSGI中,不同的插件使用自己的ClassLoader。
一個線程的ClassLoader在執行不同的插件時,其執行能力是不同的。
OSGI的這種機制保證了插件互相獨立,然而確使Apache Common-Logging無法工作!
解決之道是使用新的日誌門面庫Slf4j。
Slf4j庫類似於Apache Common-Logging。但是,他在編譯時靜態綁定真正的Log庫。使用Slf4j時,如果你需要使用某一種日誌實現,那麼你必須選擇正確的Slf4j的jar包的集合。

-----------

# Properties for configuring Log4j


# Set logger level

log4j.rootLogger=CONSOLE

log4j.logger.org=CONSOLE


log4j.additivity.com.gm=false

log4j.additivity.com.eds=false

log4j.additivity.FrameworkLogging=false

log4j.additivity.com.gm.workbench.order.service.common.helper.mq=false


log4j.logger.com.gm=INFO,APP_LOG

#log4j.logger.com.gm.workbench.order.service.offline=CONSOLE

#log4j.logger.com.gm.workbench.order.service.online.elc=CONSOLE

log4j.logger.com.eds=CONSOLE

#log4j.logger.FrameworkLogging=CONSOLE

#log4j.logger.com.gm.workbench.order.service.common.helper.mq=CONSOLE

#log4j.logger.com.gm.workbench.order.service.online.elc=CONSOLE


#log4j.logger.com.gm.workbench.order.service.online.manageinventory=CONSOLE

#log4j.logger.com.gm.workbench.order.service.common.dataaccess=CONSOLE

#log4j.logger.com.gm.workbench.order.service.online.bulkorder=CONSOLE


# CONSOLE is set to be a ConsoleAppender

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

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

log4j.appender.CONSOLE.layout.ConversionPattern=%d{MM-dd@HH:mm:ss} %-5p %c{1}:(%13F:%L) %3x - %m%n


# APP_LOG is set to be a RollingFileAppender

log4j.appender.APP_LOG=org.apache.log4j.RollingFileAppender

log4j.appender.APP_LOG.MaxFileSize=5000KB

log4j.appender.APP_LOG.MaxBackupIndex=10

log4j.appender.APP_LOG.File =c:/log4j/app-logger.log

log4j.appender.APP_LOG.Append = true

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

log4j.appender.APP_LOG.layout.ConversionPattern=%d{MM-dd@HH:mm:ss} %-5p %c{1}:(%13F:%L) %3x - %m%n


# AUD_LOG is set to be a RollingFileAppender

log4j.appender.AUD_LOG=org.apache.log4j.RollingFileAppender

log4j.appender.AUD_LOG.MaxFileSize=50000KB

log4j.appender.AUD_LOG.MaxBackupIndex=5

log4j.appender.AUD_LOG.File =c:/log4j/audit-logger_001.log

log4j.appender.AUD_LOG.Append = true

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

log4j.appender.AUD_LOG.layout.ConversionPattern=%d{MM-dd@HH:mm:ss} %-5p %c{1}:(%13F:%L) %3x - %m%n


發佈了21 篇原創文章 · 獲贊 7 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章