1. 程式人生 > >Java 日誌組件(二)

Java 日誌組件(二)

() span 需要 etl 目前 slf4 this war 默認

3、log4j2

  log4j2與log4j發生了很大變化,不兼容。log4j僅僅作為一個實際的日誌框架,slf4j、commons-logging作為門面統一各種日誌框架的混亂格局,現在log4j2也想跳出來當門面,也想統一大家。日誌越來越亂了

  • log4j-api:作為日誌接口層,用於統一底層日誌系統。
  • log4j-core:作為上述日誌接口的實現,是一個實際的日誌框架。

  3.1、maven依賴

 1 <dependency>
 2     <groupId>org.apache.logging.log4j</groupId>
 3     <
artifactId>log4j-api</artifactId> 4 <version>2.2</version> 5 </dependency> 6 <dependency> 7 <groupId>org.apache.logging.log4j</groupId> 8 <artifactId>log4j-core</artifactId> 9 <version>2.2</version> 10 </dependency
>

  3.2、使用方式

    • 編寫log4j2.xml配置文件(目前log4j2只支持xml、json、yuml,不再支持properties)
 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <Configuration status="WARN">
 3   <Appenders>
 4     <Console name="Console" target="SYSTEM_OUT">
 5       <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"
/> 6 </Console> 7 </Appenders> 8 <Loggers> 9 <Root level="debug"> 10 <AppenderRef ref="Console"/> 11 </Root> 12 </Loggers> 13 </Configuration>
    • 使用
 1 private static final Logger logger=LogManager.getLogger(Log4j2Test.class);
 2 
 3 public static void main(String[] args){
 4     if(logger.isTraceEnabled()){
 5         logger.debug("log4j trace message");
 6     }
 7     if(logger.isDebugEnabled()){
 8         logger.debug("log4j debug message");
 9     }
10     if(logger.isInfoEnabled()){
11         logger.debug("log4j info message");
12     }
13 }

    和log4j不同的是此時的Logger是log4j-api中定義的接口,而log4j中的Logger是類

  3.3、使用過程簡單分析

    • 獲取底層使用的LoggerContextFactory

        同樣LogManager的類加載會去尋找log4j-api定義的LoggerContextFactory接口的底層實現,獲取方式有三種

      • 嘗試從jar中尋找log4j2.component.properties文件,如果配置了log4j2.loggerContextFactory則使用該LoggerContextFactory。
      • 如果沒找到,嘗試從jar包中尋找META-INF/log4j-provider.properties文件,如log4j-core-2.2中就有該文件。
      • 如果找到多個,取優先級最高的(該文件中指定了LoggerContextFactory,同時指定了優先級FactoryPriority),如log4j-core-2.2中log4j-provider.properties的文件內容如下 
1 LoggerContextFactory = org.apache.logging.log4j.core.impl.Log4jContextFactory
2 Log4jAPIVersion = 2.1.0
3 FactoryPriority= 10
      • 上述方式還沒找到,就使用默認的SimpleLoggerContextFactory
    • 使用LoggerContextFactory獲取LoggerContext
    • 根據LoggerContext獲取Logger
      • 會首先判斷LoggerContext是否被初始化過了,沒有則進行初始化
      • 獲取ConfigurationFactory,從配置中獲取和插件中獲取(log4j-core核心包中有三個YamlConfigurationFactory、JsonConfigurationFactory、XmlConfigurationFactory)
      • 以上文的案例中,會使用XmlConfigurationFactory來加載log4j2.xml配置文件
      • LoggerContext初始化後,就可以獲取或者創建Logger了

  3.4、主要對象總結

    • LogManager: 它的類加載會去尋找LoggerContextFactory接口的底層實現,會從jar包中的配置文件中尋找,如上面所述

    • LoggerContextFactory : 用於創建LoggerContext,不同的日誌實現系統會有不同的實現,如log4j-core中的實現為Log4jContextFactory

    • PropertyConfigurator: 用於解析log4j.properties文件

    • LoggerContext : 它包含了配置信息,並能創建log4j-api定義的Logger接口實例,並緩存這些實例

    • ConfigurationFactory:上述LoggerContext解析配置文件,需要用到ConfigurationFactory,目前有三個YamlConfigurationFactory、JsonConfigurationFactory、XmlConfigurationFactory,分別解析yuml json xml形式的配置文件

4、logback

    • logback-core
    • logback-classic
    • slf4j-api

  4.1、對應maven的依賴

 1 <dependency> 
 2     <groupId>ch.qos.logback</groupId> 
 3     <artifactId>logback-core</artifactId> 
 4     <version>1.1.3</version> 
 5 </dependency> 
 6 <dependency> 
 7     <groupId>ch.qos.logback</groupId> 
 8     <artifactId>logback-classic</artifactId> 
 9     <version>1.1.3</version> 
10 </dependency>
11 <dependency>
12     <groupId>org.slf4j</groupId>
13     <artifactId>slf4j-api</artifactId>
14     <version>1.7.12</version>
15 </dependency>

  4.2、使用

 1 private static final Logger logger=LoggerFactory.getLogger(LogbackTest.class);
 2 
 3 public static void main(String[] args){
 4     if(logger.isDebugEnabled()){
 5         logger.debug("slf4j-logback debug message");
 6     }
 7     if(logger.isInfoEnabled()){
 8         logger.debug("slf4j-logback info message");
 9     }
10     if(logger.isTraceEnabled()){
11         logger.debug("slf4j-logback trace message");
12     }
13     
14     LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
15     StatusPrinter.print(lc);
16 }
    • 官方使用方式,其實就和slf4j集成了起來

      上述的Logger、LoggerFactory都是slf4j自己的接口與類

    • 沒有配置文件的情況下,使用的是默認配置。搜尋配置文件的過程如下:

1 Logback tries to find a file called logback.groovy in the classpath.
2 If no such file is found, logback tries to find a file called logback-test.xml in the classpath.
3 If no such file is found, it checks for the file logback.xml in the classpath..
4 If no such file is found, and the executing JVM has the ServiceLoader (JDK 6 and above) the ServiceLoader will be used to resolve an implementation of com.qos.logback.classic.spi.Configurator. The first implementation found will be used. See ServiceLoader documentation for more details
5 If none of the above succeeds, logback configures itself automatically using the BasicConfigurator which will cause logging output to be directed to the console.
6 The fourth and last step is meant to provide a default (but very basic) logging functionality in the absence of a configuration file

  也可以在類路徑上加一個類似如下的logback.xml的配置文件,logback則會去解析對應的配置文件。

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <configuration>
 3 
 4   <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
 5     <encoder>
 6       <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
 7     </encoder>
 8   </appender>
 9 
10   <root level="DEBUG">          
11     <appender-ref ref="STDOUT" />
12   </root>  
13   
14 </configuration>

  4.3、使用過程簡單分析

    • slf4j與底層的日誌系統進行綁定在jar包中尋找org/slf4j/impl/StaticLoggerBinder.class 這個類,如在logback-classic中就含有這個類,如果找到多個StaticLoggerBinder,則表明目前底層有多個實際的日誌框架,slf4j會隨機選擇一個。
    • 使用上述找到的StaticLoggerBinder創建一個實例,並返回一個LoggerFactory實例:
1 return StaticLoggerBinder.getSingleton().getLoggerFactory()

      以logback-classic中的StaticLoggerBinder為例,在StaticLoggerBinder.getSingleton()過程中:會去加載解析配置文件 源碼如下

 1 public URL findURLOfDefaultConfigurationFile(boolean updateStatus) {
 2     ClassLoader myClassLoader = Loader.getClassLoaderOfObject(this);
 3     //尋找logback.configurationFile的系統屬性
 4     URL url = findConfigFileURLFromSystemProperties(myClassLoader, updateStatus);
 5     if (url != null) {
 6       return url;
 7     }
 8     //尋找logback.groovy
 9     url = getResource(GROOVY_AUTOCONFIG_FILE, myClassLoader, updateStatus);
10     if (url != null) {
11       return url;
12     }
13     //尋找logback-test.xml
14     url = getResource(TEST_AUTOCONFIG_FILE, myClassLoader, updateStatus);
15     if (url != null) {
16       return url;
17     }
18     //尋找logback.xml
19     return getResource(AUTOCONFIG_FILE, myClassLoader, updateStatus);
20 }

    目前路徑都是定死的,只有logback.configurationFile的系統屬性是可以更改的,所以如果我們想更改配置文件的位置(不想放在類路徑下),則需要設置這個系統屬性:

1 System.setProperty("logback.configurationFile", "/path/to/config.xml");

    解析完配置文件後,返回的LoggerFactory實例的類型是LoggerContext(它包含了配置信息)

    • 根據返回的LoggerFactory實例,來獲取Logger就是根據上述的LoggerContext來創建一個Logger,每個logger與LoggerContext建立了關系,並放到LoggerContext的緩存中,就是LoggerContext的如下屬性:

1 private Map<String, Logger> loggerCache;

    其實上述過程就是slf4j與其他日誌系統的綁定過程。不同的日誌系統與slf4j集成,都會有一個StaticLoggerBinder類,並會擁有一個LoggerFactory的實現。

    

Java 日誌組件(二)