CorayThan
CorayThan

Reputation: 17825

Programmatically change log level in Log4j2

I'm interested in programmatically changing the log level in Log4j2. I tried looking at their configuration documentation but that didn't seem to have anything. I also tried looking in the package: org.apache.logging.log4j.core.config, but nothing in there looked helpful either.

Upvotes: 159

Views: 151197

Answers (10)

John kerich
John kerich

Reputation: 46

This is working for me. My log level is info and its changed to debug.

    <Logger name="com.frequentisdefense.digitaltower" level="info" additivity="false">

            changeLoggingLevel(Level.DEBUG);

private static void changeLoggingLevel(Level newLevel)
    {
        LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
        Configuration config = ctx.getConfiguration();
        // You could also specify the actual logger name as below and it will return the LoggerConfig used by the Logger.

        LoggerConfig loggerConfig = config.getLoggerConfig("com.frequentisdefense.digitaltower");
        loggerConfig.setLevel(newLevel);

        ctx.updateLoggers();
    }

Upvotes: 0

hobgoblin
hobgoblin

Reputation: 935

Most of the answers by default assume that logging has to be additive. But say that some package is generating lot of logs and you want to turn off logging for that particular logger only. Here is the code that I used to get it working

    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();
            if (parentConfig != null) {
                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();
    }
}

A test case for the same

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

Assuming following log4j2.xml is in 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>

Upvotes: 8

Rhineb
Rhineb

Reputation: 381

As of 2023 the above do not seem to work (or I will say at least did not seem to work for me), what did work was the following

import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;

final LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
final Logger logger = loggerContext.exists(org.slf4j.Logger.ROOT_LOGGER_NAME); // give it your logger name
final Level newLevel = Level.toLevel("ERROR", null); // give it your log level
logger.setLevel(newLevel);

If you want to see how to do this on a per request basis see my comment on post Change priority level in log4j per request

Upvotes: -4

markthegrea
markthegrea

Reputation: 3841

For those of you still struggeling with this, I had to add the classloader to the "getContext()" call:

  log.info("Modifying Log level! (maybe)");
  LoggerContext ctx = (LoggerContext) LogManager.getContext(this.getClass().getClassLoader(), false);
  Configuration config = ctx.getConfiguration();
  LoggerConfig loggerConfig = config.getLoggerConfig("com.cat.barrel");
  loggerConfig.setLevel(org.apache.logging.log4j.Level.TRACE);
  ctx.updateLoggers();

I added a jvm argument: -Dlog4j.debug to my test. This does some verbose logging for log4j. I noticed that the final LogManager was not the one that I was using. Bam, add the class loader and you are off to the races.

Upvotes: 6

slaadvak
slaadvak

Reputation: 4779

The Easy Way :

EDITED according to log4j2 version 2.4 FAQ

You can set a logger’s level with the class Configurator from Log4j Core. BUT be aware that the Configurator class is not part of the public 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);

Source

The Preferable Way :

EDITED to reflect changes in the API introduced in Log4j2 version 2.0.2

If you wish to change the root logger level, do something like this :

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.

Here is the javadoc for LoggerConfig.

Upvotes: 233

dpp.2325
dpp.2325

Reputation: 131

One un-usual way i found to do is to create two separate file with different logging level.
For example. log4j2.xml and log4j-debug.xml Now change the configuration from this files.
Sample 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));

Upvotes: 2

a113nw
a113nw

Reputation: 1412

The accepted answer by @slaadvak did not work for me for Log4j2 2.8.2. The following did.

To change the log Level universally use:

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

To change the log Level for only the current class, use:

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

Upvotes: 77

alfred.schalk
alfred.schalk

Reputation: 221

I found a good answer here: https://garygregory.wordpress.com/2016/01/11/changing-log-levels-in-log4j2/

You can use org.apache.logging.log4j.core.config.Configurator to set the level for a specific logger.

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

Upvotes: 20

J&#246;rg Friedrich
J&#246;rg Friedrich

Reputation: 191

If you want to change a single specific logger level (not the root logger or loggers configured in the configuration file) you can do this:

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

Upvotes: 19

Victor
Victor

Reputation: 2546

The programmatic approach is rather intrusive. Perhaps you should check JMX support given by Log4J2:

  1. Enable the JMX port in your application start up:

    -Dcom.sun.management.jmxremote.port=[port_num]

  2. Use any of the available JMX clients (the JVM provides one in JAVA_HOME/bin/jconsole.exe) while executing your application.

  3. In JConsole look for the "org.apache.logging.log4j2.Loggers" bean

  4. Finally change the level of your logger

The thing that I like most of this is that you don´t have to modify your code or configuration for managing this. It´s all external and transparent.

More info: http://logging.apache.org/log4j/2.x/manual/jmx.html

Upvotes: 3

Related Questions