89

I want to add some log.debug statements to a class I'm working on, and I'd like to see that in output when running the test. I'd like to override the log4j properties on the command line, with something like this:

-Dlog4j.logger.com.mypackage.Thingie=DEBUG

I do this kind of thing frequently. I am specifically only interested in a way to pass this on the command line. I know how to do it with a config file, and that doesn't suit my workflow.

Kevin Peterson
  • 7,189
  • 5
  • 36
  • 43

7 Answers7

61

As part of your jvm arguments you can set -Dlog4j.configuration=file:"<FILE_PATH>". Where FILE_PATH is the path of your log4j.properties file.

Please note that as of log4j2, the new system variable to use is log4j.configurationFile and you put in the actual path to the file (i.e. without the file: prefix) and it will automatically load the factory based on the extension of the configuration file:

-Dlog4j.configurationFile=/path/to/log4jconfig.{ext}
Nick Pierpoint
  • 17,641
  • 9
  • 46
  • 74
Anubis05
  • 1,234
  • 2
  • 13
  • 17
  • 3
    FILE_PATH is actually searched on the CLASSPATH, including inside jar files. – Robin Green Jan 12 '12 at 14:35
  • 13
    You need to put "file:" in front of the path if it is a file on disk. In other words... -Dlog4j.configuration=file: http://stackoverflow.com/questions/778933/log4j-configuration-via-jvm-arguments – crowmagnumb Mar 22 '12 at 20:02
  • 3
    This works as advertised; however I am trying to override a setting of a properties file in the jar, and the latter appears to get set after. Any advice? – John Lehmann Jul 17 '13 at 15:01
41

These answers actually dissuaded me from trying the simplest possible thing! Simply specify a threshold for an appender (say, "console") in your log4j.configuration like so:

log4j.appender.console.threshold=${my.logging.threshold}

Then, on the command line, include the system property -Dlog4j.info -Dmy.logging.threshold=INFO. I assume that any other property can be parameterized in this way, but this is the easiest way to raise or lower the logging level globally.

AbuNassar
  • 1,128
  • 12
  • 12
  • I'm pretty sure this is the simplest solution to the original question! – Droj Sep 18 '17 at 17:05
  • @Droj Maybe so, but OP wanted to do this all in code. Chacun a son gout. – AbuNassar Sep 19 '17 at 17:37
  • In my case, I wanted to set it from the command line too, but I already had a config. I just didn't want to have to edit the file to get different logging. I didn't read it as "all in code", but maybe so... – Droj Sep 20 '17 at 18:41
  • 2
    Just a minor improvement: yaml `Loggers:\n Logger:\n name: stuff \n level: ${sys:my.log.level:-INFO}` – Ich Oct 19 '20 at 11:45
  • I like the above YAML, but IIRC Spring won't do variable interpolation on YAML. – AbuNassar Oct 23 '20 at 15:26
22

With Log4j2, this can be achieved using the following utility method added to your code.

private static void setLogLevel() {
  if (Boolean.getBoolean("log4j.debug")) {
    Configurator.setLevel(System.getProperty("log4j.logger"), Level.DEBUG);
  }
}

You need these imports

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.config.Configurator;

Now invoke the setLogLevel method in your main() or whereever appropriate and pass command line params -Dlog4j.logger=com.mypackage.Thingie and -Dlog4j.debug=true.

Neo
  • 4,640
  • 5
  • 39
  • 53
  • 4
    This should be the accepted answer now that the packages is updated. Thank you for an updated answer--I deeply appreciate updated answers when it comes to long-standing questions. You saved me quite a bit of frustration. – Daniel B. Chapman Mar 06 '17 at 02:25
18

log4j does not support this directly.

As you do not want a configuration file, you most likely use programmatic configuration. I would suggest that you look into scanning all the system properties, and explicitly program what you want based on this.

Thorbjørn Ravn Andersen
  • 73,784
  • 33
  • 194
  • 347
6

Based on Thorbjørn Ravn Andersens suggestion I wrote some code that makes this work

Add the following early in the main method and it is now possible to set the log level from the comand line. This have been tested in a project of mine but I'm new to log4j and might have made some mistake. If so please correct me.

    Logger.getRootLogger().setLevel(Level.WARN);
    HashMap<String,Level> logLevels=new HashMap<String,Level>();
    logLevels.put("ALL",Level.ALL);
    logLevels.put("TRACE",Level.TRACE);
    logLevels.put("DEBUG",Level.DEBUG);
    logLevels.put("INFO",Level.INFO);
    logLevels.put("WARN",Level.WARN);
    logLevels.put("ERROR",Level.ERROR);
    logLevels.put("FATAL",Level.FATAL);
    logLevels.put("OFF",Level.OFF);
    for(String name:System.getProperties().stringPropertyNames()){
        String logger="log4j.logger.";
        if(name.startsWith(logger)){
            String loggerName=name.substring(logger.length());
            String loggerValue=System.getProperty(name);
            if(logLevels.containsKey(loggerValue))
                Logger.getLogger(loggerName).setLevel(logLevels.get(loggerValue));
            else
                Logger.getRootLogger().warn("unknown log4j logg level on comand line: "+loggerValue);
        }
    }
lijat
  • 640
  • 7
  • 16
5

In my pretty standard setup I've been seeing the following work well when passed in as VM Option (commandline before class in Java, or VM Option in an IDE):

-Droot.log.level=TRACE
Rob Dawson
  • 1,349
  • 10
  • 21
2

Based on @lijat, here is a simplified implementation. In my spring-based application I simply load this as a bean.

public static void configureLog4jFromSystemProperties()
{
  final String LOGGER_PREFIX = "log4j.logger.";

  for(String propertyName : System.getProperties().stringPropertyNames())
  {
    if (propertyName.startsWith(LOGGER_PREFIX)) {
      String loggerName = propertyName.substring(LOGGER_PREFIX.length());
      String levelName = System.getProperty(propertyName, "");
      Level level = Level.toLevel(levelName); // defaults to DEBUG
      if (!"".equals(levelName) && !levelName.toUpperCase().equals(level.toString())) {
        logger.error("Skipping unrecognized log4j log level " + levelName + ": -D" + propertyName + "=" + levelName);
        continue;
      }
      logger.info("Setting " + loggerName + " => " + level.toString());
      Logger.getLogger(loggerName).setLevel(level);
    }
  }
}
Chris Noe
  • 36,411
  • 22
  • 71
  • 92