<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Change Dir

    先知cd——熱愛生活是一切藝術的開始

    統計

    留言簿(18)

    積分與排名

    “牛”們的博客

    各個公司技術

    我的鏈接

    淘寶技術

    閱讀排行榜

    評論排行榜

    簡單的log

    在寫j2ee程序時,我們的程序中會經常出現這樣一句代碼:log.error(“something bad happend”);每個人都知道,這是打印日志用的,那么這個log對象如何來的呢?我們也知道,是

    private Log log = LogFactory.getLog(CLASS.class);
    
    這樣來的。配置log已經不是一件技術活了,我們總是使用JCL作為wraper,調用實際的底層的日志框架,而日志框架無非就是log4j,logback。這里簡單的記錄一下log在系統中的配置和使用。 commons-log是非常簡單的一個開源項目,apache-commons下代碼算是最少的了。功能最簡單,包裝一個統一的log接口,然后調用實際的log框架完成日志記錄的工作。 生一個log對象,是通過logFactory完成的。
       1: /**
       2:      * Convenience method to return a named logger, without the application
       3:      * having to care about factories.
       4:      *
       5:      * @param clazz Class from which a log name will be derived
       6:      *
       7:      * @exception LogConfigurationException if a suitable <code>Log</code>
       8:      *  instance cannot be returned
       9:      */
      10:     public static Log getLog(Class clazz)
      11:         throws LogConfigurationException {
      12:  
      13:         return (getFactory().getInstance(clazz));
      14:  
      15:     }

    其中的getFactory方法,首先會嘗試利用當前的classLoader去一個hashtable里取一個factory出來,這個設計為了避免資源重復(按照官方說法,getLog是一個很重的操作),利用了cache的思想,緩存了構建過的factory。這個緩存的key就是classloader。寫到這里,插一句,這個設計在我們為一個已有項目添加資源利用時是必備的設計之一——緩存重復利用的資源。

       1: ClassLoader contextClassLoader = getContextClassLoaderInternal();
       2:  
       3:        if (contextClassLoader == null) {
       4:            // This is an odd enough situation to report about. This
       5:            // output will be a nuisance on JDK1.1, as the system
       6:            // classloader is null in that environment.
       7:            if (isDiagnosticsEnabled()) {
       8:                logDiagnostic("Context classloader is null.");
       9:            }
      10:        }
      11:  
      12:        // Return any previously registered factory for this class loader
      13:        LogFactory factory = getCachedFactory(contextClassLoader);
      14:        if (factory != null) {
      15:            return factory;
      16:        }

    當然第一次加載時是緩存取不到的,那么logFactory會嘗試進行一次commons-logging.properties文件的讀取,來配置具體的log方式,沒有配置的話,接著會嘗試"META-INF/services/org.apache.commons.logging.LogFactory”來配置。最后實在沒有找到任何信息時,就會用commons-logging自己的org.apache.commons.logging.impl.LogFactoryImpl來實例化了。加載方式比較簡單,利用初始時得到的classloader加載org.apache.commons.logging.impl.LogFactoryImpl即可。然后把得到的factory緩存住就OK了。

    顯然的事情是,logFactory這種東西都緩存了,那么log這個對象就更要緩存了,LogFactoryImpl里有個hashtable用來存放已經注冊了的Log對象。key的話是調用時傳入的className。如果配置了Log4j的話,那么接下來log的所有行為就寫到log4j配置的日志里了(其實不用配置,log4j是commons-logging的首選支持)。在沒有任何配置的情況下,會支持{log4j,jdk14log,jdk13log和simpleLog}

    以log4j為例說一下具體的寫日志:在commons-logging的Log4JLogger拿到后,作為一個包裝器,其所有的寫日志方法都是調用的內部的一個logger對象的,這個logger來自Log4j的Logger,logger是通過LogManager的getLogger方法得到的。

     

    log4j的一個xml配置解說:

       1: <?xml version="1.0" encoding="GBK"?>
       2: <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
       3: <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
       4:     <appender name="appender1" class="org.apache.log4j.DailyRollingFileAppender">
       5:         <param name="file" value="/home/admin/yourapp/app.log" />
       6:         <param name="encoding" value="GBK" />
       7:         <param name="append" value="true" />
       8:         <param name="threshold" value="info"/>
       9:         <layout class="org.apache.log4j.PatternLayout">
      10:             <param name="ConversionPattern" value="%d{yy/MM/dd HH:mm:ss:SSS}][%C-%M] %m%n" />
      11:         </layout>
      12:     </appender>
      13:     <logger name="com.yourcom.yourpackage" additivity="false">
      14:        <level value="your_loggingLevel"/>
      15:        <appender-ref ref="appender1"/>
      16:    </logger>
      17:     <root>
      18:        <level value="your_loggingLevel" />
      19:        <appender-ref ref="appender1" />
      20:    </root>

    其中appender定義了日志以什么樣的pattern打印到什么目錄file,日志打印的級別threshold以及編碼方式encoding。logger配置定義了哪些類里的log代碼會被打印,這里name指定了對應的包名。root定義了log4j中的hierarchy類中的root logger。最終logger的所有打日志方法都會調用下面這個方法,這個方法在logger的父類Category中:

       1: /**
       2:      Call the appenders in the hierrachy starting at
       3:      <code>this</code>.  If no appenders could be found, emit a
       4:      warning.
       5: 
       6:      <p>This method calls all the appenders inherited from the
       7:      hierarchy circumventing any evaluation of whether to log or not
       8:      to log the particular log request.
       9: 
      10:      @param event the event to log.  */
      11:   public
      12:   void callAppenders(LoggingEvent event) {
      13:     int writes = 0;
      14:  
      15:     for(Category c = this; c != null; c=c.parent) {
      16:       // Protected against simultaneous call to addAppender, removeAppender,...
      17:       synchronized(c) {
      18:     if(c.aai != null) {
      19:       writes += c.aai.appendLoopOnAppenders(event);
      20:     }
      21:     if(!c.additive) {
      22:       break;
      23:     }
      24:       }
      25:     }
      26:  
      27:     if(writes == 0) {
      28:       repository.emitNoAppenderWarning(this);
      29:     }
      30:   }

    一個LoggingEvent在打日志的時候會被實例化,并且賦予一些記錄日志相關的信息。第19行的代碼其實就是在調用配置文件中配置過的appender。具體的打印樣式,會被Layout類處理。

    最后關于性能的討論,來源于官網的解釋,logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i])); 這樣一條語句帶來了大量的string操作及參數構建。所以文檔建議我們使用這樣的寫法:

       1: if(logger.isDebugEnabled() {
       2:         logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
       3:       }

    理由是這樣避免了log參數的構建。當然,用commons-logging也可以的,其中的Log也封裝了所有的Logger原有的方法。另外,layout花費了不少時間,目前的文檔說,SimpleLayout已經優化到和System.out.print()一樣快了。

    總結一下,log4j是使用最普遍的日志應用了,依靠日志,我們記錄了信息,同時可以幫助調試,是服務器端開發的一大利器。了解日志系統的原理也是必需的技能。log系統值得深入的地方還有很多。以后繼續挖掘。

     

    參考資料:

    http://www.iteye.com/topic/378077 

    http://logging.apache.org/log4j/1.2/manual.html

    posted on 2012-03-28 20:03 changedi 閱讀(2345) 評論(1)  編輯  收藏

    評論

    # re: 簡單的log 2012-03-30 07:50 tb

    很不錯的   回復  更多評論   


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 亚洲H在线播放在线观看H| 亚洲精品你懂的在线观看| 亚洲成a人片77777群色| 嫩草在线视频www免费看| 久久精品国产亚洲麻豆| 成人免费777777被爆出| 中文字幕亚洲一区二区va在线| 一级做a爱过程免费视| 国产L精品国产亚洲区久久| 久久久久久av无码免费看大片| 亚洲精品动漫人成3d在线| 又粗又长又爽又长黄免费视频 | 无码中文字幕av免费放dvd| 黑人精品videos亚洲人| 久艹视频在线免费观看| 亚洲视频在线观看免费视频| 久久不见久久见免费视频7| 激情内射亚洲一区二区三区爱妻| 成人毛片免费观看视频在线 | 久青草国产免费观看| 亚洲欧洲国产精品香蕉网| 美女视频黄a视频全免费网站色窝| 亚洲三级电影网址| 午夜国产精品免费观看| 国产偷国产偷亚洲清高APP| 亚洲Av无码乱码在线播放| a级毛片免费高清毛片视频| 亚洲成人福利在线| 日韩毛片免费在线观看| 国产V片在线播放免费无码| 亚洲黄色免费电影| 青青草国产免费久久久下载| 一级有奶水毛片免费看| 久久亚洲精品中文字幕| 国产精品无码免费视频二三区| 中国一级特黄高清免费的大片中国一级黄色片 | 亚洲日本在线电影| 亚洲精品午夜无码电影网| 九九九精品成人免费视频| 一区视频免费观看| 亚洲AV无码成人专区|