web-dev-qa-db-fra.com

Modifier par programme le niveau de journalisation dans Log4j2

Je suis intéressé par la modification par programme du niveau de journalisation dans Log4j2. J'ai essayé de regarder leur documentation de configuration mais cela ne semblait pas avoir rien. J'ai aussi essayé de regarder dans le paquet: org.Apache.logging.log4j.core.config, mais rien ne semblait utile non plus.

91
CorayThan

MODIFIÉ selon la FAQ de log4j2 version 2.4

Vous pouvez définir le niveau d’un enregistreur avec la classe Configurator de Log4j Core. [~ # ~] mais [~ # ~] sachez que la classe Configurator ne fait pas partie de l'API publique.

// 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);

Source

EDITED pour refléter les modifications de l'API introduites dans Log4j2 version 2.0.2

Si vous souhaitez modifier le niveau du journal racine, procédez comme suit:

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.

Ici est le javadoc pour LoggerConfig.

114
slaadvak

La réponse acceptée par @slaadvak n'a pas fonctionné pour moi pour Log4j2 2.8.2 . Les suivants ont fait.

Pour changer le journal Level universellement , utilisez:

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

Pour modifier le journal Level uniquement pour la classe actuelle, utilisez:

Configurator.setLevel(LogManager.getLogger(CallingClass.class).getName(), level);
25
4myle

Si vous souhaitez modifier un seul niveau de journalisation spécifique (et non le ou les enregistreurs racine configurés dans le fichier de configuration), vous pouvez procéder comme suit:

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();
}
18
Jörg Friedrich

J'ai trouvé une bonne réponse ici: https://garygregory.wordpress.com/2016/01/11/changing-log-levels-in-log4j2/

Vous pouvez utiliser org.Apache.logging.log4j.core.config.Configurator pour définir le niveau d'un consignateur spécifique.

Logger logger = LogManager.getLogger(Test.class);
Configurator.setLevel(logger.getName(), Level.DEBUG);
10
alfred.schalk

L'approche programmatique est plutôt intrusive. Peut-être devriez-vous vérifier le support JMX fourni par Log4J2:

  1. Activez le port JMX lors du démarrage de votre application:

    -Dcom.Sun.management.jmxremote.port = [numéro de port]

  2. Utilisez l’un des clients JMX disponibles (la machine virtuelle Java en fournit un dans Java_HOME/bin/jconsole.exe) lors de l’exécution de votre application.

  3. Dans JConsole, recherchez le bean "org.Apache.logging.log4j2.Loggers".

  4. Enfin, changez le niveau de votre enregistreur

La chose que j’aime le plus, c’est que vous n’avez pas à modifier votre code ou votre configuration pour gérer cela. Tout est extérieur et transparent.

Plus d'infos: http://logging.Apache.org/log4j/2.x/manual/jmx.html

4
Victor

La plupart des réponses supposent par défaut que la journalisation doit être additive. Mais disons que certains paquets génèrent beaucoup de journaux et que vous voulez désactiver la journalisation pour ce seul enregistreur. Voici le code que j'ai utilisé pour le faire fonctionner

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

Un cas de test pour le même

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

En supposant que la suite log4j2.xml soit dans classpath

<?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
hobgoblin

Une façon inhabituelle que j'ai trouvée est de créer deux fichiers séparés avec un niveau de journalisation différent.
Par exemple. log4j2.xml et log4j-debug.xml Modifiez maintenant la configuration à partir de ces fichiers.
Exemple de code:

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));
1
dpp.2325