Программное изменение уровня журнала в Log4j2

109

Меня интересует программное изменение уровня лога в Log4j2. Я попытался посмотреть их документацию по конфигурации, но там ничего не было. Я также попытался заглянуть в пакет:, org.apache.logging.log4j.core.configно и там ничего не помогло.

CorayThan
источник
2
Если вы не получили здесь ответа, попробуйте список рассылки, его обычно просматривают раз в 2 дня основные авторы. Тогда вернись и ответь на свой вопрос :-)
tgkprog

Ответы:

139

ИЗМЕНИТЬ согласно log4j2 версии 2.4 FAQ

Вы можете установить уровень логгера с помощью класса Configurator из Log4j Core. НО имейте в виду, что класс Configurator не является частью общедоступного API.

// org.apache.logging.log4j.core.config.Configurator;
Configurator.setLevel("com.example.Foo", Level.DEBUG);

// You can also set the root logger:
Configurator.setRootLevel(Level.DEBUG);

Источник

ИЗМЕНИТЬ, чтобы отразить изменения в API, представленные в Log4j2 версии 2.0.2

Если вы хотите изменить уровень корневого регистратора, сделайте что-то вроде этого:

LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
Configuration config = ctx.getConfiguration();
LoggerConfig loggerConfig = config.getLoggerConfig(LogManager.ROOT_LOGGER_NAME); 
loggerConfig.setLevel(level);
ctx.updateLoggers();  // This causes all Loggers to refetch information from their LoggerConfig.

Вот javadoc для LoggerConfig.

слаадвак
источник
3
Правильно, и если вы хотите изменить только для определенного регистратора (класса / пакета), получите контекст этого регистратора, setLevel и updateLoggers.
tgkprog 02
34
Такой запутанный способ просто выставить уровень логирования. Я уверен, что есть причина делать это с пятью строками кода, а не с исходной одной строкой в ​​предыдущих версиях log4j, но я просто не вижу этого. В любом случае спасибо, @slaadvak!
Sturm
1
.updateLoggers () не требуется. Кажется, что изменения, сделанные с помощью .setLevel (), применяются немедленно.
zbyszek 08
1
Вызов updateLoggers требуется всегда, даже если вы добавляете новый LoggerConfig. UpdateLoggers заставляет все регистраторы повторно связываться с LoggerConfigs и изменять свой уровень ведения журнала на уровень соответствующего LoggerConfig. Если вы добавите новый LoggerConfig, любые регистраторы, соответствующие новому шаблону LoggerConfig, будут перенаправлены на него. Требуется "запутанный" способ, потому что регистраторы и их конфигурация были разделены в Log4j2.
rgoers 01
1
Вот ответ, который предоставляет обновленное однострочное или двухстрочное решение для новых версий Log4J: stackoverflow.com/a/44678752/1339923
Lambart
37

Принятый ответ @slaadvak не сработал для меня для Log4j2 2.8.2 . Следующее сделало.

Для Level универсального изменения журнала используйте:

Configurator.setAllLevels(LogManager.getRootLogger().getName(), level);

Чтобы изменить журнал Levelтолько для текущего класса, используйте:

Configurator.setLevel(LogManager.getLogger(CallingClass.class).getName(), level);
4мил
источник
1
Получил мой голос, потому что вы вытащили имена регистраторов из самих регистраторов, а не жестко закодировали имя как строку.
DWoldrich
18

Если вы хотите изменить один конкретный уровень регистратора (не корневой регистратор или регистраторы, настроенные в файле конфигурации), вы можете сделать это:

public static void setLevel(Logger logger, Level level) {
    final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
    final Configuration config = ctx.getConfiguration();

    LoggerConfig loggerConfig = config.getLoggerConfig(logger.getName());
    LoggerConfig specificConfig = loggerConfig;

    // We need a specific configuration for this logger,
    // otherwise we would change the level of all other loggers
    // having the original configuration as parent as well

    if (!loggerConfig.getName().equals(logger.getName())) {
        specificConfig = new LoggerConfig(logger.getName(), level, true);
        specificConfig.setParent(loggerConfig);
        config.addLogger(logger.getName(), specificConfig);
    }
    specificConfig.setLevel(level);
    ctx.updateLoggers();
}
Йорг Фридрих
источник
3
Это никак не повлияло на мой регистратор. Я использовал setLevel(logger, Level.ERROR);и все еще напечатанные операторы logger.debug. Мой файл log4j2.xml находится по адресу pastebin.com/fcbV2mTW
Ноумен,
Я обновил код. Сообщите мне, если с этим возникнут проблемы.
Йорг Фридрих
4
В log4j 2.7 LoggerContext не имеет метода getConfiguration (), см. Logging.apache.org/log4j/2.x/log4j-api/apidocs/index.html?org/…
maxxyme
log4j-core-2.7.jar имеет и может использоваться как окончательный LoggerContext ctx = (LoggerContext) LogManager.getContext (false); окончательная конфигурация конфигурации = ctx.getConfiguration ();
jprism
3
Увидев это, я думаю ... «Может, они не хотят, чтобы мы меняли уровень во время выполнения?»
Корай Тугай
13

Я нашел здесь хороший ответ: https://garygregory.wordpress.com/2016/01/11/changing-log-levels-in-log4j2/

Вы можете использовать org.apache.logging.log4j.core.config.Configurator, чтобы установить уровень для определенного регистратора.

Logger logger = LogManager.getLogger(Test.class);
Configurator.setLevel(logger.getName(), Level.DEBUG);
alfred.schalk
источник
2
В этом ответе показано то же решение, а также то, как установить его для корневого регистратора, что иногда бывает полезно: stackoverflow.com/a/44678752/1339923
Lambart
4

Программный подход довольно навязчив. Возможно, вам стоит проверить поддержку JMX, предоставляемую Log4J2:

  1. Включите порт JMX при запуске приложения:

    -Dcom.sun.management.jmxremote.port = [номер_порта]

  2. Используйте любой из доступных клиентов JMX (JVM предоставляет один в JAVA_HOME / bin / jconsole.exe) во время выполнения вашего приложения.

  3. В JConsole найдите bean-компонент org.apache.logging.log4j2.Loggers.

  4. Наконец измените уровень вашего регистратора

Что мне больше всего нравится, так это то, что вам не нужно изменять свой код или конфигурацию для управления этим. Это все внешнее и прозрачное.

Дополнительная информация: http://logging.apache.org/log4j/2.x/manual/jmx.html

Виктор
источник
Очень полезно, спасибо!
Даррен Паркер
3

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

    public class LogConfigManager {

    public void setLogLevel(String loggerName, String level) {
        Level newLevel = Level.valueOf(level);
        LoggerContext logContext = (LoggerContext) LogManager.getContext(false);
        Configuration configuration = logContext.getConfiguration();
        LoggerConfig loggerConfig = configuration.getLoggerConfig(loggerName);
        // getLoggerConfig("a.b.c") could return logger for "a.b" if there is no logger for "a.b.c"
        if (loggerConfig.getName().equalsIgnoreCase(loggerName)) {
            loggerConfig.setLevel(newLevel);
            log.info("Changed logger level for {} to {} ", loggerName, newLevel);
        } else {
            // create a new config.
            loggerConfig = new LoggerConfig(loggerName, newLevel, false);
            log.info("Adding config for: {} with level: {}", loggerConfig, newLevel);
            configuration.addLogger(loggerName, loggerConfig);


            LoggerConfig parentConfig = loggerConfig.getParent();
            do {
                for (Map.Entry<String, Appender> entry : parentConfig.getAppenders().entrySet()) {
                    loggerConfig.addAppender(entry.getValue(), null, null);
                }
                parentConfig = parentConfig.getParent();
            } while (null != parentConfig && parentConfig.isAdditive());
        }
        logContext.updateLoggers();
    }
}

Тестовый пример для того же

public class LogConfigManagerTest {
    @Test
    public void testLogChange() throws IOException {
        LogConfigManager logConfigManager = new LogConfigManager();
        File file = new File("logs/server.log");
        Files.write(file.toPath(), new byte[0], StandardOpenOption.TRUNCATE_EXISTING);
        Logger logger = LoggerFactory.getLogger("a.b.c");
        logger.debug("Marvel-1");
        logConfigManager.setLogLevel("a.b.c", "debug");
        logger.debug("DC-1");
        // Parent logger level should remain same
        LoggerFactory.getLogger("a.b").debug("Marvel-2");
        logConfigManager.setLogLevel("a.b.c", "info");
        logger.debug("Marvel-3");
        // Flush everything
        LogManager.shutdown();

        String content = Files.readAllLines(file.toPath()).stream().reduce((s1, s2) -> s1 + "\t" + s2).orElse(null);
        Assert.assertEquals(content, "DC-1");
    }
}

Предполагая, что следующий log4j2.xml находится в пути к классам

<?xml version="1.0" encoding="UTF-8"?>
<Configuration xmlns="http://logging.apache.org/log4j/2.0/config">

    <Appenders>
        <File name="FILE" fileName="logs/server.log" append="true">
            <PatternLayout pattern="%m%n"/>
        </File>
        <Console name="STDOUT" target="SYSTEM_OUT">
            <PatternLayout pattern="%m%n"/>
        </Console>
    </Appenders>

    <Loggers>
        <AsyncLogger name="a.b" level="info">
            <AppenderRef ref="STDOUT"/>
            <AppenderRef ref="FILE"/>
        </AsyncLogger>

        <AsyncRoot level="info">
            <AppenderRef ref="STDOUT"/>
        </AsyncRoot>
    </Loggers>

</Configuration>
хобгоблин
источник
2

Я нашел один необычный способ - создать два отдельных файла с разным уровнем ведения журнала.
Например. log4j2.xml и log4j-debug.xml Теперь измените конфигурацию из этих файлов.
Образец кода:

ConfigurationFactory configFactory = XmlConfigurationFactory.getInstance();
            ConfigurationFactory.setConfigurationFactory(configFactory);
            LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
            ClassLoader classloader = Thread.currentThread().getContextClassLoader();
            InputStream inputStream = classloader.getResourceAsStream(logFileName);
            ConfigurationSource configurationSource = new ConfigurationSource(inputStream);

            ctx.start(configFactory.getConfiguration(ctx, configurationSource));
dpp.2325
источник