19

logger.setLevel() method is not available in log4j2 API. So how to set log level at run time.

Nandan
  • 203
  • 1
  • 2
  • 7
  • Possible duplicate of [Programmatically change log level in Log4j2](http://stackoverflow.com/questions/23434252/programmatically-change-log-level-in-log4j2) – Martin Schröder Feb 01 '17 at 10:33

5 Answers5

13

I'm not sure if this is the best way, but you set the level on org.apache.logging.log4j.core.config.LoggerConfig which you can get from the LoggerContext via the LogManager.

Once set, you can update the loggers with the new configuration.

As an example:

public static void main(String[] args) {
    Logger log = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
    log.error("An error");
    log.debug("A debug");

    LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
    Configuration conf = ctx.getConfiguration();
    conf.getLoggerConfig(LogManager.ROOT_LOGGER_NAME).setLevel(Level.DEBUG);
    ctx.updateLoggers(conf);

    log.error("Another error");
    log.debug("Another debug");
}

Yields:

14:03:41.346 [main] ERROR  - An error
14:03:41.348 [main] ERROR  - Another error
14:03:41.348 [main] DEBUG  - Another debug
amcintosh
  • 656
  • 1
  • 6
  • 15
  • 1
    Works well for the root logger, but doesn't work for any other logger -- per-package, for instance. In this case, the log level seems unchanged, even when calling `reconfigure` on the context. – amoe Dec 11 '13 at 11:27
  • 1
    @amoe same issue here. i guess this related to the right context on webapp program. did you manager to change all logger level? – oak Aug 10 '14 at 09:25
8

Credit to amcintosh, I wrapped their answer in a function:

/** Override the logging level of a given logger, return the previous level */
public static Level setLevel(Logger log, Level level) {
  LoggerContext ctx = (LoggerContext)LogManager.getContext(false);
  Configuration conf = ctx.getConfiguration();
  LoggerConfig lconf = conf.getLoggerConfig(log.getName());
  Level oldLevel = lconf.getLevel();
  lconf.setLevel(level);
  ctx.updateLoggers(conf);
  return oldLevel;
}

Despite amoe's comment, this seems to be working correctly for me using Log4J 2.5.

dimo414
  • 47,227
  • 18
  • 148
  • 244
  • Can it be configured for thread specific? Behaviour same as ThreadContext. – theGamblerRises Aug 16 '16 at 14:44
  • 1
    @theGamblerRises I'd suggest posting a separate question, rather than trying to explore this in the comments. Offhand I'd guess that you cannot control log levels per-thread with this mechanism, but there may well be other ways to do what you want. If you post a separate question feel free to share a link to it here. – dimo414 Aug 17 '16 at 14:53
6

Gary Gregory is correct.

Also the answer to this question is right there on the FAQ page in log4j2's site

https://logging.apache.org/log4j/2.x/faq.html#reconfig_level_from_code

Sample Code below:

Configurator.setLevel(logger.getName(), Level.INFO);
Sudeep Shakya
  • 101
  • 1
  • 4
  • Whilst this may theoretically answer the question, [it would be preferable](//meta.stackoverflow.com/q/8259) to include the essential parts of the answer here, and provide the link for reference. – Draken Apr 07 '17 at 16:36
  • I'm getting `ERROR StatusConsoleListener Reconfiguration failed: No configuration found for '18b4aac2' at 'null' in 'null'` with that. – luckydonald Aug 15 '23 at 13:34
5

On my side, i had to use this code in order to have this working fine (based on previous answers).

import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.AbstractConfiguration;

...

public static void changeLoggerLevel(final String module, final Level level) {
  String moduleRenamed = module.replaceAll("/", ".");
  LoggerContext ctx = (LoggerContext)LogManager.getContext(false);
  AbstractConfiguration configuration = (AbstractConfiguration) ctx
        .getConfiguration();
  if (configuration.getLogger(moduleRenamed) != null) {
    LoggerConfig loggerConfig = configuration.getLoggerConfig(moduleRenamed);
    loggerConfig.setLevel(level);
  } else {
    LoggerConfig loggerConfig = new LoggerConfig(moduleRenamed, level, true);
    configuration.addLogger(moduleRenamed, loggerConfig);
  }
  ctx.updateLoggers(configuration);
}

The problem was with the getLoggerConfig() call; if the module you are trying to give a new level is not yet registered, this method returns the root logger (or any intermediate sub path registered), and thus instead of altering the level for com.mycompany you will alter root or com level. That's why you have to add a new LoggerConfig in case the module to alter is not yet registered.

dimo414
  • 47,227
  • 18
  • 148
  • 244
SRG
  • 1,569
  • 1
  • 17
  • 19
  • Good catch, that behavior is documented, but not what people would usually expect. If I understand what you're saying however, this could equivalently be addressed by simply ensuring the `Logger` exists before calling `getLoggerConfig()`, right? – dimo414 Sep 22 '14 at 17:46
  • I haven't tryied, but i would have say that the logger inherits from a previous (upper) level (possibly root), and so is always defined ... it seems to just be the configuration inheritance that is not fully offered (and it is the configuration that have to be altered in order to change the log level, not the logger itself). – SRG Sep 22 '14 at 20:52
  • why do all of this when you can just do "'Configurator.setLevel(logger.getName(), Level.INFO);" as explained above? – Jeryl Cook Apr 29 '21 at 16:03
3

The following APIs in the class org.apache.logging.log4j.core.config.Configurator allow you to change Levels:

Gary Gregory
  • 439
  • 5
  • 7