在log4j中使用MDC动态命名日志文件

是否有可能在运行时使用MDC命名日志文件。

我有一个Web应用程序,使用tomcat docbase同时使用不同的名称调用。 所以我需要为每个文件都有单独的日志文件。

这可以在Logback中完成, 后者是Log4J的后续版本。

Logback旨在作为流行的log4j项目的后续版本,从而恢复log4j离开的位置。

请参阅Sifting Appender的文档

SiftingAppender在引用和配置嵌套appender方面具有独特性。 在上面的示例中,在SiftingAppender中将有嵌套的FileAppender实例,每个实例由与“userid”MDC键关联的值标识。 每当为“userid”MDC键分配新值时,将从头开始构建新的FileAppender实例。 SiftingAppender跟踪它创建的appender。 未使用30分钟的Appenders将自动关闭并丢弃。

在该示例中,它们基于MDC值为每个用户生成单独的日志文件。 可以根据您的需要使用其他MDC值。

log4j也可以实现这一点。 您可以通过实现自己的appender来完成此操作。 我想最简单的方法是inheritanceAppenderSkeleton 。

所有日志记录事件都以您必须实现的append(LoggingEvent event)方法结束。

在该方法中,您可以通过event.getMDC("nameOfTheKeyToLookFor");访问MDC event.getMDC("nameOfTheKeyToLookFor");

然后,您可以使用此信息打开要写入的文件。 查看RollingFileAppender等标准appender的实现以了解其余部分可能会有所帮助。

我在应用程序中自己使用这种方法将不同线程的日志分成不同的日志文件,并且它运行良好。

我挣扎了一段时间在log4j中找到类似SiftingAppender的function(由于某些依赖性,我们无法切换到logback),最终得到了一个运行良好的编程解决方案,使用MDC并在运行时追加记录器:

 // this can be any thread-specific string String processID = request.getProcessID(); Logger logger = Logger.getRootLogger(); // append a new file logger if no logger exists for this tag if(logger.getAppender(processID) == null){ try{ String pattern = "%d{yy/MM/dd HH:mm:ss} %p %c{2}: %m%n"; String logfile = "log/"+processID+".log"; FileAppender fileAppender = new FileAppender( new PatternLayout(pattern), logfile, true); fileAppender.setName(processID); // add a filter so we can ignore any logs from other threads fileAppender.addFilter(new ProcessIDFilter(processID)); logger.addAppender(fileAppender); }catch(Exception e){ throw new RuntimeException(e); } } // tag all child threads with this process-id so we can separate out log output MDC.put("process-id", processID); //whatever you want to do in the thread LOG.info("This message will only end up in "+processID+".log!"); MDC.remove("process-id"); 

上面附加的filter只检查特定的进程ID:

 public class RunIdFilter extends Filter { private final String runId; public RunIdFilter(String runId) { this.runId = runId; } @Override public int decide(LoggingEvent event) { Object mdc = event.getMDC("run-id"); if (runId.equals(mdc)) { return Filter.ACCEPT; } return Filter.DENY; } } 

希望这个对你有帮助。