Использование MDC в log4j для динамического именования файла журнала - PullRequest
6 голосов
/ 03 ноября 2011

Возможно ли как-то использовать MDC для именования файла журнала во время выполнения.

У меня есть одно веб-приложение, которое вызывается одновременно под разными именами с помощью tomcat docbase.Поэтому мне нужно иметь отдельные файлы журналов для каждого из них.

Ответы [ 3 ]

11 голосов
/ 03 ноября 2011

Это может быть выполнено в Logback , преемнике Log4J.

Logback предназначен в качестве преемника популярного проекта log4j, выбирая там, где прекращается log4j.

См. Документацию для Просеивающее устройство

SiftingAppender уникален своей способностью ссылаться и настраивать вложенные дополнения. В приведенном выше примере в SiftingAppender будут вложенные экземпляры FileAppender, каждый из которых определяется значением, связанным с ключом MDC "userid". Всякий раз, когда ключу MDC "ID пользователя" назначается новое значение, новый экземпляр FileAppender будет создаваться с нуля. SiftingAppender отслеживает создаваемые им приложения. Аппендеры, неиспользованные в течение 30 минут, автоматически закрываются и удаляются.

В этом примере они генерируют отдельный файл журнала для каждого пользователя на основе значения MDC. Другие значения MDC могут использоваться в зависимости от ваших потребностей.

10 голосов
/ 03 ноября 2011

Это также возможно с log4j. Вы можете сделать это, внедрив свой собственный appender. Я думаю, что самый простой способ это подкласс AppenderSkeleton .

Все события журналирования заканчиваются в методе append(LoggingEvent event), который вы должны реализовать.

В этом методе вы можете получить доступ к MDC по event.getMDC("nameOfTheKeyToLookFor");

Тогда вы можете использовать эту информацию, чтобы открыть файл для записи. Может быть полезно взглянуть на реализацию стандартных приложений, таких как RollingFileAppender , чтобы выяснить остальное.

Я сам использовал этот подход в приложении для разделения журналов разных потоков на разные файлы журналов, и он работал очень хорошо.

6 голосов
/ 18 июня 2013

Я некоторое время пытался найти функциональность, похожую на SiftingAppender, в log4j (мы не могли переключиться на 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");

Фильтр, добавленный выше, просто проверяет конкретный идентификатор процесса:

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;
  }
}

Надеюсь, это немного поможет.

...