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

我想创建一个自定义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 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。

这是我为滚动文件appender编写的代码。

 @Plugin(name = "MyRollingFileAppender", category = "Core", elementType = "appender", printObject = true) public class MyRollingFileAppender extends AbstractOutputStreamAppender { 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 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 configuration = new HashMap(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 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)是正确的,因为我们无法扩展现有的滚动文件appender,我需要重新编写所有的我的自定义类中滚动文件appender的代码只是在日志事件中添加了两个字段? 有没有简单的方法来做同样的事情?

谢谢!

您正在升级的应用程序使用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" ,使您的值显示在日志中。