Обновить шаблон log4j2 во время выполнения - PullRequest
0 голосов
/ 25 августа 2018

Я искал долго и усердно, поэтому прочитайте, прежде чем пометить его как дубликат.

У меня есть функция (Lambda.handle()), которая вызывается с параметром id.Я хочу добавить этот идентификатор в каждое сообщение журнала в качестве префикса.Он меняется каждый раз, когда вызывается функция.Поэтому я хочу обновить шаблон регистратора, добавив этот идентификатор в качестве префикса.

Я прочитал:

  • как настроить
  • как перенастроить
  • Многочисленные сообщения на форумах SO и log4j, рассказывающие о том, как изменить конфигурацию во время выполнения.Они либо устарели, либо просто не работают.

Следующий код основан на документации log4j2.Она печатает:

INIT  MyLogger handle() - id ONE 
INIT  MyLogger handle() - id TWO 
INIT  MyLogger handle() - id THR 

Если я закомментирую строку initLoggerConfig("INIT ");, то она печатает:

ERROR StatusLogger No Log4j 2 configuration file found. Using default configuration (logging only errors to the console), or user programmatically provided configurations. Set system property 'log4j2.debug' to show Log4j 2 internal initialization logging. See https://logging.apache.org/log4j/2.x/manual/configuration.html for instructions on how to configure Log4j 2
ONE  MyLogger handle() - id ONE 
ONE  MyLogger handle() - id TWO 
ONE  MyLogger handle() - id THR 

Я хочу, чтобы она напечатала:

ONE  MyLogger handle() - id ONE 
TWO  MyLogger handle() - id TWO 
THR  MyLogger handle() - id THR 

Будь якомментарий ctxLocal = ctx;, не имеет никакого эффекта.

Вот полный журнал Я получаю, установив собственный уровень ведения журнала log4j равным ALL (builder.setStatusLevel(Level.ALL);)

Воткод

package foobar;

import java.util.Arrays;
import java.util.List;

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.config.AppenderRef;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder;
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
import org.apache.logging.log4j.core.layout.PatternLayout;

class Lambda {
  private static final String LOGGER_NAME = "MyLogger";
  private LoggerContext ctx;

  public Lambda() {
    initLoggerConfig("INIT ");
  }

  public void handle(String id) {
    updateLoggerConfig(id);
    Logger logger = LogManager.getLogger(LOGGER_NAME);
    logger.error("handle() - id {}", id);
  }

  private void updateLoggerConfig(String prefix) {
    final LoggerContext ctxLocal = (LoggerContext) LogManager.getContext(false);
    // ctxLocal = ctx;
    Configuration config = ctxLocal.getConfiguration();
    Layout<String> layout = PatternLayout.newBuilder().withPattern(prefix + " %c %m\n").withConfiguration(config)
        .build();
    Appender appender = ConsoleAppender.createDefaultAppenderForLayout(layout);
    appender.start();
    config.addAppender(appender);
    AppenderRef ref = AppenderRef.createAppenderRef("File", null, null);
    AppenderRef[] refs = new AppenderRef[] { ref };
    LoggerConfig loggerConfig = LoggerConfig.createLogger(false, Level.ALL, getClass().getName(), "true", refs, null,
        config, null);
    loggerConfig.addAppender(appender, null, null);
    config.addLogger(LOGGER_NAME, loggerConfig);
    ctxLocal.updateLoggers();
  }

  void initLoggerConfig(String prefix) {
    ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
    builder.setStatusLevel(Level.ERROR);
    builder.setConfigurationName("BuilderTest");
    builder.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.NEUTRAL).addAttribute("level",
        Level.DEBUG));
    AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE").addAttribute("target",
        ConsoleAppender.Target.SYSTEM_OUT);
    appenderBuilder.add(builder.newLayout("PatternLayout").addAttribute("pattern", prefix + " %c %m\n"));
    appenderBuilder.add(
        builder.newFilter("MarkerFilter", Filter.Result.DENY, Filter.Result.NEUTRAL).addAttribute("marker", "FLOW"));
    builder.add(appenderBuilder);
    builder.add(builder.newLogger(LOGGER_NAME, Level.ALL).add(builder.newAppenderRef("Stdout"))
        .addAttribute("additivity", false));
    builder.add(builder.newRootLogger(Level.ERROR).add(builder.newAppenderRef("Stdout")));
    ctx = Configurator.initialize(builder.build());
  }
}

public class TestMain {
  static Lambda lamb = new Lambda();
  private static Logger logger = LogManager.getLogger();

  public static void main(String[] args) {
    Configurator.setLevel(logger.getName(), Level.ALL);
    List<String> a = Arrays.asList("ONE ", "TWO ", "THR ");
    for (String i : a) {
      lamb.handle(i);
    }

  }
}

1 Ответ

0 голосов
/ 11 декабря 2018

Используя поиск, предложенный Д.Б., я так и исправил.

Добавьте ссылку на вашу «переменную» в свой PatternLayout, в приведенном ниже примере я назвал ее MyVarialbe (вам нужно использовать точный синтаксис с% X {}:

appenderBuilder.add (builder.newLayout ( "PatternLayout") .addAttribute ("pattern", "% X {MyVariable} % msg% n% throwable"));

Позже в вашем коде вы можете установить значение для него в любое время, выполнив:

org.apache.logging.log4j.ThreadContext.put ("MyVariable", extraInfo);

Использование log4j2 программно сложно. Поскольку у меня были такие же трудности, и этому посту 3 месяца, надеюсь, этот ответ будет полезен кому-то еще.

...