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

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

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

    上善若水
    In general the OO style is to use a lot of little objects with a lot of little methods that give us a lot of plug points for overriding and variation. To do is to be -Nietzsche, To bei is to do -Kant, Do be do be do -Sinatra
    posts - 146,comments - 147,trackbacks - 0

    JDK1.4開始提供Logging實現,據說當初JDK打算采用Log4J的,后來因為某些原因談判沒談攏,然后就自己開發了一套,不知道是為了報復而故意不沿用Log4J的命名方式和抽象方式,還是開發這個模塊的人水平不夠,或沒用心,亦或是我用Commons LoggingLog4J習慣了,看JDKLogging實現怎么看怎么不爽~~~吐個槽額~~~~

    JDK Logging將日志打印抽象成以下幾個類之間的交互:

    1.    Level,定義日志的級別,類似Log4J中的Level類。

    JDK Logging采用了完全不同于Log4J中對級別的抽象。在JDK Logging中,默認定義了以下幾個級別:SEVERE(對應Log4J中的ERRORFATAL)、WARNING(對應Log4J中的WARN)、INFO(對應Log4J中的INFO)、CONFIG(對應Log4J中的DEBUG)、FINE(對應Log4J中的TRACE)、FINER(對應Log4J中的TRACE)、FINEST(對應Log4J中的TRACE)。另外,類似Log4J,JDK Logging也定義了兩個特殊的級別:ALLOFF,分別對應打印所有級別的日志和關閉日志打印。

    Level中包含三個字段:namevalue、resourceBundleName。其中name指定級別名稱,value指定該級別對應的一個int值,其值從SEVERE開始依次遞減,resourceBundleName定義本地化后的級別名稱,默認是sun.util.logging.resources.logging,即我們在日志中看到警告、信息等級別字段就是通過調用LevelgetLocalizedName()方法,讀取resourceBundleName對應的resource值來獲得的,這也是Log4J中沒有聽過的。

    Level還定義了一個parse()方法,它可以支持解析name字符串、代表級別的int值(以字符串的形式)、以及對應的Localized名稱,如果所有的都不滿足需求,則拋出IllegalArgumentException。

    最后,Level還實現了readResolve()方法,從而確保反序列化后的Level只是Level類中定義的幾個實例(出了自定義的Level實例)。

    2.    LogRecord,封裝了打印一條一直所包含的所有數據,類似Log4J中的LoggingEvent。

    它包含了以下信息:

    a.    日志級別(level

    b.    全局標識號(sequenceNumber,即沒創建一個LogRecordsequenceNumber都會自增1

    c.    打印這條日志語句所在的類的名稱(sourceClassName),可以通過調用inferCaller()方法解析出來。解析實現則是通過實例化一個Throwable實例,通過解析該實例的Call Stack即可得出打印這條日志所在的類的名稱和方法名稱,這里貌似不支持行號、文件名等信息。并且通過設置needToInferCaller字段(不可序列化)來判斷sourceClassNamesourceMethodName是否已經取得,從而不用每次調用的時候都去解析而提升性能。

    d.    打印這條日志語句所在調用方法的名稱(sourceMethodName),它也是通過調用inferCaller()方法解析出來。

    e.    打印消息(message

    f.     線程號(threadID),對LogRecord本身而言,從0開始對每個線程自增1

    g.    創建LogRecord的時間(millis

    h.    打印日志中的異常(thrown

    i.      日志名稱(loggerName

    j.     資源名稱(resourceBundleName

    k.    參數列表(parameters數組),在Formatter中通過MessageFormat使用這些參數列表,并在序列化是手動調用其toString()方法序列化,而不是采用默認的序列化方式。

    l.      ResourceBundle實例,獲取本地消息,不可序列化。

    3.    Formatter,根據配置格式化一條日志記錄,類似Log4J中的Layout

    JDK Logging支持兩種類型的FormatterSimpleFormatterXMLFormatter,默認采用SimpleFormatter,它先打印日期和時間、LoggerNamesource ClassName、方法名稱,然后換行,在打印日志級別、本地化后的消息,然后換行,打印異常信息。而XMLFormatter實現getHead()、getTail()方法,并且將每條記錄寫成一條<record></record>記錄。吐槽一下,它的實現是在是太不專業了~~。

    4.    Handler,實現將日志寫入指定目的地,如ConsoleHandlerFileHandler、SocketHandler即對應將日志寫入控制臺、文件、Socket端口。它類似Log4J中的Appender。

    Handler包含對Formatter、Level、Filter的引用,其中FormatterLogRecord格式化成String字符串;Level定義當前Handler支持的日志級別;而Filter則提供一個用戶自定義的過濾一些日志的擴展點。

    public interface Filter {

            public boolean isLoggable(LogRecord record);

    }

    用戶可以定義自己的Filter類以實現用戶自定義的過濾邏輯。Handler還定義了encoding屬性,以配置底層日志的輸出格式。

    Handler中最終要的方法是publish(),它實現了真正打印日志消息的邏輯。

    public abstract void close() throws SecurityException;

     

    默認JDK Logging實現了StreamHandler,而StreamHandler有三個子類:ConsoleHandlerFileHandler、SocketHandlerStreamHandler支持的配置有:

    java.util.logging.StreamHandler.level 設置當前Handler支持的級別,默認為FINE

    java.util.logging.StreamHandler.filter 設置當前HandlerFilter,默認為null

    java.util.logging.StreamHandler.formatter 設置當前HandlerFormatter類,默認為SimpleFormatter

    java.util.logging.StreamHandler.encoding 設置當前Handler的編碼方式,默認為null

     

    ConsoleHandler只是將OutputStream設置為System.err,其他實現和StreamHandler類似。

     

    SocketHandlerOutputStream綁定到對應的端口號中,其他也和StreamHandler類似。另外它還增加了兩個配置:java.util.logging.SocketHandler.portjava.util.logging.SocketHandler.host分別對應端口號和主機。

     

    FileHandler支持指定文件名模板(java.util.logging.FileHandler.pattern),文件最大支持大小(java.util.logging.FileHandler.limit,字節為單位,0為沒有限制),循環日志文件數(java.util.logging.FileHandler.count)、對已存在的日志文件是否往后添加(java.util.logging.FileHandler.append)。

    FileHandler支持的文件模板參數有:

    /     目錄分隔符

    %t   系統臨時目錄

    %h 系統當前用戶目錄

    %g 生成的以區別循環日志文件名

    %u 一個唯一的數字以處理沖突問題

    %% 一個%

    5.    LogManager類,讀取配置文件和管理Logger實例,類似Log4JLogRepository。

    LogManager類初始化時,用戶可以通過指定java.util.logging.manager系統屬性以自定義LogManager,默認使用LogManager類本身。初始化完成后創建RootLogger,并將新創建的RootLogger實例加入到LogManager中。LogManager中將所有創建的Logger緩存在loggers字段中(Hashtable,name作為keyWeakReference<Logger>作為value)。RootLoggername為空,因而所有對RootLogger的配置都從”.”開始。

     

    Logger的配置支持一下幾種方式:

    <name>.level=INFO|CONFIG….

    handers=<handlerName1>,<handlerName2>…. (”,”分隔或以空格、TAB等字符分隔,全局Handler)

    config=<configClassName1>,<configClassName2>….(自定義類,實現在其構造函數中實現自定義配置)

    <name>.userParentHandlers=true|false|1|0

    <name>.handlers=<handlerName1>,<handlerName2>…(”,”分隔或以空格、TAB等字符分隔)

    <handlerName>.level=INFO|CONFIG….

    以及各自Handler本身支持的配置,具體各自的Handler

     

    用戶可以通過以下方式自定義配置文件:

    a.    設置系統屬性java.util.logging.config.class,由自定義類的構造函數實現自定義配置,如調用LogManager、Logger中的一些靜態方法。

    b.    設置系統屬性java.util.logging.config.file,自定義配置文件路徑。讀取該文件中的內容作為配置信息。

    c.    默認使用${java.home}/lib/logging.properties文件作為配置文件(JDK已經提供了一些默認配置,一般是${JRE_HOME}/lib/logging.properties文件)

     

    類似Log4J,LogManager也將Logger構建成樹狀結構,并且對那些暫時沒有真正Logger實例的節點,使用LogNode,同樣構建成樹,這個實現也類似Log4JProvisionNode

    6.    Logger類,用戶打印log接口,類似Log4J中的Logger。

    Logger包含name、HandlersresourceBundleName、useParentHandlers、filter、anonymouslevelObject、parent、kids等字段。其中其他字段都比較容易理解,anonymous比較難理解,按注釋,它是用來表達當前Logger是一個匿名Logger,即不會被加入到LogManager中,因而也不需要安全檢查,匿名Logger一般在Applet中使用,對Applet不了解,因而也無法做更詳細的解釋。在構建樹時,該Logger同時保持了父節點和子節點的所有引用,對JDK這個Logging的實現一直無力吐槽。

    Logger提供getLogger()接口,這個也是一般用戶直接打交道的接口,傳入name,返回緩存的Logger實例或新創建一個Logger實例。

    對匿名Logger,Logger提供getAnonymousLogger()接口。log(LogRecord)方法是對打印日志的真正實現:

    public void log(LogRecord record) {

        if (record.getLevel().intValue() < levelValue || levelValue == offValue) {

            return;

        }

        synchronized (this) {

            if (filter != null && !filter.isLoggable(record)) {

                return;

            }

        }

        Logger logger = this;

        while (logger != null) {

            Handler targets[] = logger.getHandlers();

            if (targets != null) {

                for (int i = 0; i < targets.length; i++) {

                    targets[i].publish(record);

                }

            }

            if (!logger.getUseParentHandlers()) {

                break;

            }

            logger = logger.getParent();

        }

    }

    其他log方法只是對該方法中LogRecord中不同字段參數的組合。其他logp()系類方法只是提供給用戶自定log所在的方法名和類名;而entering、existing、thrown等幾個方法只是幾個傻逼的命名而已。

     

    最后給張JDK Logging的類圖吧:


    posted on 2012-11-08 00:49 DLevin 閱讀(4217) 評論(0)  編輯  收藏 所屬分類: Logging
    主站蜘蛛池模板: 久久亚洲AV无码西西人体| 国产免费小视频在线观看| 香蕉国产在线观看免费| 91嫩草亚洲精品| 亚洲AV日韩AV永久无码久久| 国产aa免费视频| 成年女人毛片免费播放人| 亚洲av无码专区在线电影天堂| 亚洲精品无码不卡| 亚洲日韩激情无码一区| 亚洲国产成人久久笫一页| 在线观着免费观看国产黄| A国产一区二区免费入口| 精品国产亚洲一区二区三区在线观看| 久久久久久亚洲AV无码专区| 性感美女视频免费网站午夜| 57pao一国产成视频永久免费| 免费黄网站在线观看| 国产线视频精品免费观看视频| 免费视频精品一区二区| 亚洲精品美女久久久久9999| 亚洲AV日韩AV高潮无码专区| 亚洲AV区无码字幕中文色| 精品国产亚洲一区二区三区| 亚洲乱码无码永久不卡在线| 国产午夜亚洲不卡| 亚洲日韩在线第一页| 国产成人亚洲影院在线观看| 亚洲人成无码网WWW| 国产91精品一区二区麻豆亚洲 | 亚洲AV综合色区无码一区| 亚洲精品中文字幕乱码三区| 久久亚洲国产成人影院网站| 国产亚洲色视频在线| 亚洲人成网77777亚洲色 | 久青草视频97国内免费影视| 国产乱妇高清无乱码免费| a视频在线观看免费| 日韩精品无码专区免费播放| 99在线热视频只有精品免费| 91精品国产免费久久久久久青草|