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

时间:2011-11-03 09:17:38

标签: java log4j mdc

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

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

3 个答案:

答案 0 :(得分:11)

这可以在Logback中完成,这是Log4J的继承者。

  

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

请参阅Sifting Appender

的文档
  

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

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

答案 1 :(得分:10)

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

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

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

访问MDC

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

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

答案 2 :(得分:6)

我挣扎了一段时间在log4j中找到类似SiftingAppender的功能(由于某些依赖性,我们无法切换到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");

上面附加的过滤器只检查特定的进程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;
  }
}

希望这会有所帮助。