如何自定义 log4j2 RollingFileAppender? [英] How to customize log4j2 RollingFileAppender?

查看:41
本文介绍了如何自定义 log4j2 RollingFileAppender?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们使用 log4j 1.2.x 登录我们的产品,并希望在不久的将来迁移到 log4j 2.x.我们已实现的功能之一是在生成的每个新滚动日志文件上记录系统信息和其他重要参数.我们在 log4j 1.2.x 中实现的方式是我们扩展了 log4j 的 RollingFileAppender 类并覆盖了 rollOver() 方法,下面是实现的部分片段

We use log4j 1.2.x for logging in our product and are looking to migrate to log4j 2.x in near future. One of the functionality we have implemented is to log the system information and other important parameters on every new roll-over logfile that gets generated. The way we implemented in log4j 1.2.x is that we have extended RollingFileAppender class of log4j and have overridden the rollOver() method, below is the part snippet of the implementation

@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以及.

Now as we want to migrate to log4j2 we are looking at a new solution to achieve same functionality. But as I see the source code for log4j2 it is very different from older source code. The RollingFileAppender class does not contain rollover() method as it has been moved to RollingManagerhelper and it has been set to private as-well.

开发一个完整的新包并从 log4j2 扩展/实现一些抽象/帮助类是我们可能的解决方案之一,但这需要大量的编码/复制,因为我们不修改 RollingFileAppender 而是我们只需要对其进行小的扩展.有没有简单的解决方法?

Developing a complete new package and extending/implementing some abstract/helper classes from log4j2 is one of the possible solution for us but that would require a lot of coding/copying as we do not modify what RollingFileAppender does rather we only need small extension to it. Is there a simple solution to it?

更新

我根据答案中的建议创建了一个自定义查找,下面是我创建它的方式;

I created a custom lookup according to the suggestion in answers and below is how I created it;

@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 .我还尝试将断点放在第一个 if 条件上,我注意到它只被调用一次.所以我担心的是 customLookup 类只会在 log4j2 从 xml 配置初始化其属性时在启动时初始化.我不知道我还能如何实现这个自定义查找类.

But this did not work as mentioned; this always prints this was first call in the header. I also tried putting breakoint on the first if condition and what I noticed was that it only gets called once. So what I fear is that the customLookup class only gets initialized on the startup when log4j2 is initialising its properties from xml config. I don't know how else I could implemented this custom lookup class.

更新 2

在上面的实现之后,我以不同的方式尝试了它,如下所示;

After the above implementation I tried it in bit different way which is as below;

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 值不能动态更改,因为它只在初始化期间被调用.任何更多帮助将不胜感激.

But this does the same thing as-well. log4j2 creates the headers at while initialising from its xml config file and then uses the headers from memory. The return value of overridden lookup() method can not be changed dynamically as it only gets called during initialisation. Any more help would be highly appreciated.

推荐答案

使用内置查找的替代方法是创建自定义查找.这可以使用 log4j2 插件在几行代码中完成.然后,您的自定义查找会提供您希望在每次翻转时在文件标题中显示的确切值.

An alternative to using the built-in lookups is to create a custom lookup. This can be accomplished in a few lines of code with a log4j2 plugin. Your custom lookup then provides the exact value you want to show in the file header at each roll over.

插件代码如下所示:

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);
    }
}

然后,在您的配置中,您可以使用模式布局的标题在每次翻转时输出:

Then, in your configuration you can use the header of the pattern layout to output this at every rollover:

<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 手册详细介绍了构建/部署自定义插件.简要总结:

The log4j2 manual has details on building/deploying custom plugins. Brief summary:

最简单的方法是用Maven构建你的jar;这将导致 log4j2 注释处理器在 jar 中生成一个二进制索引文件,以便 log4j2 可以快速找到您的插件.

The easiest way is to build your jar with Maven; this will cause the log4j2 annotation processor to produce a binary index file in the jar so your plugin can be found quickly by log4j2.

另一种方法是在 log4j2.xml 配置的 packages 属性中指定插件类的包名称:

The alternative is to specify the package name of your plugin class in your log4j2.xml configuration's packages attribute:

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

<小时>

更新:请注意,在您的查找实现中,您可以根据需要发挥创意.例如:


UPDATE: Note that in your lookup implementation you can get as creative as necessary. For example:

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);
    }
    ....
}

这篇关于如何自定义 log4j2 RollingFileAppender?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆