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

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

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

    Change Dir

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

    統(tǒng)計(jì)

    留言簿(18)

    積分與排名

    “牛”們的博客

    各個(gè)公司技術(shù)

    我的鏈接

    淘寶技術(shù)

    閱讀排行榜

    評(píng)論排行榜

    簡(jiǎn)單的log

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

    private Log log = LogFactory.getLog(CLASS.class);
    
    這樣來的。配置log已經(jīng)不是一件技術(shù)活了,我們總是使用JCL作為wraper,調(diào)用實(shí)際的底層的日志框架,而日志框架無非就是log4j,logback。這里簡(jiǎn)單的記錄一下log在系統(tǒng)中的配置和使用。 commons-log是非常簡(jiǎn)單的一個(gè)開源項(xiàng)目,apache-commons下代碼算是最少的了。功能最簡(jiǎn)單,包裝一個(gè)統(tǒng)一的log接口,然后調(diào)用實(shí)際的log框架完成日志記錄的工作。 生一個(gè)log對(duì)象,是通過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方法,首先會(huì)嘗試?yán)卯?dāng)前的classLoader去一個(gè)hashtable里取一個(gè)factory出來,這個(gè)設(shè)計(jì)為了避免資源重復(fù)(按照官方說法,getLog是一個(gè)很重的操作),利用了cache的思想,緩存了構(gòu)建過的factory。這個(gè)緩存的key就是classloader。寫到這里,插一句,這個(gè)設(shè)計(jì)在我們?yōu)橐粋€(gè)已有項(xiàng)目添加資源利用時(shí)是必備的設(shè)計(jì)之一——緩存重復(fù)利用的資源。

       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:        }

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

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

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

     

    log4j的一個(gè)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,日志打印的級(jí)別threshold以及編碼方式encoding。logger配置定義了哪些類里的log代碼會(huì)被打印,這里name指定了對(duì)應(yīng)的包名。root定義了log4j中的hierarchy類中的root logger。最終logger的所有打日志方法都會(huì)調(diào)用下面這個(gè)方法,這個(gè)方法在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:   }

    一個(gè)LoggingEvent在打日志的時(shí)候會(huì)被實(shí)例化,并且賦予一些記錄日志相關(guān)的信息。第19行的代碼其實(shí)就是在調(diào)用配置文件中配置過的appender。具體的打印樣式,會(huì)被Layout類處理。

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

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

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

    總結(jié)一下,log4j是使用最普遍的日志應(yīng)用了,依靠日志,我們記錄了信息,同時(shí)可以幫助調(diào)試,是服務(wù)器端開發(fā)的一大利器。了解日志系統(tǒng)的原理也是必需的技能。log系統(tǒng)值得深入的地方還有很多。以后繼續(xù)挖掘。

     

    參考資料:

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

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

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

    評(píng)論

    # re: 簡(jiǎn)單的log 2012-03-30 07:50 tb

    很不錯(cuò)的   回復(fù)  更多評(píng)論   


    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 国精产品一区一区三区免费视频 | 亚洲精品无码久久千人斩| 免费国产污网站在线观看不要卡| 国产一区二区三区在线观看免费| 看全免费的一级毛片| 国产亚洲色婷婷久久99精品91| 成全视频在线观看免费| 亚洲欧美在线x视频| 亚洲日产无码中文字幕| 黄色网址免费大全| 亚洲第一成年网站视频| 亚洲一区二区精品视频| 99热这里有免费国产精品| 亚洲综合偷自成人网第页色| 亚洲国产成人久久笫一页| 免费视频一区二区| 亚洲精品理论电影在线观看| 亚洲欧洲精品一区二区三区| 18禁止观看免费私人影院| 九九精品成人免费国产片| 一区二区三区免费视频观看| 亚洲国产日韩在线一区| 四虎影视在线永久免费看黄| 中中文字幕亚洲无线码| 久久青青成人亚洲精品| 96免费精品视频在线观看| 国产亚洲精品AAAA片APP| 亚洲熟女综合色一区二区三区| 亚洲а∨天堂久久精品| 好爽好紧好大的免费视频国产| 青青操免费在线视频| 亚洲色大18成人网站WWW在线播放| 亚洲日本国产乱码va在线观看| 亚洲精品高清久久| 国产精品嫩草影院免费| 30岁的女人韩剧免费观看| 国产一区二区三区亚洲综合 | 日本免费大黄在线观看| 久久免费观看国产精品| 曰批全过程免费视频免费看| 国产精品亚洲精品日韩动图 |