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

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

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

    Change Dir

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

    統計

    留言簿(18)

    積分與排名

    “牛”們的博客

    各個公司技術

    我的鏈接

    淘寶技術

    閱讀排行榜

    評論排行榜

    logback那些事

    logback:

    logback可以認為是log4j的升級版,依然出自Ceki Gülcü,使用簡單,只需要在你的classpath里包含slf4j-api.jar、logback-core.jar以及logback-classic.jar即可。

    簡單代碼示例如下:

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;

    import ch.qos.logback.classic.LoggerContext;
    import ch.qos.logback.core.util.StatusPrinter;
    public class LogTest {


        public static void main(String[] args) {

            Logger logger = LoggerFactory
                    .getLogger(LogTest .class.getName());
            logger.debug("Hello world.");

    }

    其中的logger對象和LoggerFactory都來自slf4j項目,slf4j是一個很好的facade,包裝了接口,就像之前寫的一篇文章中的提到的commons-logging框架。

    同樣也可以認為logback+slf4j是log4j+commons-logging的升級版吧。

    logback的架構:

    logback包含3個子工程——classic、core和access。core是其他兩個的基礎,也是logback的核心;classic擴展了core,內置了slf4j,但也支持各種其他log門面。同log4j一樣,logback的主要構成也是Logger、Appender和Layout。Logger是核心控制器及調用入口,Appender主管配置和寫日志實際process,Layout控制日志樣式,是Appender的重要配置。值得注意的是,3個基本核心居然不都在core模塊中,Logger是在classic里的。

    對于Logger來講,和Log4j一樣,Logger是一個層次結構,每個logger都有一個name屬性在LoggerFactory中被一個map管理著。對于Logback來說,這個factory就是classic下的LoggerContext。這里插一段自我理解,在做facade模式的時候,代碼結構可能會引入一個占位性質的類,就像slf4j中的StaticLoggerBinder,這個類在org.slf4j.impl包下,是一個單例,但是私有構造函數卻拋出了一個異常,這個在不熟悉這種寫法時會產生困惑。其實這是很合理的,logback的classic中也有org.slf4j.impl這個包,其中也有StaticLoggerBinder這個類,但是內容完整了許多。這就完成了slf4j的任務,同時解除了耦合。我認為這種解耦合方式非常好,plugin的感覺。

    再回來說LoggerContext,這個對應了log4j的LogManager和Hierarchy,用一個hashtable來維護logger的cache。代碼真的是簡潔了很多,再回頭看看log4j中LogManager的getLogger方法,就知道logback的簡潔了,一個while遍歷省去了一個hierarchy。當然這里得補充一句,log4j包括logback的整個日志框架對于logger對象,是一個層次結構,這也是為什么log4j中有個Hierarchy的東西的原因。是一個層次的話,對于通過包名來管理日志記錄等級的管理方式來說,就存在著level的控制,也就是說,你某個包名的類被設定了日志級別是什么,那么對應級別以下的日志才會被打印出來。有這樣一個規則,logger的日志記錄有效level由hierarchy中離它最近且方向向上(upwards)的一個logger的級別決定。如官網上的例子:

    image

    這里有4個logger,但是只有root被設定了level是DEBUG,其他幾個logger由于沒有被設定,依照規則,就都是root的level了。

    image

    第二個例子中,每個logger都自己設定了level,那么依據規則,離它最近的被使用,當然自己離自己最近了。

    image

    第三個例子里,X.Y沒有設定level,那么離它最近且upwards的一個是X,那么X.Y的level就和X的一樣。

    level控制是日志框架的基礎,什么樣的日志在什么環境下被打印出來,這種設定可以配置才是一個合理的日志系統。一貫的level控制規則如下顯示:

    image

    appender這個東西,和log4j是一樣的,支持一個logger有多個appender,在AppenderAttachableImpl里會維護一個CopyOnWriteArrayList來存放一個logger的appender。每次log的時候都會遍歷這個list里的appender然后調用對應的doAppend方法。我們在配置的時候每個logger的配置上有個additivity屬性,默認為true。appender這個東西同logger一樣有繼承性。additivity屬性就是控制這種繼承的,true代表開啟,false代表關閉,一般使用都會設置false,因為如果是true,那么如果appender比較多的話可能日志打的就有點太離譜了。

    Layout和log4j一樣,我沒有細研究過,但是我認為這是控制輸出的一大法寶,下次研究layout的時候做一個詳細的分享,一般大家都使用patternLayout,寫個表達式足以。

    在之前的那篇寫log的文章中,提到過一個優化寫法,就是不要直接寫出這樣的代碼:

    logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));

    構造string參數是復雜且耗時的。要用if判斷一下。而slf4j提供了比較合適的解決方法:

    Object entry = new SomeObject(); 
    logger.debug("The entry is {}.", entry);

    這樣的代碼就更符合程序設計人員的編寫習慣,而且可讀性我認為要遠遠高于用+號連接。但是遺憾的是,這種編碼風格作者并沒有持續貫徹下去,沒有用變長參數,而是用的object[]終止了參數的個數。也就是說,你對于多個變量的log的話,只能這么寫:

    Object[] paramArray = {newVal, below, above};
    logger.debug("Value {} was inserted between {} and {}.", paramArray);

    在執行log的時候,會有一個判斷流程,依據官網上的介紹,我簡要翻譯一下:

    1,Get the filter chain decision:如果存在,嘗試調用TurboFilterTurboFilter 會設置一個整個上下文范圍的閾值或者過濾掉每個log請求的相關參數。如果這個filter返回的參數是FilterReply.DENY ,那么log結束;如果FilterReply.NEUTRAL返回,則進入第2步,如果FilterReply.ACCEPT ,直接第3步。

    2, Apply the basic selection rule,如果log請求的閾值和高于配置的閾值,那么放棄處理該log。

    3, Create a LoggingEvent object,logback會構建一個LoggingEvent對象,包含了所有的請求參數。其中有些參數可能是延遲加載的。

    4, Invoking appenders,logback調用doAppend方法。

    5, Formatting the output,layout會把LoggingEvent對象按固定格式格式化并返回字符串形式,像SocketAppender這樣的方法不會返回字符串,相似的只會把它序列化。

    6,  Sending out the LoggingEvent,把最終形式打印到對應的目的地址。

    流程圖見這里http://logback.qos.ch/manual/underTheHood.html

    最后還是通過性能討論結束這篇短文,性能的東西,我們不去看代碼的話,是無法估計復雜度的變化的。那么就官網上給出的3條提示,第一點針對參數構建,第二點針對level的定位,這個在看過代碼后,發現確實精簡了,尤其是那種復雜的hierarchy結構沒有了,線性的鏈條運行起來明顯會快,算是去除冗余做了優化吧。第3條針對說format和write會快,尤其是format被大力投入改進,這個在看過代碼后,可以做個比較。

    本文算是一篇半自主半翻譯的文章吧,重在學習。

    參考文獻:

    http://logback.qos.ch/manual/introduction.html

    posted on 2012-03-31 17:14 changedi 閱讀(2925) 評論(1)  編輯  收藏 所屬分類: Java技術

    主站蜘蛛池模板: 国产高清视频免费在线观看| 亚洲精品无码日韩国产不卡av| 亚洲AV日韩AV永久无码色欲| 免费福利网站在线观看| 亚洲伊人久久大香线蕉影院| 1000部无遮挡拍拍拍免费视频观看| 亚洲成熟xxxxx电影| 最好看最新的中文字幕免费 | 日本免费人成在线网站| 亚洲综合自拍成人| 国产成人福利免费视频| 亚洲中文字幕久在线| 国产精品视频永久免费播放| 亚洲色大成网站WWW国产| 日韩免费三级电影| 日日躁狠狠躁狠狠爱免费视频| 区三区激情福利综合中文字幕在线一区亚洲视频1 | 黄页免费视频播放在线播放| 亚洲精品国产精品乱码不卡| 三级黄色在线免费观看| 中文字幕亚洲精品| 四虎影院在线免费播放| 免费无遮挡无码视频在线观看 | 区三区激情福利综合中文字幕在线一区亚洲视频1| 日韩在线观看视频免费| 亚洲国产美女精品久久久久∴| 99视频在线看观免费| 亚洲最大av资源站无码av网址| www.亚洲色图.com| 国产精品免费一区二区三区四区| 久久亚洲AV成人无码软件| 青草草在线视频永久免费| 99视频在线观看免费| 亚洲三级视频在线| 久久久久久亚洲精品不卡| 222www免费视频| 男女男精品网站免费观看| 亚洲美女视频一区二区三区| 在线a亚洲v天堂网2018| 97视频免费观看2区| 偷自拍亚洲视频在线观看99|