如何在log4j2中创建滚动文件appender插件

时间:2015-05-23 12:31:03

标签: java logging log4j append log4j2

我想创建一个自定义的log4j2滚动文件appender。我需要创建这个自定义appender,因为我想用我的应用程序特有的一些信息包装log4j日志事件。例如userId,托管的应用程序名称。

我有一个扩展Log4jLogEvent实现LogEvent的类。这个类包含了我需要用日志事件包装的信息。 请参阅此代码:

public class CustomLogEvent extends Log4jLogEvent implements LogEvent {

private String userId;
private String applicationName;

private static final long serialVersionUID = 1L;

public CustomLogEvent(String loggerName, Marker marker, String loggerFQCN, Level level, Message message, Throwable t, Map<String, String> mdc, ThreadContext.ContextStack ndc, String threadName, StackTraceElement location, long timestamp){
    super(loggerName,marker,loggerFQCN,level,message,t,mdc,ndc,threadName,location,timestamp);
}
         //Getters and setters for user Id and app name
}

在log4j2中,因为我们不能像log4j 1.2那样扩展滚动文件appender,所以我通过查看原始滚动文件appender的源代码创建了新的滚动文件appender。此类扩展了AbstractOutputStreamAppender。

这是我为滚动文件追加器编写的代码。

@Plugin(name = "MyRollingFileAppender", category = "Core", elementType = "appender", printObject = true)
public class MyRollingFileAppender extends AbstractOutputStreamAppender<RollingFileManager> {

private static final int DEFAULT_BUFFER_SIZE = 8192;
private static final long serialVersionUID = 1L;

private final String fileName;
private final String filePattern;
private Object advertisement;
private final Advertiser advertiser;


private MyRollingFileAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
                            final RollingFileManager manager, final String fileName, final String filePattern,
                            final boolean ignoreExceptions, final boolean immediateFlush, final Advertiser advertiser) {
    super(name, layout, filter, ignoreExceptions, immediateFlush, manager);
    if (advertiser != null) {
        final Map<String, String> configuration = new HashMap<String, String>(layout.getContentFormat());
        configuration.put("contentType", layout.getContentType());
        configuration.put("name", name);
        advertisement = advertiser.advertise(configuration);
    }
    this.fileName = fileName;
    this.filePattern = filePattern;
    this.advertiser = advertiser;
}


@Override
public void append(final LogEvent logEvent) {

    int userId = //get user Id

    String appplicatinName = //get application name

    GetLoggingEvent myLogEvent = new GetLoggingEvent();

    LogEvent customLogEvent = myLogEvent.getCustomLogEvent(logEvent, userId, applicationName);
    getManager().checkRollover(customLogEvent);
    super.append(customLogEvent);
}

@PluginFactory
public static MyRollingFileAppender createAppender(
        @PluginAttribute("fileName") final String fileName,
        @PluginAttribute("filePattern") final String filePattern,
        @PluginAttribute("append") final String append,
        @PluginAttribute("name") final String name,
        @PluginAttribute("bufferedIO") final String bufferedIO,
        @PluginAttribute("bufferSize") final String bufferSizeStr,
        @PluginAttribute("immediateFlush") final String immediateFlush,
        @PluginElement("Policy") final TriggeringPolicy policy,
        @PluginElement("Strategy") RolloverStrategy strategy,
        @PluginElement("Layout") Layout<? extends Serializable> layout,
        @PluginElement("Filter") final Filter filter,
        @PluginAttribute("ignoreExceptions") final String ignore,
        @PluginAttribute("advertise") final String advertise,
        @PluginAttribute("advertiseURI") final String advertiseURI,
        @PluginConfiguration final Configuration config) {

    final boolean isAppend = Booleans.parseBoolean(append, true);
    final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
    final boolean isBuffered = Booleans.parseBoolean(bufferedIO, true);
    final boolean isFlush = Booleans.parseBoolean(immediateFlush, true);
    final boolean isAdvertise = Boolean.parseBoolean(advertise);
    final int bufferSize = Integers.parseInt(bufferSizeStr, DEFAULT_BUFFER_SIZE);
    if (!isBuffered && bufferSize > 0) {
        LOGGER.warn("The bufferSize is set to {} but bufferedIO is not true: {}", bufferSize, bufferedIO);
    }
    if (name == null) {
        LOGGER.error("No name provided for FileAppender");
        return null;
    }

    if (fileName == null) {
        LOGGER.error("No filename was provided for FileAppender with name "  + name);
        return null;
    }

    if (filePattern == null) {
        LOGGER.error("No filename pattern provided for FileAppender with name "  + name);
        return null;
    }

    if (policy == null) {
        LOGGER.error("A TriggeringPolicy must be provided");
        return null;
    }

    if (strategy == null) {
        strategy = DefaultRolloverStrategy.createStrategy(null, null, null,
                String.valueOf(Deflater.DEFAULT_COMPRESSION), config);
    }

    if (layout == null) {
        layout = PatternLayout.createDefaultLayout();
    }

    final RollingFileManager manager = RollingFileManager.getFileManager(fileName, filePattern, isAppend,
            isBuffered, policy, strategy, advertiseURI, layout, bufferSize);
    if (manager == null) {
        return null;
    }

    return new MyRollingFileAppender(name, layout, filter, manager, fileName, filePattern,
            ignoreExceptions, isFlush, isAdvertise ? config.getAdvertiser() : null);
}
}

我从log4j 1.2升级到log4j2的应用程序使用Apache commons API,因此我不能使用线程上下文映射来添加信息。

这个appender现在工作正常。但是我对我的程序有一些困惑。

我想确保我这样做的方式(即使用自定义信息包装日志事件并为自定义信息创建滚动文件追加器)是正确的,因为我们无法扩展现有的滚动文件追加器吗?重新编写我的自定义类中滚动文件appender的所有代码,只是在日志事件中添加两个字段? 有没有简单的方法来做同样的事情?

谢谢!

1 个答案:

答案 0 :(得分:1)

您要升级的应用程序使用Apache Commons Logging,并且Commons Logging API中没有ThreadContext映射。

但是,您只需在应用程序中使用log4j2 ThreadContext映射即可完成对象。这样您就不需要任何自定义日志事件或appender子类。

应用程序中应该只有少数位置可以设置或修改userID。在这些地方,添加以下代码行:

int userId = //get user Id
String appplicationName = //get application name
ThreadContext.put("userID", String.valueOf(userId));
ThreadContext.put("appplicationName", appplicationName);
// ... your business logic

如果将Commons Logging委托给log4j2,您可以配置类似于"%-5p [%t] %c: %X{userID}/%{appplicationName} %m%n"的模式布局,以使您的值显示在日志中。