slf4j+logback的配置及使用


幾種日志的區(qū)別

  • commons-logging
    apache最早提供的日志的門面接口甥捺。避免和具體的日志方案直接耦合瘟仿。類似于JDBCapi 接口,具體的的JDBC driver 實(shí)現(xiàn)由各數(shù)據(jù)庫(kù)提供商實(shí)現(xiàn)。通過統(tǒng)一接口解耦荤胁,不過其內(nèi)部也實(shí)現(xiàn)了一些簡(jiǎn)單日志方案。
  • Log4j
    Logging for Java屎债,經(jīng)典的一種日志解決方案仅政。內(nèi)部把日志系統(tǒng)抽象封裝成Loggerappender 盆驹、pattern 等實(shí)現(xiàn)圆丹。我們可以通過配置文件輕松的實(shí)現(xiàn)日志系統(tǒng)的管理和多樣化配置。
  • slf4j
    全稱為Simple Logging Facade for Java躯喇。 是對(duì)不同日志框架提供的一個(gè)門面封裝辫封。可以在部署的時(shí)候不修改任何配置即可接入一種日志實(shí)現(xiàn)方案廉丽。和commons-loging 類似倦微。個(gè)人感覺設(shè)從計(jì)上更好一些,沒有commons 那么多潛規(guī)則正压。同時(shí)有兩個(gè)額外特點(diǎn):①能支持多個(gè)參數(shù)欣福,并通過{}占位符進(jìn)行替換,避免老寫logger.isXXXEnabled這種無奈的判斷焦履,帶來性能提升見拓劝;②OSGI機(jī)制更好兼容支持雏逾。
  • logback
    作為一個(gè)通用可靠、快速靈活的日志框架郑临,將作為Log4j 的替代和slf4j 組成新的日志系統(tǒng)的完整實(shí)現(xiàn)校套。具有極佳的性能,在關(guān)鍵路徑上執(zhí)行速度是log4j 的10 倍牧抵,且內(nèi)存消耗更少笛匙。
  • Log4j2
    Log4j2Log4j的升級(jí)版,與之前的版本Log4j 1.x相比犀变、有重大的改進(jìn)妹孙,在修正了Logback固有的架構(gòu)問題的同時(shí),改進(jìn)了許多Logback所具有的功能获枝。

可以這么理解蠢正,slf4jcommons-logging是一種抽象接口,Log4j省店、Log4j2logback是它們的實(shí)現(xiàn)嚣崭,在實(shí)際使用中,一般選擇slf4j+Log4j2或者slf4j+logback懦傍。

性能對(duì)比可以看:Apache Log4j 2.0值得升級(jí)嗎

下文僅討論slf4j+logback


配置及使用

1雹舀、引入相關(guān)日志依賴,去除其他無關(guān)日志依賴

既然選擇了slf4j+logback粗俱,首先要將項(xiàng)目中的其他jar包说榆,如commons-loggingLog4j去掉寸认。
如果項(xiàng)目使用maven签财,可以使用mvn dependency:tree命令來查看描繪項(xiàng)目依賴樹,看哪些顯式的dependecy依賴了它們偏塞。
spring-core里面就集成了commons-logging唱蒸,可以通過exclusions標(biāo)簽將其排除掉。

<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
            <!--因?yàn)槭褂昧藄l4j灸叼,所以去掉commons-logging-->
            <exclusions>
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
</dependency>

但spring本身日志就使用的commons-logging神汹,僅僅去掉就會(huì)使其不能正常工作,還需要添加commons loggingslf4j的橋接器jcl-over-slf4j怜姿,如下在項(xiàng)目中添加該依賴:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>${jcl.over.slf4j.version}</version>
</dependency>

如果有直接使用log4j的組件慎冤,也要將log4j排除掉,同時(shí)添加log4j-over-slf4沧卢。

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>log4j-over-slf4j</artifactId>
</dependency>

最后,可以使用mvn dependency:tree或者mvn dependency:list查看項(xiàng)目依賴醉者,看是否存在重復(fù)引入等但狭,比如我們使用slf4j+logback的方案披诗,只需要引入logback-classic即可,不必再顯示添加slf4j-apilogback-core立磁,因?yàn)?code>logback-classic本身依賴它們呈队。

<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>${logback.version}</version>
</dependency>

這一步就是引入logbackslf4j,去掉common-logging唱歧、Log4j宪摧、Log4j等無關(guān)日志組件,同時(shí)添加commons loggingslf4j的橋接器jcl-over-slf4j(如果項(xiàng)目中原來使用到了commons logging)颅崩。

2几于、配置logback

logback在啟動(dòng)時(shí),根據(jù)以下步驟尋找配置文件:①在classpath中尋找logback-test.xml文件→②如果找不到logback-test.xml沿后,則在 classpath中尋找logback.groovy文件→③如果找不到 logback.groovy沿彭,則在classpath中尋找logback.xml文件
如果上述的文件都找不到,則logback會(huì)使用JDKSPI機(jī)制查找 META-INF/services/ch.qos.logback.classic.spi.Configurator中的 logback 配置實(shí)現(xiàn)類尖滚,這個(gè)實(shí)現(xiàn)類必須實(shí)現(xiàn)Configuration接口喉刘,使用它的實(shí)現(xiàn)來進(jìn)行配置
如果上述操作都不成功,logback 就會(huì)使用它自帶的 BasicConfigurator 來配置漆弄,并將日志輸出到console睦裳。

這里采用xml格式的配置文件:在resources目錄下新建logback.xml文件,logback.xml文件的具體配置如下(僅供參考):

<?xml version="1.0" encoding="UTF-8"?>
<!--scan:
            當(dāng)此屬性設(shè)置為true時(shí)撼唾,配置文件如果發(fā)生改變推沸,將會(huì)被重新加載,默認(rèn)值為true券坞。
scanPeriod:
            設(shè)置監(jiān)測(cè)配置文件是否有修改的時(shí)間間隔鬓催,如果沒有給出時(shí)間單位,默認(rèn)單位是毫秒恨锚。當(dāng)scan為true時(shí)宇驾,此屬性生效。默認(rèn)的時(shí)間間隔為1分鐘猴伶。
debug:
            當(dāng)此屬性設(shè)置為true時(shí)课舍,將打印出logback內(nèi)部日志信息,實(shí)時(shí)查看logback運(yùn)行狀態(tài)他挎。默認(rèn)值為false筝尾。

configuration 子節(jié)點(diǎn)為 appender、logger办桨、root

            -->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <!--用于區(qū)分不同應(yīng)用程序的記錄-->
    <contextName>edu-cloud</contextName>
    <!--日志文件所在目錄筹淫,如果是tomcat,如下寫法日志文件會(huì)在則為${TOMCAT_HOME}/bin/logs/目錄下-->
    <property name="LOG_HOME" value="logs"/>

    <!--控制臺(tái)-->
    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!--格式化輸出:%d表示日期呢撞,%thread表示線程名损姜,%-5level:級(jí)別從左顯示5個(gè)字符寬度 %logger輸出日志的logger名 %msg:日志消息饰剥,%n是換行符 -->
            <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] %-5level %logger{36} : %msg%n</pattern>
            <!--解決亂碼問題-->
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!--滾動(dòng)文件-->
    <appender name="infoFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- ThresholdFilter:臨界值過濾器,過濾掉 TRACE 和 DEBUG 級(jí)別的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_HOME}/log.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory><!--保存最近30天的日志-->
        </rollingPolicy>
        <encoder>
            <charset>UTF-8</charset>
            <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] %-5level %logger{36} : %msg%n</pattern>
        </encoder>
    </appender>

    <!--滾動(dòng)文件-->
    <appender name="errorFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
             <!-- ThresholdFilter:臨界值過濾器摧阅,過濾掉 TRACE 和 DEBUG 級(jí)別的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>error</level>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_HOME}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory><!--保存最近30天的日志-->
        </rollingPolicy>
        <encoder>
            <charset>UTF-8</charset>
            <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] %-5level %logger{36} : %msg%n</pattern>
        </encoder>
    </appender>

    <!--將日志輸出到logstack-->
    <!--<appender name="logstash" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <destination>47.93.173.81:7002</destination>
        <encoder class="net.logstash.logback.encoder.LogstashEncoder">
            <charset>UTF-8</charset>
        </encoder>
        <keepAliveDuration>5 minutes</keepAliveDuration>
    </appender>-->

    <!--這里如果是info汰蓉,spring、mybatis等框架則不會(huì)輸出:TRACE < DEBUG < INFO <  WARN < ERROR-->
    <!--root是所有l(wèi)ogger的祖先棒卷,均繼承root顾孽,如果某一個(gè)自定義的logger沒有指定level,就會(huì)尋找
    父logger看有沒有指定級(jí)別比规,直到找到root若厚。-->
    <root level="debug">
        <appender-ref ref="stdout"/>
        <appender-ref ref="infoFile"/>
        <appender-ref ref="errorFile"/>
        <appender-ref ref="logstash"/>
    </root>

    <!--為某個(gè)包單獨(dú)配置logger

    比如定時(shí)任務(wù),寫代碼的包名為:com.seentao.task
    步驟如下:
    1苞俘、定義一個(gè)appender盹沈,取名為task(隨意,只要下面logger引用就行了)
    appender的配置按照需要即可


    2吃谣、定義一個(gè)logger:
    <logger name="com.seentao.task" level="DEBUG" additivity="false">
      <appender-ref ref="task" />
    </logger>
    注意:additivity必須設(shè)置為false乞封,這樣只會(huì)交給task這個(gè)appender,否則其他appender也會(huì)打印com.seentao.task里的log信息岗憋。

    3肃晚、這樣,在com.seentao.task的logger就會(huì)是上面定義的logger了仔戈。
    private static Logger logger = LoggerFactory.getLogger(Class1.class);
    -->

</configuration>

在進(jìn)行配置的時(shí)候关串,主要要理解或記住以下幾點(diǎn)(主要標(biāo)簽的用處):

  • appender,負(fù)責(zé)定義日志的輸出目的地(控制臺(tái)监徘、日志文件晋修、滾動(dòng)日志文件,其他如logstash等)凰盔。

    • encoder負(fù)責(zé)定義日志的輸出樣式和字符編碼墓卦,如果在控制臺(tái)出現(xiàn)?????或亂碼,則指定編碼(一般是UTF-8)就好了户敬。
    • filter負(fù)責(zé)過濾日志落剪,即使logger傳來了dubug級(jí)別以上的日志,如果filter中設(shè)定了級(jí)別為info尿庐,則該appender只會(huì)將info級(jí)別及以上的日志輸出到目的地忠怖。
    • rollingPolicy負(fù)責(zé)制定日志文件的滾動(dòng)規(guī)則,是根據(jù)日志文件大小還是根據(jù)日期進(jìn)行滾動(dòng)抄瑟。
  • logger凡泣,負(fù)責(zé)定義我們實(shí)際代碼中使用的loggerlogger中有一個(gè)非常重要的屬性namename必須指定问麸。在logback中往衷,logger有繼承關(guān)系钞翔,而所有的logger的祖先是root严卖。
    舉個(gè)例子,如果我們有個(gè)類叫UserService布轿,所在的包為com.maxwell.service哮笆,在UserService中要打印日志,我們一般會(huì)這么寫:

①private  Logger logger = LoggerFactory.getLogger(UserService.class);
或者
②private  Logger logger = LoggerFactory.getLogger("com.maxwell.service.UserService");

這兩種寫法是一樣的汰扭,第①中寫法實(shí)際會(huì)轉(zhuǎn)化為②中的方式來獲取一個(gè)logger實(shí)例稠肘。
當(dāng)我們寫下這行代碼時(shí),logback會(huì)依次檢查以下各個(gè)logger實(shí)例的是否存在萝毛,如果不存在則依次創(chuàng)建:

com
com.maxwell
com.maxwell.service
com.maxwell.service.UserService

而創(chuàng)建logger實(shí)例的時(shí)候项阴,就會(huì)去配置文件中查找名字為comcom.maxwell笆包、com.maxwell.service环揽、com.maxwell.service.UserServicelogge標(biāo)簽,并根據(jù)其中定義的規(guī)則創(chuàng)建庵佣。所以歉胶,假如你在配置文件中沒有定義name為上述字符串的logger時(shí),就會(huì)找到root這個(gè)祖先巴粪,根據(jù)root標(biāo)簽定義的規(guī)則創(chuàng)建logger實(shí)例通今。

理解了上面的這一點(diǎn),想要實(shí)現(xiàn)某個(gè)包或者某個(gè)類單獨(dú)輸出到某日志文件的需求就很好實(shí)現(xiàn)了:①定義一個(gè)appender肛根,指明日志文件的輸出目的地辫塌;②定義一個(gè)loggername設(shè)為那個(gè)包或類的全路徑名派哲。如果只想將這個(gè)類或包的日志輸出到剛才定義的appender中臼氨,就將additivity設(shè)置為false

還有就是狮辽,上面的參考配置可以保證mybatissql語句一也、spring的日志正常輸出到控制臺(tái),但由于mybatissql語句輸出的級(jí)別為debug喉脖,所以不會(huì)輸出到nameinfoFileappender中椰苟,因?yàn)樵?code>appender中設(shè)置了級(jí)別為info的過濾器filter,如果想將mybatissql語句也輸出到日志文件中树叽,請(qǐng)將info改為debug舆蝴。
也就是,一條日志想要順利到達(dá)輸出目的地,除了logger的級(jí)別要低于該級(jí)別洁仗,appender中的filter中設(shè)置的級(jí)別也要低于該級(jí)別层皱。(TRACE < DEBUG < INFO < WARN < ERROR)

3、使用

在代碼中獲取logger時(shí)赠潦,我們可能有兩種方式:

private static Logger logger = LoggerFactory.getLogger(UserService.class);
private Logger logger = LoggerFactory.getLogger(UserService.class);

你可能會(huì)認(rèn)為不加static會(huì)為UserService類的不同實(shí)例創(chuàng)建多個(gè)logger實(shí)例叫胖,實(shí)際不是的,某個(gè)類的logger實(shí)例一旦創(chuàng)建她奥,logback會(huì)將其緩存在一個(gè)map中(Map<String, Logger> loggerCache)瓮增,下次獲取的時(shí)候直接從這個(gè)map中獲取。所以哩俭,上述兩種寫法性能差距不大绷跑,只多一個(gè)很小的從cache中取對(duì)象的開銷:加上static,下次獲取的時(shí)候就直接從內(nèi)存中取了(類變量是多個(gè)實(shí)例共享的)凡资,不會(huì)再調(diào)用LoggerFactory.getLogger(UserService.class)砸捏,而不加static則從logback的緩存中取,需要調(diào)用LoggerFactory.getLogger(UserService.class)隙赁。

最后要注意的是垦藏,這里的LoggerLoggerFactoryslf4j包里的,不要選成了java.util.logging鸳谜。如果你的IDE出現(xiàn)了slf4jjava自帶日志包外的其他選項(xiàng)膝藕,就要考慮你是不是沒有將其他不相關(guān)的日志組件從你的項(xiàng)目中去掉。


參考

logback中l(wèi)ogger對(duì)象的創(chuàng)建過程源碼分析
Why log4j's Logger.getLogger() need pass a Class type?
logback logback.xml常用配置詳解
java日志咐扭,需要知道的幾件事(commons-logging,log4j,slf4j,logback)
logback 配置詳解
logback為單獨(dú)的包配置日志輸出文件
Apache Log4j 2.0值得升級(jí)嗎

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末芭挽,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蝗肪,更是在濱河造成了極大的恐慌袜爪,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件薛闪,死亡現(xiàn)場(chǎng)離奇詭異辛馆,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)豁延,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門昙篙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人诱咏,你說我怎么就攤上這事苔可。” “怎么了袋狞?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵焚辅,是天一觀的道長(zhǎng)映屋。 經(jīng)常有香客問我,道長(zhǎng)同蜻,這世上最難降的妖魔是什么棚点? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮湾蔓,結(jié)果婚禮上瘫析,老公的妹妹穿的比我還像新娘。我一直安慰自己卵蛉,他們只是感情好颁股,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布么库。 她就那樣靜靜地躺著傻丝,像睡著了一般。 火紅的嫁衣襯著肌膚如雪诉儒。 梳的紋絲不亂的頭發(fā)上葡缰,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音忱反,去河邊找鬼泛释。 笑死,一個(gè)胖子當(dāng)著我的面吹牛温算,可吹牛的內(nèi)容都是我干的怜校。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼注竿,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼茄茁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起巩割,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤裙顽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后宣谈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體愈犹,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年闻丑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了漩怎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嗦嗡,死狀恐怖勋锤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情酸钦,我是刑警寧澤怪得,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布咱枉,位于F島的核電站,受9級(jí)特大地震影響徒恋,放射性物質(zhì)發(fā)生泄漏蚕断。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一入挣、第九天 我趴在偏房一處隱蔽的房頂上張望亿乳。 院中可真熱鬧,春花似錦径筏、人聲如沸葛假。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽聊训。三九已至,卻和暖如春恢氯,著一層夾襖步出監(jiān)牢的瞬間带斑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工勋拟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留勋磕,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓敢靡,卻偏偏與公主長(zhǎng)得像挂滓,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子啸胧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

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

  • 在應(yīng)用程序中添加日志記錄總的來說基于三個(gè)目的:監(jiān)視代碼中變量的變化情況赶站,周期性的記錄到文件中供其他應(yīng)用進(jìn)行統(tǒng)計(jì)分析...
    時(shí)待吾閱讀 4,961評(píng)論 0 6
  • 在項(xiàng)目開發(fā)過程中,我們可以通過 debug 查找問題吓揪。而在線上環(huán)境我們查找問題只能通過打印日志的方式查找問題亲怠。因此...
    Java架構(gòu)閱讀 3,459評(píng)論 2 41
  • 一、Log4j簡(jiǎn)介 Log4j有三個(gè)主要的組件:Loggers(記錄器)柠辞,Appenders (輸出源)和Layo...
    默默守護(hù)閱讀 1,899評(píng)論 2 8
  • 在應(yīng)用程序中添加日志記錄總的來說基于三個(gè)目的:監(jiān)視代碼中變量的變化情況团秽,周期性的記錄到文件中供其他應(yīng)用進(jìn)行統(tǒng)計(jì)分析...
    時(shí)待吾閱讀 4,951評(píng)論 1 13
  • Log Java日志:(slf4j、log4j叭首、logback习勤、common-logging ) slf4j 是規(guī)...
    年少懵懂丶流年夢(mèng)閱讀 17,491評(píng)論 1 11