上善若水
          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實(shí)現(xiàn),據(jù)說當(dāng)初JDK打算采用Log4J的,后來因為某些原因談判沒談攏,然后就自己開發(fā)了一套,不知道是為了報復(fù)而故意不沿用Log4J的命名方式和抽象方式,還是開發(fā)這個模塊的人水平不夠,或沒用心,亦或是我用Commons LoggingLog4J習(xí)慣了,看JDKLogging實(shí)現(xiàn)怎么看怎么不爽~~~吐個槽額~~~~

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

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

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

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

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

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

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

          它包含了以下信息:

          a.    日志級別(level

          b.    全局標(biāo)識號(sequenceNumber,即沒創(chuàng)建一個LogRecordsequenceNumber都會自增1

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

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

          e.    打印消息(message

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

          g.    創(chuàng)建LogRecord的時間(millis

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

          i.      日志名稱(loggerName

          j.     資源名稱(resourceBundleName

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

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

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

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

          4.    Handler,實(shí)現(xiàn)將日志寫入指定目的地,如ConsoleHandlerFileHandlerSocketHandler即對應(yīng)將日志寫入控制臺、文件、Socket端口。它類似Log4J中的Appender

          Handler包含對FormatterLevelFilter的引用,其中FormatterLogRecord格式化成String字符串;Level定義當(dāng)前Handler支持的日志級別;而Filter則提供一個用戶自定義的過濾一些日志的擴(kuò)展點(diǎn)。

          public interface Filter {

                  public boolean isLoggable(LogRecord record);

          }

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

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

          public abstract void close() throws SecurityException;

           

          默認(rèn)JDK Logging實(shí)現(xiàn)了StreamHandler,而StreamHandler有三個子類:ConsoleHandlerFileHandlerSocketHandlerStreamHandler支持的配置有:

          java.util.logging.StreamHandler.level 設(shè)置當(dāng)前Handler支持的級別,默認(rèn)為FINE

          java.util.logging.StreamHandler.filter 設(shè)置當(dāng)前HandlerFilter,默認(rèn)為null

          java.util.logging.StreamHandler.formatter 設(shè)置當(dāng)前HandlerFormatter類,默認(rèn)為SimpleFormatter

          java.util.logging.StreamHandler.encoding 設(shè)置當(dāng)前Handler的編碼方式,默認(rèn)為null

           

          ConsoleHandler只是將OutputStream設(shè)置為System.err,其他實(shí)現(xiàn)和StreamHandler類似。

           

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

           

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

          FileHandler支持的文件模板參數(shù)有:

          /     目錄分隔符

          %t   系統(tǒng)臨時目錄

          %h 系統(tǒng)當(dāng)前用戶目錄

          %g 生成的以區(qū)別循環(huán)日志文件名

          %u 一個唯一的數(shù)字以處理沖突問題

          %% 一個%

          5.    LogManager類,讀取配置文件和管理Logger實(shí)例,類似Log4JLogRepository

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

           

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

          <name>.level=INFO|CONFIG….

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

          config=<configClassName1>,<configClassName2>….(自定義類,實(shí)現(xiàn)在其構(gòu)造函數(shù)中實(shí)現(xiàn)自定義配置)

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

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

          <handlerName>.level=INFO|CONFIG….

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

           

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

          a.    設(shè)置系統(tǒng)屬性java.util.logging.config.class,由自定義類的構(gòu)造函數(shù)實(shí)現(xiàn)自定義配置,如調(diào)用LogManagerLogger中的一些靜態(tài)方法。

          b.    設(shè)置系統(tǒng)屬性java.util.logging.config.file,自定義配置文件路徑。讀取該文件中的內(nèi)容作為配置信息。

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

           

          類似Log4JLogManager也將Logger構(gòu)建成樹狀結(jié)構(gòu),并且對那些暫時沒有真正Logger實(shí)例的節(jié)點(diǎn),使用LogNode,同樣構(gòu)建成樹,這個實(shí)現(xiàn)也類似Log4JProvisionNode

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

          Logger包含nameHandlersresourceBundleNameuseParentHandlersfilteranonymouslevelObjectparentkids等字段。其中其他字段都比較容易理解,anonymous比較難理解,按注釋,它是用來表達(dá)當(dāng)前Logger是一個匿名Logger,即不會被加入到LogManager中,因而也不需要安全檢查,匿名Logger一般在Applet中使用,對Applet不了解,因而也無法做更詳細(xì)的解釋。在構(gòu)建樹時,該Logger同時保持了父節(jié)點(diǎn)和子節(jié)點(diǎn)的所有引用,對JDK這個Logging的實(shí)現(xiàn)一直無力吐槽。

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

          對匿名LoggerLogger提供getAnonymousLogger()接口。log(LogRecord)方法是對打印日志的真正實(shí)現(xiàn):

          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中不同字段參數(shù)的組合。其他logp()系類方法只是提供給用戶自定log所在的方法名和類名;而enteringexistingthrown等幾個方法只是幾個傻逼的命名而已。

           

          最后給張JDK Logging的類圖吧:


          posted on 2012-11-08 00:49 DLevin 閱讀(4223) 評論(0)  編輯  收藏 所屬分類: Logging
          主站蜘蛛池模板: 射阳县| 邻水| 房产| 鄂州市| 莱州市| 乌鲁木齐县| 栾城县| 岑巩县| 昔阳县| 瑞昌市| 富源县| 南华县| 望谟县| 阜康市| 元阳县| 荔波县| 内乡县| 上杭县| 广水市| 滁州市| 湖州市| 当涂县| 舟曲县| 美姑县| 黑龙江省| 万载县| 宁夏| 丰顺县| 和林格尔县| 抚松县| 敖汉旗| 田东县| 唐山市| 苍溪县| 汉沽区| 榆社县| 固镇县| 襄城县| 南岸区| 泾川县| 镇宁|