java日誌組件介紹(common-logging,log4j,slf4j,logback )

來源:互聯網
上載者:User

標籤:

slf4j與jul、log4j1、log4j2、logback的整合原理

slf4j

先從一個簡單的使用案例來說明

2.1 簡單的使用案例

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

public static void main(String[] args){

    if(logger.isDebugEnabled()){

        logger.debug("slf4j-log4j debug message");

    }

    if(logger.isInfoEnabled()){

        logger.debug("slf4j-log4j info message");

    }

    if(logger.isTraceEnabled()){

        logger.debug("slf4j-log4j trace message");

    }

}

上述Logger介面、LoggerFactory類都是slf4j自己定義的。

2.2 使用原理

LoggerFactory.getLogger(Log4jSlf4JTest.class)的源碼如下:

public static Logger getLogger(String name) {

    ILoggerFactory iLoggerFactory = getILoggerFactory();

    return iLoggerFactory.getLogger(name);

}

上述獲取Log的過程大致分成2個階段

獲取ILoggerFactory的過程 (從字面上理解就是生產Logger的工廠)

根據ILoggerFactory獲取Logger的過程

下面來詳細說明:

1 獲取ILoggerFactory的過程

又可以分成3個過程:

1.1 從類路徑中尋找org/slf4j/impl/StaticLoggerBinder.class類

ClassLoader.getSystemResources("org/slf4j/impl/StaticLoggerBinder.class")

如果找到多個,則輸出 Class path contains multiple SLF4J bindings,表示有多個日誌實現與slf4j進行了綁定

下面看下當出現多個StaticLoggerBinder的時候的輸出日誌(簡化了一些內容):

SLF4J: Class path contains multiple SLF4J bindings.

SLF4J: Found binding in [slf4j-log4j12-1.7.12.jar!/org/slf4j/impl/StaticLoggerBinder.class]

SLF4J: Found binding in [logback-classic-1.1.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]

SLF4J: Found binding in [slf4j-jdk14-1.7.12.jar!/org/slf4j/impl/StaticLoggerBinder.class]

SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.

SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]

1.2 “隨機選取"一個StaticLoggerBinder.class來創建一個單例

StaticLoggerBinder.getSingleton()

這裏的"隨機選取"可以見官方文檔說明:

SLF4J API is designed to bind with one and only one underlying logging framework at a time. If more than one binding is present on the class path, 

SLF4J will emit a warning, listing the location of those bindings

The warning emitted by SLF4J is just that, a warning. Even when multiple bindings are present,SLF4J will pick one logging 

framework/implementation and bind with it. The way SLF4J picks a binding is determined by the JVM and for all practical purposes should be considered random

1.3 根據上述創建的StaticLoggerBinder單例,返回一個ILoggerFactory實例

StaticLoggerBinder.getSingleton().getLoggerFactory()

所以slf4j與其他實際的日誌架構的整合jar包中,都會含有這樣的一個org/slf4j/impl/StaticLoggerBinder.class類檔案,並且提供一個ILoggerFactory的實現

2 根據ILoggerFactory獲取Logger的過程

這就要看具體的ILoggerFactory類型了,下面的整合來詳細說明

3 slf4j與jdk-logging整合

3.1 需要的jar包

slf4j-api

slf4j-jdk14

對應的maven依賴為:

<dependency>

    <groupId>org.slf4j</groupId>

    <artifactId>slf4j-api</artifactId>

    <version>1.7.12</version>

</dependency>

<dependency>

    <groupId>org.slf4j</groupId>

    <artifactId>slf4j-jdk14</artifactId>

    <version>1.7.12</version>

</dependency>

3.2 使用案例

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

public static void main(String[] args){

    if(logger.isDebugEnabled()){

        logger.debug("jul debug message");

    }

    if(logger.isInfoEnabled()){

        logger.info("jul info message");

    }

    if(logger.isWarnEnabled()){

        logger.warn("jul warn message");

    }

}

上述的Logger、LoggerFactory都是slf4j自己的API中的內容,沒有jdk自帶的logging的蹤影,然後打出來的日誌卻是通過jdk自帶的logging來輸出的,如下:

四月 28, 2015 7:33:20 下午 com.demo.log4j.JulSlf4jTest main

資訊: jul info message

四月 28, 2015 7:33:20 下午 com.demo.log4j.JulSlf4jTest main

警告: jul warn message

3.3 使用案例原理分析

先看下slf4j-jdk14 jar包中的內容:

jul與slf4j整合

從中可以看到:

的確是有org/slf4j/impl/StaticLoggerBinder.class類

該StaticLoggerBinder返回的ILoggerFactory類型將會是JDK14LoggerFactory

JDK14LoggerAdapter就是實現了slf4j定義的Logger介面

下面梳理下整個流程:

1 獲取ILoggerFactory的過程

由於類路徑下有org/slf4j/impl/StaticLoggerBinder.class,所以會選擇slf4j-jdk14中的StaticLoggerBinder來創建單例對象並返回ILoggerFactory,

來看下StaticLoggerBinder中的ILoggerFactory是什麼類型:

private StaticLoggerBinder() {

    loggerFactory = new org.slf4j.impl.JDK14LoggerFactory();

}

所以返回了JDK14LoggerFactory的實例

2 根據ILoggerFactory獲取Logger的過程

來看下JDK14LoggerFactory是如何返回一個slf4j定義的Logger介面的實例的,源碼如下:

java.util.logging.Logger julLogger = java.util.logging.Logger.getLogger(name);

Logger newInstance = new JDK14LoggerAdapter(julLogger);

可以看到,就是使用jdk自帶的logging的原生方式來先創建一個jdk自己的java.util.logging.Logger實例,參見jdk-logging的原生寫法

然後利用JDK14LoggerAdapter將上述的java.util.logging.Logger包裝成slf4j定義的Logger實例

所以我們使用slf4j來進行編程,最終會委託給jdk自帶的java.util.logging.Logger去執行。

4 slf4j與log4j1整合

4.1 需要的jar包

slf4j-api

slf4j-log4j12

log4j

maven依賴分別為:

<!-- slf4j -->

<dependency>

    <groupId>org.slf4j</groupId>

    <artifactId>slf4j-api</artifactId>

    <version>1.7.12</version>

</dependency>


<!-- slf4j-log4j -->

<dependency>

    <groupId>org.slf4j</groupId>

    <artifactId>slf4j-log4j12</artifactId>

    <version>1.7.12</version>

</dependency>


<!-- log4j -->

<dependency>

    <groupId>log4j</groupId>

    <artifactId>log4j</artifactId>

    <version>1.2.17</version>

</dependency>

4.2 使用案例

第一步:編寫log4j.properties設定檔,放到類路徑下

log4j.rootLogger = debug, console

log4j.appender.console = org.apache.log4j.ConsoleAppender

log4j.appender.console.layout = org.apache.log4j.PatternLayout

log4j.appender.console.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} %m%n

設定檔的詳細內容不是本部落格關注的重點,不再說明,自行搜尋

第二步:代碼中如下使用

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

public static void main(String[] args){

    if(logger.isDebugEnabled()){

        logger.debug("slf4j-log4j debug message");

    }

    if(logger.isInfoEnabled()){

        logger.info("slf4j-log4j info message");

    }

    if(logger.isTraceEnabled()){

        logger.trace("slf4j-log4j trace message");

    }

}

補充說明:

1 設定檔同樣可以隨意放置,如log4j1原生方式加載設定檔的方式log4j1原生開發

2 注意兩者方式的不同:

slf4j:  Logger logger=LoggerFactory.getLogger(Log4jSlf4JTest.class);

log4j:  Logger logger=Logger.getLogger(Log4jTest.class);

slf4j的Logger是slf4j定義的介面,而log4j的Logger是類。LoggerFactory是slf4j自己的類

4.3 使用案例原理分析

先來看下slf4j-log4j12包中的內容:

log4j與slf4j的整合

的確是有org/slf4j/impl/StaticLoggerBinder.class類

該StaticLoggerBinder返回的ILoggerFactory類型將會是Log4jLoggerFactory

Log4jLoggerAdapter就是實現了slf4j定義的Logger介面

來看下具體過程:

1 獲取對應的ILoggerFactory

從上面的slf4j的原理中我們知道:ILoggerFactory是由StaticLoggerBinder來創建出來的,所以可以簡單分成2個過程:

1.1 第一個過程:slf4j尋找綁定類StaticLoggerBinder

使用ClassLoader來加載 “org/slf4j/impl/StaticLoggerBinder.class"這樣的類的url,然後就找到了slf4j-log4j12包中的StaticLoggerBinder

1.2 第二個過程:創建出StaticLoggerBinder實例,並創建出ILoggerFactory

源碼如下:

StaticLoggerBinder.getSingleton().getLoggerFactory()

以slf4j-log4j12中的StaticLoggerBinder為例,創建出的ILoggerFactory為Log4jLoggerFactory

2 根據ILoggerFactory獲取Logger的過程

來看下Log4jLoggerFactory是如何返回一個slf4j定義的Logger介面的實例的,源碼如下:

org.apache.log4j.Logger log4jLogger;

if (name.equalsIgnoreCase(Logger.ROOT_LOGGER_NAME))

    log4jLogger = LogManager.getRootLogger();

else

    log4jLogger = LogManager.getLogger(name);


Logger newInstance = new Log4jLoggerAdapter(log4jLogger);

2.1 我們可以看到是通過log4j1的原生方式,即使用log4j1的LogManager來獲取,引發log4j1的加載設定檔,然後初始化,

最後返回一個org.apache.log4j.Logger log4jLogger,參見log4j1原生的寫法

2.2 將上述的org.apache.log4j.Logger log4jLogger封裝成Log4jLoggerAdapter,而Log4jLoggerAdapter是實現了slf4j的介面,

所以我們使用的slf4j的Logger介面實例(這裏即Log4jLoggerAdapter)都會委託給內部的org.apache.log4j.Logger實例

5 slf4j與log4j2整合

5.1 需要的jar包

slf4j-api

log4j-api

log4j-core

log4j-slf4j-impl (用於log4j2與slf4j整合)

對應的maven依賴分別是:

<!-- slf4j -->

<dependency>

    <groupId>org.slf4j</groupId>

    <artifactId>slf4j-api</artifactId>

    <version>1.7.12</version>

</dependency>

<!-- log4j2 -->

<dependency>

    <groupId>org.apache.logging.log4j</groupId>

    <artifactId>log4j-api</artifactId>

    <version>2.2</version>

</dependency>

<dependency>

    <groupId>org.apache.logging.log4j</groupId>

    <artifactId>log4j-core</artifactId>

    <version>2.2</version>

</dependency>

<!-- log4j-slf4j-impl -->

<dependency>

    <groupId>org.apache.logging.log4j</groupId>

    <artifactId>log4j-slf4j-impl</artifactId>

    <version>2.2</version>

</dependency>

5.2 使用案例

第一步:編寫log4j2的設定檔log4j2.xml,簡單如下:、

<?xml version="1.0" encoding="UTF-8"?>

<Configuration status="WARN">

  <Appenders>

    <Console name="Console" target="SYSTEM_OUT">

      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>

    </Console>

  </Appenders>

  <Loggers>

    <Root level="debug">

      <AppenderRef ref="Console"/>

    </Root>

  </Loggers>

</Configuration>

第二步:使用方式

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

public static void main(String[] args){

    if(logger.isTraceEnabled()){

        logger.trace("slf4j-log4j2 trace message");

    }

    if(logger.isDebugEnabled()){

        logger.debug("slf4j-log4j2 debug message");

    }

    if(logger.isInfoEnabled()){

        logger.info("slf4j-log4j2 info message");

    }

}

5.3 使用案例原理分析

先來看下log4j-slf4j-impl包中的內容:

log4j與slf4j的整合

的確是有org/slf4j/impl/StaticLoggerBinder.class類

該StaticLoggerBinder返回的ILoggerFactory類型將會是Log4jLoggerFactory(這裏的Log4jLoggerFactory與上述log4j1整合時的Log4jLoggerFactory是不一樣的)

Log4jLogger就是實現了slf4j定義的Logger介面

來看下具體過程:

1 獲取對應的ILoggerFactory

1.1 第一個過程:slf4j尋找綁定類StaticLoggerBinder

使用ClassLoader來加載 “org/slf4j/impl/StaticLoggerBinder.class"這樣的類的url,然後就找到了log4j-slf4j-impl包中的StaticLoggerBinder

1.2 第二個過程:創建出StaticLoggerBinder實例,並創建出ILoggerFactory

log4j-slf4j-impl包中的StaticLoggerBinder返回的ILoggerFactory是Log4jLoggerFactory

2 根據ILoggerFactory獲取Logger的過程

來看下Log4jLoggerFactory是如何返回一個slf4j定義的Logger介面的實例的,源碼如下:

@Override

protected Logger newLogger(final String name, final LoggerContext context) {

    final String key = Logger.ROOT_LOGGER_NAME.equals(name) ? LogManager.ROOT_LOGGER_NAME : name;

    return new Log4jLogger(context.getLogger(key), name);

}


@Override

protected LoggerContext getContext() {

    final Class<?> anchor = ReflectionUtil.getCallerClass(FQCN, PACKAGE);

    return anchor == null ? LogManager.getContext() : getContext(ReflectionUtil.getCallerClass(anchor));

}

2.1 我們可以看到是通過log4j2的原生方式,即使用log4j2的LoggerContext來獲取,

返回一個org.apache.logging.log4j.core.Logger即log4j2定義的Logger介面實例,參見log4j2原生的寫法

2.2 將上述的org.apache.logging.log4j.core.Logger封裝成Log4jLogger,而Log4jLogger是實現了slf4j的Logger介面的,

所以我們使用的slf4j的Logger介面實例(這裏即Log4jLogger)都會委託給內部的log4j2定義的Logger實例。

上述獲取LoggerContext的過程也是log4j2的原生方式:

LogManager.getContext()

該操作會去加載log4j2的設定檔,引發log4j2的初始化

6 slf4j與logback整合

6.1 需要的jar包

slf4j-api

logback-core

logback-classic(已含有對slf4j的整合套件)

對應的maven依賴為:

<!-- slf4j-api -->

<dependency>

    <groupId>org.slf4j</groupId>

    <artifactId>slf4j-api</artifactId>

    <version>1.7.12</version>

</dependency>

<!-- logback -->

<dependency> 

    <groupId>ch.qos.logback</groupId> 

    <artifactId>logback-core</artifactId> 

    <version>1.1.3</version> 

</dependency> 

<dependency> 

    <groupId>ch.qos.logback</groupId> 

    <artifactId>logback-classic</artifactId> 

    <version>1.1.3</version> 

</dependency>

6.2 使用案例

第一步:編寫logback的設定檔logback.xml,簡單如下:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">

    <encoder>

      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>

    </encoder>

  </appender>

  <root level="DEBUG">          

    <appender-ref ref="STDOUT" />

  </root>  

</configuration>

第二步:使用方式

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


public static void main(String[] args){

    if(logger.isDebugEnabled()){

        logger.debug("slf4j-logback debug message");

    }

    if(logger.isInfoEnabled()){

        logger.info("slf4j-logback info message");

    }

    if(logger.isTraceEnabled()){

        logger.trace("slf4j-logback trace message");

    }

}

6.3 使用案例原理分析

先來看下logback-classic包中與slf4j整合的內容:

log4j與slf4j的整合

log4j與slf4j的整合

的確是有org/slf4j/impl/StaticLoggerBinder.class類

該StaticLoggerBinder返回的ILoggerFactory類型將會是LoggerContext(logback的對象)

logback自己定義的ch.qos.logback.classic.Logger類就是實現了slf4j定義的Logger介面

1 獲取對應的ILoggerFactory

1.1 第一個過程:slf4j尋找綁定類StaticLoggerBinder

使用ClassLoader來加載 “org/slf4j/impl/StaticLoggerBinder.class"這樣的類的url,然後就找到了logback-classic包中的StaticLoggerBinder

1.2 第二個過程:創建出StaticLoggerBinder實例,並創建出ILoggerFactory

logback-classic包中的StaticLoggerBinder返回的ILoggerFactory是LoggerContext(logback的對象)

創建出單例後,同時會引發logback的初始化,這時候logback就要去尋找一系列的設定檔,嘗試加載並解析。

2 根據ILoggerFactory獲取Logger的過程

來看下LoggerContext(logback的對象)是如何返回一個slf4j定義的Logger介面的實例的:

該LoggerContext(logback的對象)返回的ch.qos.logback.classic.Logger(logback的原生Logger對象)就是slf4j的Logger實現類。


java日誌組件介紹(common-logging,log4j,slf4j,logback )

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.