天天看點

Java日志架構梳理-SLF4J+log4j

  log4j的配置檔案是用來設定紀錄器的級别、存放位置和布局的,可以通過Java屬性檔案(key=value)格式設定或XML格式設定。log4j配置檔案元素簡介:

Logger

  Logger是一個允許應用紀錄日志的對象,開發者不必考慮輸出位置。應用可将具體需要列印的資訊通過一個Object傳遞。Logger是命名了的實體,每個Logger互相獨立,它們的名字大小寫敏感且遵循階層化命名規則:

如果logger的名稱帶上一個點号後是另外一個logger的名稱的字首,則前者被稱為後者的祖先。如果logger與其後代logger之間沒有其他祖先,則前者就被稱為子logger之父。

  根logger(rootLogger)位于logger等級的最頂端,它是每個層次等級的共同始祖。擷取根logger的方式:

  logger可被配置設定級别,如果logger沒有被配置設定級别,那它将從沒有配置設定級别的最近祖先繼承級别,直至根logger,預設情況下,根logger級别為DEBUG。

  logger可通過additivity辨別設定其Appender的疊加性,定義如下:

logger A記錄語句的輸出會發送給A及其祖先的全部Appender,如果logger A的某個祖先B設定疊加性辨別為false,則A的輸出會發送給A與B(包含B)之間的所有Appender,但不會發送給B的任何祖先Appender

Appender

  每個Appender可獨立配置紀錄日志的裝置,可以是:控制台、檔案、資料庫、消息系統等。log4j提供的Appender具體有如下幾種:

類型 描述
org.apache.log4j.ConsoleAppender 控制台
org.apache.log4j.FileAppender 檔案
org.apache.log4j.DailyRollingFileAppender 每天産生一個日志檔案
org.apache.log4j.RollingFileAppender 檔案大小到達指定尺寸的時候産生一個新的檔案
org.apache.log4j.WriterAppender 将日志資訊以流格式發送到任意指定的地方

Layout

  Layout也被稱為Formatters,負責對日志時間中的資料進行轉換和格式化,Layout決定了資料在一條日志記錄中的最終形式。log4j提供的Layout有如下幾種:

類型 描述
org.apache.log4j.HTMLLayout 以HTML表格形式布局
org.apache.log4j.PatternLayout 可以靈活地指定布局模式
org.apache.log4j.SimpleLayout 包含日志資訊的級别和資訊字元串
org.apache.log4j.TTCCLayout 包含日志産生的時間、線程、類别等等資訊

  log4j采用類似C語言中printf的列印格式化日志資訊,列印參數如下

類型 描述
%m 輸出代碼中制定的消息
%p 輸出日志級别
%r 輸出自應用啟動到出處該日志記錄耗費的毫秒數
%c 輸出觸發該日志事件的類
%t 輸出觸發該日志事件的線程
%d 輸出日志事件發生的時間,如:%-d{yyyy-MM-dd HH:mm:ss}
%l 輸出日志發生的位置,包括類資訊、線程、行數

Level

每個列印日志都可以單獨指定日志級别,通過配置檔案來控制輸出級别。log4j提供的日志級别如下:

類型 描述
ALL 最低級别,用于打開所有日志記錄
TRACE 指定粒度比DEBUG更細的事件
DEBUG 指定細粒度資訊事件,對調試應用程式有幫助
INFO 指定粗粒度資訊事件,突出強調程式運作過程
WARN 指定具有潛在危害的情況
ERROR 指定錯誤事件,程式仍然允許運作
FATAL 指定非常嚴重的錯誤事件,可能導緻應用程式終止
OFF 最高等級,用于關閉日志記錄

SLF4J+log4j實踐

  log4j擴充卡綁定可添加如下pom依賴,添加配置後會自動拉下來兩個依賴包,分别是slf4j-api-1.7.25和log4j-1.2.17。

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.25</version>
</dependency>
           

  log4j必須指定配置檔案或預設配置。如果程式中引入了以上包,在沒有編寫配置檔案,且沒有設定預設配置器時列印日志,log4j會報如下錯誤:

  

public class Test {

    public static void main(String [] args) {
        //BasicConfigurator.configure();
        Logger logger  = LoggerFactory.getLogger(Test.class);
        logger.debug( " this is {} debug log", Test.class.getName() );
        logger.error( " this is {} error log", Test.class.getName());
    }
}

結果:
log4j:WARN No appenders could be found for logger (com.xiaofan.test.Test).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j//faq.html#noconfig for more info.
           

  通過BasicConfigurator.configure() 可指定log4j預設配置器,該配置預設生成rootLogger,并添加一個控制台Appender,源碼如下:

static public void configure() {
    Logger root = Logger.getRootLogger();
    root.addAppender(new ConsoleAppender(
           new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN)));
  }
           

  列印日志結果如下:

[main] DEBUG com.xiaofan.test.Test  -  this is com.xiaofan.test.Test debug log
 [main] ERROR com.xiaofan.test.Test  -  this is com.xiaofan.test.Test error log
           

  編寫log4j配置檔案有兩種方式:Java屬性檔案(key=value)和XML形式。

  • log4j.properties

      

      屬性配置檔案範例如下:

### set log levels ###
log4j.rootLogger = debug,stdout,D,E

### 輸出到控制台 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern =  %-d{yyyy-MM-dd HH:mm:ss} %p [%c] %m%n

### 輸出到日志檔案 ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG 
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

### 儲存異常資訊到單獨檔案 ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File = logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n


### logger ### 
# 設定後com.xiaofan路徑下的日志将隻輸出ERROR日志
#log4j.logger.com.xiaofan=ERROR
           

  将log4j.properties檔案放到工程的resources檔案夾下,如果程式沒有顯示指定其他配置檔案,log4j會預設加載log4j.properties檔案作為配置檔案。可通過PropertyConfigurator.configure()顯示指定外部配置檔案。

  

  測試代碼如下:

package com.xiaofan.test;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.xml.DOMConfigurator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by Jerry on 17/7/24.
 */
public class Test {

    public static void main(String [] args) {
        PropertyConfigurator.configure(Test.class.getResource("/log4j.properties"));
        Logger logger  = LoggerFactory.getLogger(Test.class);
        logger.debug( " this is {} debug log", Test.class.getName() );
        logger.error( " this is {} error log", Test.class.getName());
    }
}

結果:
console:
    -- :: DEBUG [com.xiaofan.test.Test]  this is com.xiaofan.test.Test debug log
    -- :: ERROR [com.xiaofan.test.Test]  this is com.xiaofan.test.Test error log
/logs/error.log:
    -- ::  [ main: ] - [ ERROR ]   this is com.xiaofan.test.Test error log
/logs/log.log:
    -- ::  [ main: ] - [ DEBUG ]   this is com.xiaofan.test.Test debug log
    -- ::  [ main: ] - [ ERROR ]   this is com.xiaofan.test.Test error log
           
  • log4j.xml

      XML配置檔案如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/' >

    <appender name="console" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern"
                   value="[%d{yyyy-MM-dd HH:mm:ss,SSS\} %-5p] %c{2\} [%t] - %m%n" />
        </layout>
        <filter class="org.apache.log4j.varia.LevelRangeFilter">
            <param name="levelMin" value="debug" />
            <param name="levelMax" value="error" />
            <param name="AcceptOnMatch" value="true" />
        </filter>
    </appender>

    <appender name="ERROR" class="org.apache.log4j.RollingFileAppender">
        <param name="File" value="logs/error.log" />
        <param name="Append" value="true" />
        <param name="threshold" value="error" />
        <param name="MaxBackupIndex" value="10" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%p (%c:%L)- %m%n" />
        </layout>
    </appender>

    <appender name="INFO" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="File" value="logs/log.log" />
        <param name="DatePattern" value="'.'yyyy-MM-dd'.log'" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern"
                   value="[%d{MMdd HH:mm:ss SSS\} %-5p] [%t] %c{3\} - %m%n" />
        </layout>
    </appender>

    <logger name="mylogger" additivity="true">
        <level value="debug" />
        <appender-ref ref="INFO" />
    </logger>

    <root>
        <priority value ="debug"/>
        <appender-ref ref="INFO"/>
        <appender-ref ref="ERROR" />
        <appender-ref ref="console" />
    </root>

</log4j:configuration>
           

 将log4j.xml檔案放到工程的resources檔案夾下,如果程式沒有顯示指定其他配置檔案,log4j會預設加載log4j.xml檔案作為配置檔案。可通過DOMConfigurator.configure()顯示制定外部配置檔案。

 

  測試代碼如下:

public class Test {

    public static void main(String [] args) {
        DOMConfigurator.configure(Test.class.getResource("/log4j.xml"));
        Logger logger  = LoggerFactory.getLogger(Test.class);
        logger.debug( " this is {} debug log", Test.class.getName() );
        logger.error( " this is {} error log", Test.class.getName());
    }
}

結果:
控制台:
    [-- ::, DEBUG] test.Test [main] -  this is com.xiaofan.test.Test debug log
    [-- ::, ERROR] test.Test [main] -  this is com.xiaofan.test.Test error log
/logs/error.log
    ERROR (com.xiaofan.test.Test:)-  this is com.xiaofan.test.Test error log
/logs/log.log
    [ ::  DEBUG] [main] xiaofan.test.Test -  this is com.xiaofan.test.Test debug log
    [ ::  ERROR] [main] xiaofan.test.Test -  this is com.xiaofan.test.Test error log