java日志體系

為什么要使用日志

剛開始接觸java時(shí)都使用過System.out來調(diào)試蹬敲,通過它我們能打印出一些關(guān)注的信息到控制臺(tái)便于我們調(diào)試壳坪。這種方式只限于我們平常開發(fā)時(shí)簡單測試舶得,但是生產(chǎn)環(huán)境這樣是不行的。首先這樣做會(huì)有性能上的問題爽蝴,其次使用這種方式會(huì)很麻煩沐批。例如我打印的結(jié)果需要顯示方法名稱、線程名稱蝎亚、時(shí)間等等九孩,你總不能每次都手動(dòng)拼接然后打印吧;還例如我需要將它輸入到不同的文件中发框。以上說的都是System.out所不能實(shí)現(xiàn)或者特別麻煩的地方躺彬。

混亂的日志體系

上面我們總結(jié)了System.out不足之處,所以我們正式項(xiàng)目一般都是使用的日志梅惯。但是java中的日志體系特別亂宪拥,特別對(duì)于新手來說簡直就是一臉悶逼。你肯定聽過Log4j铣减、JUL江解、JCL、Slf4j徙歼、Logback、Log4j2這些里面的幾種鳖枕,面對(duì)這么多日志相關(guān)的東西魄梯,你除此接觸簡直就是一臉悶逼。下面我們來簡單說說這些日志工具的關(guān)系和歷史宾符。

Log4j:Java之前官方并沒有提供日志相關(guān)的工具酿秸,而Log4j就是最早提供日志功能的工具了,然后大家都開始使用這個(gè)工具魏烫,而Log4j也幾乎成為Java標(biāo)準(zhǔn)的日志庫了辣苏。

JUC:log4j很流行但是并沒有成為java標(biāo)準(zhǔn)的日志庫,Sun公司推出了JUL(java Util Logging)哄褒。因?yàn)樵谥按蠹乙呀?jīng)習(xí)慣使用Log4j了稀蟋,所以JUL并沒有流行起來。

JCL:上面說了已經(jīng)存在Log4j和JUL呐赡,如果想從Log4j換成JUC或者從JUC換成Log4j很麻煩退客,需要修改所有日志調(diào)用的地方,所以Apache為了解決問題推出了JCL(Jakarta Commons Loggin)。JCL中只是定義了一套日志接口萌狂,支持在運(yùn)行時(shí)動(dòng)態(tài)的加載日志組件的實(shí)現(xiàn)档玻。也就是說我們?cè)诖a里使用JCL的API,底層我們可以使用Log4j或者JUC實(shí)現(xiàn)茫藏,這樣我們?cè)谇袚Q日志實(shí)現(xiàn)時(shí)误趴,不需要修改大量的代碼。

Slf4j和Logback:而之前開發(fā)Log4j的作者離開原來的公司之后务傲,覺得之前的日志框架還不夠牛逼凉当,于是他再次出手,掏出Slfj4和Logback(Sl4j的實(shí)現(xiàn))兩個(gè)項(xiàng)目树灶。這下java日志領(lǐng)域基本上就分成兩個(gè)幫派了纤怒,Commons Loggin和Slf4j。而隨著時(shí)間推移天通,Slf4j搭配Logback慢慢的搶占了Log4j的用戶泊窘。

Log4j 2:上面說了Slf4j搭配Logback慢慢的搶占了Log4j的用戶,這個(gè)時(shí)候Log4j推出了Log4j 2.x與Logback對(duì)戰(zhàn)像寒。

看了上面的java日志工具的發(fā)展烘豹,現(xiàn)在大概明白了日志工具的體系了吧。對(duì)于上面說的工具基本上可以分為兩類诺祸,一類是日志接口携悯,也就是日志門面,它們不提供實(shí)現(xiàn)或者提供簡單的實(shí)現(xiàn)筷笨。而另外一類是日志實(shí)現(xiàn)憔鬼,也就是實(shí)際上實(shí)現(xiàn)日志功能的工具。

對(duì)于日志工具包門面工具主要就是Slf4j和JCL這個(gè)兩個(gè)胃夏,而實(shí)際上因?yàn)樾蕟栴}轴或,目前日志門面大家都使用的是Slf4j,而JCL逐漸的退出了舞臺(tái)仰禀。

對(duì)于日志的實(shí)現(xiàn)現(xiàn)在基本上的選擇就是Log4j照雁、Logback、Log4j 2答恶。

Slf4j和Logback組合使用

這個(gè)組合應(yīng)該是目前使用最廣的饺蚊,至少我個(gè)人使用比較多,而且在Spring Boot中也默認(rèn)使用的該組合悬嗓,下面就說如何使用Slf4j和Logback組合使用污呼。

jar包說明

logback-core:Logback核心功能包,如果只是想用Logback使用這個(gè)包就可以了烫扼。

logback-access:訪問模塊集成和Servlet容器集成曙求,提供Http訪問日志的功能。

logback-classic:如果想與Slf4j集成就需要使用到這個(gè)包,這個(gè)包里面還依賴了Slf4j的包悟狱。

一般情況下我們使用Slf4j與Logback只需要在工程中添加下面的依賴即可静浴,不需要我們手動(dòng)添加Slf4j包的依賴。

<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>

Logback配置說明

如果不需要定制化的日志只需要添加相關(guān)的maven依賴就可以了挤渐,如果需要定制化需求就需要自己添加配置苹享。Logback支持通過XML和groovy的方式來配置,但是使用較多的方式還是通過XML這種方式配置浴麻。配置時(shí)我們只需要在創(chuàng)建Logback.xml文件放在resource下即可得问。

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="true">
    <!--設(shè)置變量-->
    <property name="APP_NAME" value="logback-demo"/>
    <!--上下文名稱,設(shè)置之后不能再修改-->
    <contextName>${APP_NAME}</contextName>
    <!--配置appender-->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
        </encoder>
    </appender>
    <!--配置logger-->
    <logger name="com.buydeem.share.log.logback" level="debug" additivity="true"/>
    <!--配置root-->
    <root level="info">
        <!--引用appender-->
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

configuration

上面就是一個(gè)最簡單的logback配置文件软免,首先就是configuration節(jié)點(diǎn)的配置宫纬,其中scanscanPeriod是用來監(jiān)控配置文件變化的,scan設(shè)置為true時(shí)代表會(huì)掃描配置文件的變化膏萧,而scanPeriod是用來指定掃描頻率漓骚。而debug是用來打印Logback內(nèi)部的日志,它會(huì)打印如何查找配置文件和實(shí)際應(yīng)用的日志文件等信息榛泛。

contextName

設(shè)置應(yīng)用的名稱蝌蹂,該值設(shè)置之后是無法再次修改的。簡單的說就是應(yīng)用啟動(dòng)之后曹锨,再次修改該值是不生效的孤个。

property

用來定義變量,在后續(xù)的配置中可是使用該變量沛简。

appender

日志輸出組件齐鲤,主要用來輸入和格式化日志,而且Logback中提供了多種appender組件椒楣,不同的組件有不同的效果佳遂。例如可以將日志輸出在控制臺(tái)中,還可以將日志輸出到文件中撒顿。例如我們上文中使用的ch.qos.logback.core.ConsoleAppender它就是將日志輸出到控制臺(tái)。

對(duì)于appender節(jié)點(diǎn)來說我們還可以配置其他東西荚板,例如我們可以篩選日志的級(jí)別凤壁,讓該appender中只輸出某種級(jí)別的日志。利用這個(gè)設(shè)置跪另,我們可以將不同級(jí)別的日志輸出到不同的文件中拧抖。

logger和root

logger用來設(shè)置某一個(gè)包或者具體某一個(gè)類的日志打印級(jí)別以及指定appender。你可以理解logger和root是同一種東西免绿,不同的在于root是logger的最上級(jí)唧席。對(duì)于logger節(jié)點(diǎn)中,我們可以設(shè)置的屬性有l(wèi)evel和additivity兩個(gè)屬性。

level代表該appender中輸出的最低日志級(jí)別淌哟,例如上面的配置文件中我們將其設(shè)置成debug代表低于該級(jí)別的日志將不會(huì)再logger中打印出來迹卢。如果我們沒有設(shè)置將應(yīng)用父級(jí)的level,如果logger沒有父級(jí)則會(huì)使用root中的level(root是所有l(wèi)evel最上級(jí))徒仓。

additivity用來設(shè)置該logger是否向上級(jí)傳遞腐碱,如果設(shè)置為true,該logger下打印的日志還會(huì)傳遞到root中掉弛。在我們的配置中症见,我們并沒有在logger下配置appender,但是仍然可以打印出日志殃饿。這是因?yàn)槲覀冊(cè)趓oot節(jié)點(diǎn)下配置了appender谋作,并且我們還把logger的additivity設(shè)置成了true。如果我們將該值改為false乎芳,你可以發(fā)現(xiàn)日志將不會(huì)再控制臺(tái)中輸出了遵蚜。

配置不同級(jí)別的日志內(nèi)容輸出到不同的文件

對(duì)于實(shí)際開發(fā)中我們可能需要將不同的日志輸出到不同的文件,下面是一個(gè)示例配置秒咐。

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds">
    <!--日志文件前綴谬晕,即應(yīng)用名稱 -->
    <property name="logfile.prefix" value="logback-demo"/>
    <!--日志路徑,可寫相對(duì)路徑携取,也可寫絕對(duì)路徑 -->
    <property name="log.path" value="logs"/>
    <!-- 日志輸出格式 -->
    <property name="log.pattern"
              value="%d{yyyy-MM-dd HH:mm:ss.SSS} %5level [%15thread] %40.40logger{40} [%10method,%line] : %msg%n"/>
    <!-- 控制臺(tái)輸出日志 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!--        設(shè)置日志輸出格式-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${log.pattern}</pattern>
            <!-- 編碼 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <!-- 文件輸出日志攒钳, 滾動(dòng)(時(shí)間/文件大小)輸出策略 -->
    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 過濾器雷滋,只記錄debug級(jí)別的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUG</level>
            <OnMismatch>DENY</OnMismatch>
            <OnMatch>ACCEPT</OnMatch>
        </filter>
        <!-- 日志文件路徑及文件名 -->
        <File>${log.path}/${logfile.prefix}-debug.log</File>
        <!-- 日志記錄器的滾動(dòng)策略不撑,按日期記錄 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 日志輸出格式 -->
            <FileNamePattern>${log.path}/${logfile.prefix}-debug.%d{yyyy-MM-dd}.log</FileNamePattern>
            <!-- 日志保留天數(shù) -->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <!--        設(shè)置日志輸出格式-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${log.pattern}</pattern>
            <!-- 編碼 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <!--    info級(jí)別-->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <OnMismatch>DENY</OnMismatch>
            <OnMatch>ACCEPT</OnMatch>
        </filter>
        <File>${log.path}/${logfile.prefix}-info.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${log.path}/${logfile.prefix}-info.%d{yyyy-MM-dd}.log</FileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <!--        設(shè)置日志輸出格式-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${log.pattern}</pattern>
            <!-- 編碼 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <!--    warn級(jí)別-->
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>WARN</level>
            <OnMismatch>DENY</OnMismatch>
            <OnMatch>ACCEPT</OnMatch>
        </filter>
        <File>${log.path}/${logfile.prefix}-warn.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${log.path}/${logfile.prefix}-warn.%d{yyyy-MM-dd}.log</FileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <!--        設(shè)置日志輸出格式-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${log.pattern}</pattern>
            <!-- 編碼 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <!--    error級(jí)別-->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <OnMismatch>DENY</OnMismatch>
            <OnMatch>ACCEPT</OnMatch>
        </filter>
        <File>${log.path}/${logfile.prefix}-error.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${log.path}/${logfile.prefix}-error.%d{yyyy-MM-dd}.log</FileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <!--        設(shè)置日志輸出格式-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${log.pattern}</pattern>
            <!-- 編碼 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <logger name="com.buydeem.share.log.logback" level="debug" additivity="true"/>
    <!-- 日志輸出 -->
    <root level="DEBUG">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="DEBUG_FILE"/>
        <appender-ref ref="INFO_FILE"/>
        <appender-ref ref="WARN_FILE"/>
        <appender-ref ref="ERROR_FILE"/>
    </root>
</configuration>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市晤斩,隨后出現(xiàn)的幾起案子焕檬,更是在濱河造成了極大的恐慌,老刑警劉巖澳泵,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件实愚,死亡現(xiàn)場離奇詭異,居然都是意外死亡兔辅,警方通過查閱死者的電腦和手機(jī)腊敲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來维苔,“玉大人碰辅,你說我怎么就攤上這事〗槭保” “怎么了没宾?”我有些...
    開封第一講書人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵凌彬,是天一觀的道長。 經(jīng)常有香客問我循衰,道長铲敛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任羹蚣,我火速辦了婚禮原探,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘顽素。我一直安慰自己咽弦,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開白布胁出。 她就那樣靜靜地躺著型型,像睡著了一般。 火紅的嫁衣襯著肌膚如雪全蝶。 梳的紋絲不亂的頭發(fā)上闹蒜,一...
    開封第一講書人閱讀 51,182評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音抑淫,去河邊找鬼绷落。 笑死,一個(gè)胖子當(dāng)著我的面吹牛始苇,可吹牛的內(nèi)容都是我干的砌烁。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼催式,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼函喉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起荣月,我...
    開封第一講書人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤管呵,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后哺窄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捐下,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年萌业,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蔑担。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡咽白,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鸟缕,到底是詐尸還是另有隱情晶框,我是刑警寧澤排抬,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站授段,受9級(jí)特大地震影響蹲蒲,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜侵贵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一届搁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧窍育,春花似錦卡睦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至乞娄,卻和暖如春瞬逊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背仪或。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來泰國打工确镊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人范删。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓蕾域,卻偏偏與公主長得像,于是被迫代替她去往敵國和親瓶逃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子束铭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容