log4j2 實際使用詳解

1、目錄簡介

  • 基礎部分 
    • 日誌框架簡單比較(slf4j、log4j、logback、log4j2 )
    • log4j2基礎示例
    • log4j2配置文件
  • 實戰部分 
    • slf4j + log4j2 實際使用

2、日誌框架比較(slf4j、log4j、logback、log4j2 )

  • 日誌接口(slf4j) 
    slf4j是對全部日誌框架制定的一種規範、標準、接口,並非一個框架的具體的實現,由於接口並不能獨立使用,須要和具體的日誌框架實現配合使用(如log4j、logback)html

  • 日誌實現(log4j、logback、log4j2)java

    • log4j是apache實現的一個開源日誌組件
    • logback一樣是由log4j的做者設計完成的,擁有更好的特性,用來取代log4j的一個日誌框架,是slf4j的原生實現
    • Log4j2是log4j 1.x和logback的改進版,聽說採用了一些新技術(無鎖異步、等等),使得日誌的吞吐量、性能比log4j 1.x提升10倍,並解決了一些死鎖的bug,並且配置更加簡單靈活,官網地址: http://logging.apache.org/log4j/2.x/manual/configuration.html
  • 爲何須要日誌接口,直接使用具體的實現不就好了嗎?web

    接口用於定製規範,能夠有多個實現,使用時是面向接口的(導入的包都是slf4j的包而不是具體某個日誌框架中的包),即直接和接口交互,不直接使用實現,因此能夠任意的更換實現而不用更改代碼中的日誌相關代碼。sql

    好比:slf4j定義了一套日誌接口,項目中使用的日誌框架是logback,開發中調用的全部接口都是slf4j的,不直接使用logback,調用是 本身的工程調用slf4j的接口,slf4j的接口去調用logback的實現,能夠看到整個過程應用程序並無直接使用logback,當項目須要更換更加優秀的日誌框架時(如log4j2)只須要引入Log4j2的jar和Log4j2對應的配置文件便可,徹底不用更改Java代碼中的日誌相關的代碼logger.info(「xxx」),也不用修改日誌相關的類的導入的包(import org.slf4j.Logger; 
    import org.slf4j.LoggerFactory;)數據庫

    使用日誌接口便於更換爲其餘日誌框架。apache

    log4j、logback、log4j2都是一種日誌具體實現框架,因此既能夠單獨使用也能夠結合slf4j一塊兒搭配使用)json

3、log4j2基礎示例

  1. 建立maven web 項目, 結構以下 
    這裏寫圖片描述api

  2. 配置pom.xml,引入log4j2必要的依賴(log4j-api、log4j-core)app

<properties>
    <junit.version>3.8.1</junit.version>
    <log4j.version>2.5</log4j.version>
</properties>

<!-- 使用aliyun鏡像 -->
<repositories>
  <repository>
      <id>aliyun</id>
      <name>aliyun</name>
      <url>http://maven.aliyun.com/nexus/content/groups/public</url>
  </repository>
</repositories>

<dependencies>
    <dependency>  
        <groupId>org.apache.logging.log4j</groupId>  
        <artifactId>log4j-api</artifactId>  
        <version>${log4j.version}</version>  
    </dependency>  
    <dependency>  
        <groupId>org.apache.logging.log4j</groupId>  
        <artifactId>log4j-core</artifactId>  
        <version>${log4j.version}</version>  
    </dependency>  
</dependencies>

三、 使用Main方法簡單測試 
這裏寫圖片描述框架

測試說明:

  1. 工程中只引入的jar並無引入任何配置文件,在測試的時候能夠看到有ERROR輸出:「ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console.」

  2. 輸出logger時能夠看到只有error和fatal級別的被輸出來,是由於沒有配置文件就使用默認的,默認級別是error,因此只有error和fatal輸出來

  3. 引入的包是log4j自己的包(import org.apache.logging.log4j.LogManager)

四:log2j 配置文件詳解

配置文件的格式和位置

配置文件的格式:log2j配置文件能夠是xml格式的,也能夠是json格式的, 
配置文件的位置:log4j2默認會在classpath目錄下尋找log4j2.xml、log4j.json、log4j.jsn等名稱的文件,若是都沒有找到,則會按默認配置輸出,也就是輸出到控制檯,也能夠對配置文件自定義位置(須要在web.xml中配置),通常放置在src/main/resources根目錄下便可 
這裏寫圖片描述

純Java方式:

public static void main(String[] args) throws IOException {  
    File file = new File("D:/log4j2.xml");  
    BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));  
    final ConfigurationSource source = new ConfigurationSource(in);  
    Configurator.initialize(null, source);  

    Logger logger = LogManager.getLogger("myLogger");  
}

Web工程方式:

<context-param>  
    <param-name>log4jConfiguration</param-name>  
    <param-value>/WEB-INF/conf/log4j2.xml</param-value>  
</context-param>  

<listener>  
    <listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class>  
</listener>

示例一:簡單配置(使用根控制器輸出到控制檯上)

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="info">  
            <AppenderRef ref="Console" />  
        </Root>  
    </Loggers>  
</Configuration>

示例結果:

這裏寫圖片描述

結果解釋: 
日誌管理器獲取的是根日誌器LogManager.getLogger(LogManager.ROOT_LOGGER_NAME); 
對應的log4j2.xml中的Loggers節點下的Root,由於該根日誌器的level=「info」,因此輸出的info級別以上的日誌

示例二:File Logger

<?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>

        <File name="FileAppender" fileName="D:/logs/app.log">  
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />  
        </File>  

        <!-- 發現Async 好像PatternLayout的輸出格式配置的和輸出的格式不同,不用異步就徹底同樣  -->
        <Async name="AsyncAppender">
        <AppenderRef ref="FileAppender"/>
        </Async>
    </Appenders>  

    <Loggers>  
        <Logger name="AsyncFileLogger" level="trace" additivity="true">  
            <AppenderRef ref="AsyncAppender" />  
        </Logger>
        <Root level="info">  
            <AppenderRef ref="Console" />  
        </Root>  
    </Loggers>  
</Configuration>
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Log4j2Test {

    public static void main(String[] args) {
        Logger logger = LogManager.getLogger("AsyncFileLogger"); // Logger的名稱

        logger.trace("trace level");
        logger.debug("debug level");
        logger.info("info level");
        logger.warn("warn level");
        logger.error("error level");
        logger.fatal("fatal level");
    }
}

AsyncFileLogger的additivity的值若是爲false的話,就不會在控制檯上輸出或者爲該Logger再增長一個輸出源Consloe

<Logger name="AsyncFileLogger" level="trace" additivity="false">  
    <AppenderRef ref="AsyncAppender" />  
    <AppenderRef ref="Console" />  
</Logger>

示例三: RollingRandomAccessFile

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN"> 
    <properties>
        <property name="LOG_HOME">D:/logs</property>
        <property name="FILE_NAME">mylog</property>
    </properties>


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

        <RollingRandomAccessFile name="RollingRandomAccessFile" fileName="${LOG_HOME}/${FILE_NAME}.log" filePattern="${LOG_HOME}/$${date:yyyy-MM}/${FILE_NAME}-%d{yyyy-MM-dd HH-mm}-%i.log">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1"/>
                <SizeBasedTriggeringPolicy size="10 MB"/>
            </Policies>
            <DefaultRolloverStrategy max="20"/>
        </RollingRandomAccessFile>

        <Async name="AsyncAppender">
            <AppenderRef ref="RollingRandomAccessFile"/>
        </Async>
    </Appenders>  

    <Loggers>  
        <Logger name="RollingRandomAccessFileLogger" level="info" additivity="false">  
            <AppenderRef ref="AsyncAppender" />  
            <AppenderRef ref="Console" />  
        </Logger>
    </Loggers>  
</Configuration>
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Log4j2Test {

    public static void main(String[] args) {

        Logger logger = LogManager.getLogger("RollingRandomAccessFileLogger");  
        for(int i = 0; i < 50000; i++) {  
            logger.trace("trace level");  
            logger.debug("debug level");  
            logger.info("info level");  
            logger.warn("warn level");  
            logger.error("error level");  
            logger.fatal("fatal level");  
        }  

        try {  
            Thread.sleep(1000 * 61);  
        } catch (InterruptedException e) {}  

        logger.trace("trace level");  
        logger.debug("debug level");  
        logger.info("info level");  
        logger.warn("warn level");  
        logger.error("error level");  
        logger.fatal("fatal level"); 
    }
}

這裏寫圖片描述

RollingRandomAccessFile 會根據命名規則當文件知足必定大小時就會另起一個新的文件

五:log4j2配置文件詳解

log4j2.xml文件的配置大體以下:

  • Configuration 
    • properties
    • Appenders 
      • Console 
        • PatternLayout
      • File
      • RollingRandomAccessFile
      • Async
    • Loggers 
      • Logger
      • Root 
        • AppenderRef
  • Configuration:爲根節點,有status和monitorInterval等多個屬性

    • status的值有 「trace」, 「debug」, 「info」, 「warn」, 「error」 and 「fatal」,用於控制log4j2日誌框架自己的日誌級別,若是將stratus設置爲較低的級別就會看到不少關於log4j2自己的日誌,如加載log4j2配置文件的路徑等信息
    • monitorInterval,含義是每隔多少秒從新讀取配置文件,能夠不重啓應用的狀況下修改配置
  • Appenders:輸出源,用於定義日誌輸出的地方 
    log4j2支持的輸出源有不少,有控制檯Console、文件File、RollingRandomAccessFile、MongoDB、Flume 等

    • Console:控制檯輸出源是將日誌打印到控制檯上,開發的時候通常都會配置,以便調試

    • File:文件輸出源,用於將日誌寫入到指定的文件,須要配置輸入到哪一個位置(例如:D:/logs/mylog.log)

    • RollingRandomAccessFile: 該輸出源也是寫入到文件,不一樣的是比File更增強大,能夠指定當文件達到必定大小(如20MB)時,另起一個文件繼續寫入日誌,另起一個文件就涉及到新文件的名字命名規則,所以須要配置文件命名規則 
      這種方式更加實用,由於你不可能一直往一個文件中寫,若是一直寫,文件過大,打開就會卡死,也不便於查找日誌。

      • fileName 指定當前日誌文件的位置和文件名稱
      • filePattern 指定當發生Rolling時,文件的轉移和重命名規則
      • SizeBasedTriggeringPolicy 指定當文件體積大於size指定的值時,觸發Rolling
      • DefaultRolloverStrategy 指定最多保存的文件個數
      • TimeBasedTriggeringPolicy 這個配置須要和filePattern結合使用,注意filePattern中配置的文件重命名規則是${FILE_NAME}-%d{yyyy-MM-dd HH-mm}-%i,最小的時間粒度是mm,即分鐘
      • TimeBasedTriggeringPolicy指定的size是1,結合起來就是每1分鐘生成一個新文件。若是改爲%d{yyyy-MM-dd HH},最小粒度爲小時,則每個小時生成一個文件
    • NoSql:MongoDb, 輸出到MongDb數據庫中

    • Flume:輸出到Apache Flume(Flume是Cloudera提供的一個高可用的,高可靠的,分佈式的海量日誌採集、聚合和傳輸的系統,Flume支持在日誌系統中定製各種數據發送方,用於收集數據;同時,Flume提供對數據進行簡單處理,並寫到各類數據接受方(可定製)的能力。)

    • Async:異步,須要經過AppenderRef來指定要對哪一種輸出源進行異步(通常用於配置RollingRandomAccessFile)

    PatternLayout:控制檯或文件輸出源(Console、File、RollingRandomAccessFile)都必須包含一個PatternLayout節點,用於指定輸出文件的格式(如 日誌輸出的時間 文件 方法 行數 等格式),例如 pattern=」%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n」

    %d{HH:mm:ss.SSS} 表示輸出到毫秒的時間
    %t 輸出當前線程名稱
    %-5level 輸出日誌級別,-5表示左對齊而且固定輸出5個字符,若是不足在右邊補0
    %logger 輸出logger名稱,由於Root Logger沒有名稱,因此沒有輸出
    %msg 日誌文本
    %n 換行
    
    其餘經常使用的佔位符有:
    %F 輸出所在的類文件名,如Log4j2Test.java
    %L 輸出行號
    %M 輸出所在方法名
    %l 輸出語句所在的行數, 包括類名、方法名、文件名、行數
  • Loggers:日誌器 
    日誌器分根日誌器Root和自定義日誌器,當根據日誌名字獲取不到指定的日誌器時就使用Root做爲默認的日誌器,自定義時須要指定每一個Logger的名稱name(對於命名能夠以包名做爲日誌的名字,不一樣的包配置不一樣的級別等),日誌級別level,相加性additivity(是否繼承下面配置的日誌器), 對於通常的日誌器(如Console、File、RollingRandomAccessFile)通常須要配置一個或多個輸出源AppenderRef;

    每一個logger能夠指定一個level(TRACE, DEBUG, INFO, WARN, ERROR, ALL or OFF),不指定時level默認爲ERROR

    additivity指定是否同時輸出log到父類的appender,缺省爲true。

<Logger name="rollingRandomAccessFileLogger" level="trace" additivity="true">  
    <AppenderRef ref="RollingRandomAccessFile" />  
</Logger>
  • properties: 屬性 
    使用來定義常量,以便在其餘配置的時候引用,該配置是可選的,例如定義日誌的存放位置 
    D:/logs

【實戰部分】

  1. 引入slf4j和log4j須要的依賴
<properties>
    <junit.version>3.8.1</junit.version>
    <log4j.version>2.5</log4j.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>${junit.version}</version>
      <scope>test</scope>
    </dependency>

    <!-- slf4j + log4j2 begin -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.10</version>
    </dependency>

    <dependency> <!-- 橋接:告訴Slf4j使用Log4j2 -->
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j-impl</artifactId>
        <version>2.2</version>
    </dependency>
    <dependency> <!-- 橋接:告訴commons logging使用Log4j2 -->
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-jcl</artifactId>
        <version>2.2</version>
    </dependency>

    <dependency>  
        <groupId>org.apache.logging.log4j</groupId>  
        <artifactId>log4j-api</artifactId>  
        <version>${log4j.version}</version>  
    </dependency>  
    <dependency>  
        <groupId>org.apache.logging.log4j</groupId>  
        <artifactId>log4j-core</artifactId>  
        <version>${log4j.version}</version>  
    </dependency>  
    <!-- log4j end-->
  </dependencies>

  <!-- 使用aliyun鏡像 -->
  <repositories>
    <repository>
        <id>aliyun</id>
        <name>aliyun</name>
        <url>http://maven.aliyun.com/nexus/content/groups/public</url>
    </repository>
  </repositories>

二、配置log2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN"> 
    <properties>
        <property name="LOG_HOME">D:/logs</property>
        <property name="FILE_NAME">mylog</property>
        <property name="log.sql.level">info</property>
    </properties>


    <Appenders>  
        <Console name="Console" target="SYSTEM_OUT">  
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %l - %msg%n" />  
        </Console>

        <RollingRandomAccessFile name="RollingRandomAccessFile" fileName="${LOG_HOME}/${FILE_NAME}.log" filePattern="${LOG_HOME}/$${date:yyyy-MM}/${FILE_NAME}-%d{yyyy-MM-dd HH-mm}-%i.log">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %l - %msg%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1"/>
                <SizeBasedTriggeringPolicy size="10 MB"/>
            </Policies>
            <DefaultRolloverStrategy max="20"/>
        </RollingRandomAccessFile>
    </Appenders>  

    <Loggers>  
        <Root level="info">  
            <AppenderRef ref="Console" />  
            <AppenderRef ref="RollingRandomAccessFile" />  
        </Root>

        <Logger name="com.mengdee.dao" level="${log.sql.level}" additivity="false">
             <AppenderRef ref="Console" />
        </Logger>
    </Loggers>  
</Configuration>

三、 Java

package com.mengdee.manage;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Log4j2Test {

    // Logger和LoggerFactory導入的是org.slf4j包
    private final static Logger logger = LoggerFactory.getLogger(Log4j2Test.class);
    public static void main(String[] args) {
        long beginTime = System.currentTimeMillis();

        for(int i = 0; i < 100000; i++) {  
            logger.trace("trace level");  
            logger.debug("debug level");  
            logger.info("info level");  
            logger.warn("warn level");  
            logger.error("error level");
        }

        try {  
            Thread.sleep(1000 * 61);  
        } catch (InterruptedException e) {}  


        logger.info("請求處理結束,耗時:{}毫秒", (System.currentTimeMillis() - beginTime));    //第一種用法
        logger.info("請求處理結束,耗時:" + (System.currentTimeMillis() - beginTime)  + "毫秒");    //第二種用法

    }
}

四、運行結果 
這裏寫圖片描述

這裏寫圖片描述

這裏寫圖片描述

持續完善中。。。

相關文章
相關標籤/搜索