Dynamically Changing Log4J Log Level

Dynamically Changing log4j log level

Changing the log level is simple; modifying other portions of the configuration will pose a more in depth approach.

LogManager.getRootLogger().setLevel(Level.DEBUG);

The changes are permanent through the life cyle of the Logger. On reinitialization the configuration will be read and used as setting the level at runtime does not persist the level change.

UPDATE: If you are using Log4j 2 you should remove the calls to setLevel per the documentation as this can be achieved via implementation classes.

Calls to logger.setLevel() or similar methods are not supported in the
API. Applications should remove these. Equivalent functionality is
provided in the Log4j 2 implementation classes but may leave the
application susceptible to changes in Log4j 2 internals.

Programmatically change log level in Log4j2

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.

Log4j: Change log level programmatically that works for to-be created loggers

Didn't find the resource anymore, but as to my faded memory LogManager.getLogger("com.my.company").setLevel(whateverloglevel) should do the job.

All loggers that are created with LogManager.getLogger(MyClass.class) where MyClass is in com.my.company or in a subtree of that will be affected.

whateverloglevel is one of Level:


ALL
    The ALL has the lowest possible rank and is intended to turn on all logging.

DEBUG
    The DEBUG Level designates fine-grained informational events that are most useful to debug an application.

ERROR
    The ERROR level designates error events that might still allow the application to continue running.

FATAL
    The FATAL level designates very severe error events that will presumably lead the application to abort.

INFO
    The INFO level designates informational messages that highlight the progress of the application at coarse-grained level.
OFF
    The OFF has the highest possible rank and is intended to turn off logging.

TRACE
    The TRACE Level designates finer-grained informational events than the DEBUG

WARN
    The WARN level designates potentially harmful situations.



Be aware that this probably does not work in log4j 2.

For (I think) version >= 2.4 see:

  • log4j FAQ
  • Programmatically change log level in Log4j2

Dynamically changing log level in log4j version 1 and bridge to version 2

You should use these 2 dependencies:

<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-1.2-api</artifactId>
<version>2.11.1</version>
</dependency>

And adapt log4j.properties, which must be placed in the project´s classpath. See: https://logging.apache.org/log4j/2.x/manual/configuration.html#Properties

How to dynamically change log level in SLF4j OR Log4J

Consider Logback http://logback.qos.ch/ - "a successor to the popular log4j project, picking up where log4j leaves off". If instructed to do so, logback-classic will scan for changes in its configuration file and automatically reconfigure itself when the configuration file changes. Besides, you can control Logback's logging levels with JMX.

can we change the logging level of log4j at runtime

Calling the Logger.setLevel method with the desired Level can alter a Logger's output level at runtime.

The following is an example which demonstrates its usage:

Logger logger = Logger.getLogger("myLogger");
logger.addAppender(new ConsoleAppender(new SimpleLayout()));

System.out.println("*** The current level will be INFO");

logger.setLevel(Level.INFO);
logger.warn("Only INFO and higher will appear");
logger.info("Only INFO and higher will appear");
logger.debug("Only INFO and higher will appear");

System.out.println("*** Changing level to DEBUG");

// remember the previous level
Level previousLevel = logger.getLevel();

logger.setLevel(Level.DEBUG);
logger.warn("DEBUG and higher will appear");
logger.info("DEBUG and higher will appear");
logger.debug("DEBUG and higher will appear");

System.out.println("*** Changing level back to previous level");

// revert to previous level
logger.setLevel(previousLevel);
logger.warn("Only INFO and higher will appear");
logger.info("Only INFO and higher will appear");
logger.debug("Only INFO and higher will appear");

The above outputs:

*** The current level will be INFO
WARN - Only INFO and higher will appear
INFO - Only INFO and higher will appear
*** Changing level to DEBUG
WARN - DEBUG and higher will appear
INFO - DEBUG and higher will appear
DEBUG - DEBUG and higher will appear
*** Changing level back to previous level
WARN - Only INFO and higher will appear
INFO - Only INFO and higher will appear

The above demonstrates how to change the level of one Logger named myLogger, but if the levels of all the loggers in the current repository should be changed, then the setLevel method on the root logger obtained by Logger.getRootLogger should be called to change the levels on all the child loggers.

Change log level programmatically

I would strongly suggest that you do NOT use a programmatic solution for this because it will make your code depend on the implementation details of log4j2. This will make long term maintenance of your code problematic if the implementation changes. So, if you don't want to go with the JMX approach then you could set up your log4j2 configuration to use a DynamicThresholdFilter.

Here is a simple example of the filter approach:

First, a log4j2.xml file to configure the log4j2 system:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
<DynamicThresholdFilter key="myLogLvl" defaultThreshold="ERROR"
onMatch="ACCEPT" onMismatch="DENY">
<KeyValuePair key="TRACE" value="TRACE"/>
<KeyValuePair key="DEBUG" value="DEBUG"/>
<KeyValuePair key="INFO" value="INFO"/>
<KeyValuePair key="WARN" value="WARN"/>
<KeyValuePair key="FATAL" value="FATAL"/>
</DynamicThresholdFilter>
</Console>
</Appenders>

<Loggers>
<Root level="ALL">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>

Notice how I have set up the filter so that the DynamicThresholdFilter has a key of "myLogLvl" and then several KeyValuePair that define the log level threshold based on the value in ThreadContext for the key "myLogLvl". I assumed you wanted to use the names of the levels as the value you would put into ThreadContext.

Also notice that I have set the Root logger's level to "ALL". This is so that all messages will be accepted by the logger and then filtered by the filter. In other words I'm putting the filter in control of which messages are accepted rather than the logger.

Here is a simple Java class to generate some logs:

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;

public class SomeClass {

private static final Logger log = LogManager.getLogger();

public static void main(String[] args){

ThreadContext.put("myLogLvl", "WARN");

if(log.isDebugEnabled())
log.debug("This is some debug! (This should not appear in console)");
log.info("Here's some info! (This should not appear in console)");
log.error("Some error happened! (We will see this in the console)");

//Maybe now I want INFO log level
ThreadContext.put("myLogLvl", "INFO");

log.info("This should now appear in the console");
log.debug("This still should --not-- appear");
log.fatal("This will also appear");
}
}

Notice the first I do is set the ThreadContext variable "myLogLvl" to "WARN" so that only messages that are "WARN" level or more specific are accepted. If you don't do this there will be no value for "myLogLvl" which means the default level defined in the filter will not apply either, so all messages will be accepted.

Here is sample output generated by the above:

10:39:44.668 [main] ERROR example.SomeClass - Some error happened! (We will see this in the console)
10:39:44.670 [main] INFO example.SomeClass - This should now appear in the console
10:39:44.670 [main] FATAL example.SomeClass - This will also appear

Hope this helps!



Related Topics



Leave a reply



Submit