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

Sha*_*oor 6 java log4j mdc

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

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

小智 11

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

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

请参阅Sifting Appender的文档

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

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


Wol*_*ang 10

log4j也可以这样做.您可以通过实现自己的appender来完成此操作.我想最简单的方法是继承AppenderSkeleton.

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

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

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

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


小智 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");
Run Code Online (Sandbox Code Playgroud)

上面附加的过滤器只检查特定的进程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;
  }
}
Run Code Online (Sandbox Code Playgroud)

希望这个对你有帮助.