2016年3月24日 星期四

log4j2 簡易教學

首先到官網的download下載,或者用 maven、gradle 也行


然後到 Configuration 來複製,也可以照裡面的教學,但我修改成如下:
public class App {
    private static final Logger logger = LogManager.getLogger(App.class);
    public static void main(final String... args) {
        logger.trace("a");
        logger.debug("b");
        logger.info("c");
        logger.warn("d");
        logger.error("e");
        logger.fatal("f");
    }
}

※注意 Logger 要 import 的包為 org.apache.logging.log4j.Logger

※排的順序是有原因的,logger有階層關係,看  architecture 中間偏下一點點有一張叫 LoggerConfig Level 的表,看直的

※執行後,console印出來如下:
ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console.
最後只有印出 e 和 f

※因為還沒設定,所以有警告,但已有預設值了,所以還是能輸出,但如果想用自己設定的,可在 classpath 放一個 xml 檔,叫 log4j2.xml,上面的 Configuration 連結有說明 Automatic Configuration,沒設時是走第10條規則,現在是用第9條的方式,內容可到 Configuration 複製(JSON、YAML、properties 也有範例),如下:

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

※Configuration 下有 Appenders 和 Loggers,因為 Root level 設成 error,所以 error 以下的才會印出來,Configuration 的 status 也有類似的東西,但是針對 log4j 內部的輸出,打 trace 就會印出很多,其他屬性可參考官網

※AppenderRef 的 ref 要對應 name 名稱,否則會報錯

※Appenders 有 20 多個可以用,官網都有貼範例,如 AsyncAppender,可以在 Appenders 下,增加 Async (不用打Appender) ,依此類推,至於屬性,每個表也都有

※假設想在 D 槽輸出日誌,可增加如下的設定
<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="MyFile" fileName="D:/xxx.log">
            <PatternLayout>
                <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
            </PatternLayout>
        </File>
    </Appenders>
    
    <Loggers>
        <Root level="error">
            <AppenderRef ref="Console" />
            <AppenderRef ref="MyFile" />
        </Root>
    </Loggers>
</Configuration>

※AppenderRef 的 ref,可視情況增加或減少,如不想輸出到控制台,就註解

※會用附加的方式到檔案裡

※PatternLayout 的 pattern 可參考 Layouts 的 PatternLayout



※PatternLayout 格式

%d{HH:mm:ss,SSS}:時間,還有很多,看官網

%-5p:p 也可用 level 表示,格式有5格,加「-」是左邊對齊,不加是右邊,如右邊對齊如下:
DEBUG
 INFO

%t:執行的是哪一隻thread

%F:file name,檔案名稱

%L:line,行數

%m:訊息,就是我打的a~f,也可用 %msg、%message

%n:換行

%C:包+類別名稱,像我是「test.log4j2.App」,花括號表示從右邊以「.」為一個單位,
所以2表示log4j2.App,如下:

我將第一行改成如下:private static final Logger logger = LogManager.getLogger("www.google.com.tw");
然後pattern改成「%c{3} %C %d{yyyy-MM-dd} %L%n」
以下是結果:
google.com.tw test.log4j2.App 2016-03-24 14
google.com.tw test.log4j2.App 2016-03-24 15
google.com.tw test.log4j2.App 2016-03-24 16
google.com.tw test.log4j2.App 2016-03-24 17
google.com.tw test.log4j2.App 2016-03-24 18
google.com.tw test.log4j2.App 2016-03-24 19



※在 Web 環境使用 log4j2

官方文件
下 log4j-core 時,會依賴 log4j-api,但 log4j-web 並沒有,所以還得去下載
注意 container 的版本

※web.xml

<context-param>
    <param-name>log4jConfiguration</param-name>
    <param-value>/WEB-INF/log4j2.xml</param-value>
</context-param>
    
<listener>
    <listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class>
</listener>
    
<filter>
    <filter-name>log4jServletFilter</filter-name>
    <filter-class>org.apache.logging.log4j.web.Log4jServletFilter</filter-class>
</filter>
    
<filter-mapping>
    <filter-name>log4jServletFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
    <dispatcher>ASYNC</dispatcher><!-- Servlet 3.0 w/ disabled auto-initialization 
        only; not supported in 2.5 -->
</filter-mapping>

※如果 container 的版本夠高 (Tomcat 7(含) 以上,但7.0.43有bug),只要寫 context-param 就可以了,又如果設定檔放在 classpath 裡,而且叫 log4j2.xml,那連 context-param 也不用寫(最上面的 Configuration 連結的 10 條規則其中之一)

※都是官方複製的,唯一改的地方就是放配置檔的路徑

※如果設定沒成功,和沒 Web 時很像,只會印出 error 以下層級,但不會有警告

※官方還提供一個開關,要關閉自動初始化 log 嗎?如下:

<context-param>
    <param-name>isLog4jAutoInitializationDisabled</param-name>
    <param-value>true</param-value>
</context-param>

※true 代表關閉,此時不會去讀取設定檔,所以還是會有預設的 error 以下的層級



※API

官網連結


※代替參數、lambda

public class TestLog4j2 {
    private static final Logger logger = LogManager.getLogger(TestLog4j2.class);
    
    @Test
    public void bruceTest() {
        logger.info("replace1= {} {}", "a", "b");
        logger.info("replace2= {} {}", "a");
        logger.info("replace3= {}", "a", "b");
        
        logger.info("lambda1= {}", () -> array());
        logger.info("lambda2= {}", () -> System.getProperties());
        logger.info("lambda3= {}", System::getProperties);
    }
    
    public String[] array() {
        return new String[] { "xxxx", "oooo" };
    }
}

※使用 {} 代替

※lambda 只會佔用1個 {},但 lambda 必需 log4j 2.4以上才有支援

※注意 Supplier 已被改寫

※官網說使用 lambda 不用顯式判斷層級,我無法理解
層級有開就印,沒開就不印,不管加不加判斷式,結果都一樣,不知道它在說什麼?


※格式化、混合

public class TestLog4j2 {
    public static final Logger logger = LogManager.getFormatterLogger(TestLog4j2.class);
    
    @Test
    public void bruceTest() {
        logger.info("format1= %1$s born in %2$tm %2$te,%2$tY", "bruce", new Date());
        logger.info("format2= %,d", Integer.MAX_VALUE);
        logger.printf(Level.INFO, "mixing= %1$s born in %2$tm %2$te,%2$tY", "bruce", new Date());
    }
}

※混合的意思表示使用 getFormatterLogger 和 getLogger 都可以使用 $1 這種東西,但如果使用getFormatterLogger,那 {} 就失效了

沒有留言:

張貼留言