簡體   English   中英

如何自定義 log4j2 RollingFileAppender?

[英]How to customize log4j2 RollingFileAppender?

我們使用 log4j 1.2.x 來登錄我們的產品,並希望在不久的將來遷移到 log4j 2.x。 我們已實現的功能之一是在生成的每個新滾動日志文件上記錄系統信息和其他重要參數。 我們在 log4j 1.2.x 中實現的方式是我們擴展了 log4j 的RollingFileAppender類並覆蓋了rollOver()方法,下面是實現的部分片段

@Override
public void rollOver() {

    super.rollOver(); //We are not modifying it's default functionality but as soon as rollOver happens we apply our logic 

    // 
    // Logic to log required system properties and important parameters.
    //

}

現在,當我們想要遷移到 log4j2 時,我們正在尋找一種新的解決方案來實現相同的功能。 但是當我看到 log4j2 的源代碼時,它與舊的源代碼非常不同。 RollingFileAppender類不包含rollover()方法,因為它已移至RollingManagerhelper並且也已設置為private

開發一個完整的新包並從 log4j2 擴展/實現一些抽象/幫助類是我們可能的解決方案之一,但這將需要大量編碼/復制,因為我們不修改RollingFileAppender所做的事情,而只需要對其進行小的擴展. 有沒有簡單的解決方案?

更新

我根據答案中的建議創建了一個自定義查找,下面是我創建它的方式;

@Plugin(name = "property", category = StrLookup.CATEGORY)
public class CustomLookup extends AbstractLookup {

private static AtomicLong aLong = new AtomicLong(0);

@Override
public String lookup(LogEvent event, String key) {

    if (aLong.getAndIncrement() == 0) {
        return "this was first call";
    }
    if (key.equalsIgnoreCase("customKey")) {
        return getCustomHeader();
    } else {
        return "non existing key";
    }
}

private static String getCustomHeader() {

    // Implementation of custom header
    return "custom header string";

}}

但這並沒有像提到的那樣工作; 這總是在標題中打印this was first call 我還嘗試將 breakpoint 放在第一個if條件上,我注意到它只被調用一次。 所以我擔心的是 customLookup 類只會在 log4j2 從 xml 配置初始化其屬性時在啟動時初始化。 我不知道我還能如何實現這個自定義查找類。

更新 2

在上述實現之后,我以不同的方式嘗試了它,如下所示;

private static AtomicLong aLong = new AtomicLong(0);

@Override
public String lookup(LogEvent event, String key) {
    return getCustomHeader(key);
}

private static String getCustomHeader(final String key) {

    if (aLong.getAndIncrement() == 0) {
        return "this was first call";
    }
    if (key.equalsIgnoreCase("customKey")) {
        // Implementation for customKey
        return "This is custom header";
    } else {
        return "non existing key";
    }
}

但這也做同樣的事情。 log4j2 在從其 xml 配置文件初始化時創建標頭,然后使用內存中的標頭。 重寫的lookup()方法的return值不能動態更改,因為它只在初始化期間被調用。 任何更多的幫助將不勝感激。

使用內置查找的替代方法是創建自定義查找。 這可以使用 log4j2 插件在幾行代碼中完成。 然后,您的自定義查找會提供您希望在每次翻轉時在文件標題中顯示的確切值。

插件代碼如下所示:

package com.mycompany;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.lookup.AbstractLookup;
import org.apache.logging.log4j.core.lookup.StrLookup;

/**
 * Looks up keys from a class SomeClass which has access to all
 * information you want to provide in the log file header at rollover.
 */
@Plugin(name = "setu", category = StrLookup.CATEGORY)
public class SetuLookup extends AbstractLookup {

    /**
     * Looks up the value of the specified key by invoking a
     * static method on SomeClass.
     *
     * @param event The current LogEvent (ignored by this StrLookup).
     * @param key  the key to be looked up, may be null
     * @return The value of the specified key.
     */
    @Override
    public String lookup(final LogEvent event, final String key) {
        return com.mycompany.SomeClass.getValue(key);
    }
}

然后,在您的配置中,您可以使用模式布局的標題在每次翻轉時輸出它:

<RollingFile name="RollingFile" fileName="logs/app.log"
             filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}.log.gz">

  <!-- use custom lookups to access arbitrary internal system info -->
  <PatternLayout header="${setu:key1} ${setu:key2}">
    <Pattern>%d %m%n</Pattern>
  </PatternLayout>
  <Policies>
    <TimeBasedTriggeringPolicy />
  </Policies>
</RollingFile>

log4j2 手冊有關於構建/部署自定義插件的詳細信息。 簡要總結:

最簡單的方法是用 Maven 構建你的 jar; 這將導致 log4j2 注釋處理器在 jar 中生成一個二進制索引文件,以便 log4j2 可以快速找到您的插件。

另一種方法是在 log4j2.xml 配置的packages屬性中指定插件類的包名稱:

<Configuration status="warn" packages="com.mycompany">
  ...

更新:請注意,在您的查找實現中,您可以根據需要獲得盡可能多的創意。 例如:

package com.mycompany;

public class SomeClass {
    private static AtomicLong count = new AtomicLong(0);

    public static String getValue(final String key) {
        if (count.getAndIncrement() == 0) { // is this the first call?
            return ""; // don't output a value at system startup
        }
        if ("FULL".equals(key)) {
            // returns info to shown on rollover, nicely formatted
            return fullyFormattedHeader();
        }
        return singleValue(key);
    }
    ....
}

這可以通過配置來實現。 您可以使用模式布局的標題來輸出信息。 這將包含在每次翻轉中。

<RollingFile name="RollingFile" fileName="logs/app.log"
             filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}.log.gz">

  <!-- use built-in lookups for system info or system properties -->
  <PatternLayout header="${java:runtime} - ${java:vm} - ${java:os}">
    <Pattern>%d %m%n</Pattern>
  </PatternLayout>
  <Policies>
    <TimeBasedTriggeringPolicy />
  </Policies>
</RollingFile>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM