Can I do something along the lines of:
-Djava.util.logging.loglevel=FINE
Obviously that doesn't work, but you get the idea. Is there anything like that? Or am I forced to create a properties file?
Can I do something along the lines of:
-Djava.util.logging.loglevel=FINE
Obviously that doesn't work, but you get the idea. Is there anything like that? Or am I forced to create a properties file?
for java-9+ put this code at the beginning of your main
method:
(see the bottom for java-8 and earlier)
var cmdLineVal = System.getProperty("java.util.logging.loglevel");
if (cmdLineVal != null) {
LogManager.getLogManager().updateConfiguration(
(key) -> (oldVal, newVal) ->
key.equals(".level")
|| key.equals("java.util.logging.ConsoleHandler.level")
? cmdLineVal : newVal
);
}
main
cannot be modified:Generally java.util.logging
does not use system properties to configure itself (there are a few exceptions, like java.util.logging.SimpleFormatter.format
). Instead, the global LogManager singleton instance is responsible for configuring the logging subsystem and by default it loads properties from ${JAVA_HOME}/conf/logging.properties
. There are a few ways to tweak this behavior:
java.util.logging.config.file
system property with a path to an alternative logging config properties file.java.util.logging.config.class
system property with a class name that completely overrides configuration process (usually by providing a custom InputStream
with logging config properties to readConfiguration(is)).So in case of overriding the global root log-level, it's probably easiest to use updateConfiguration(mapper)
somewhere at the beginning of your main
method. LogManager
uses .level
property (level of the empty-string root logger) as a default for its child loggers not configured explicitly, so using the java.util.logging.loglevel
system property from the OP, it would be like this:
var cmdLineVal = System.getProperty("java.util.logging.loglevel");
if (cmdLineVal != null) {
LogManager.getLogManager().updateConfiguration(
(key) -> (oldVal, newVal) ->
key.equals(".level")
? cmdLineVal : newVal
);
}
Note that in case of the default logging config, the above is not sufficient for any FINE
(or lower) log entries to be output on the console, as ConsoleHandler by default outputs INFO
and higher. To change this, you need to override also java.util.logging.ConsoleHandler.level
logging config property. If you want to use the same system property for this again, then you need to modify the argument of updateConfiguration
like the below:
var cmdLineVal = System.getProperty("java.util.logging.loglevel");
if (cmdLineVal != null) {
LogManager.getLogManager().updateConfiguration(
(key) -> (oldVal, newVal) ->
key.equals(".level")
|| key.equals("java.util.logging.ConsoleHandler.level")
? cmdLineVal : newVal
);
}
If you can't change the main
method, then you can define the previously mentioned java.util.logging.config.class
property to point to your class like this: -Djava.util.logging.config.class=com.example.MyJulConfig
. This will delegate the task of logging configuration to the constructor of this class. In such constructor you can first read the config from a file the normal way (using readConfiguration() method) and then use the code from the previous snippet:
public MyJulConfig() throws IOException {
System.clearProperty("java.util.logging.config.class");
LogManager.getLogManager().readConfiguration();
// the same code as in the previous snippet:
var cmdLineVal = System.getProperty("java.util.logging.loglevel");
if (cmdLineVal != null) {
LogManager.getLogManager().updateConfiguration(
(key) -> (oldVal, newVal) ->
key.equals(".level")
|| key.equals("java.util.logging.ConsoleHandler.level")
? cmdLineVal : newVal
);
}
}
As a final note, I've recently written a simple helper function to make any ad-hoc command-line changes to logging config easier: overrideLogLevelsWithSystemProperties (also supports adding new logging properties).
As mentioned by @TWiStErRob in the comment, you don't even need to include the containing jul-utils
as a dependency of your project: just add it to your classpath (available in central) when starting your app and define your desired system properties:
java -cp /path/to/jul-utils.jar:${CLASSPATH} \
-Djava.util.logging.config.class=pl.morgwai.base.jul.JulConfigurator \
-Djava.util.logging.overrideLevel=,java.util.logging.ConsoleHandler,com.third.party.talkative.lib \
-D.level=FINE \
-Djava.util.logging.ConsoleHandler.level=FINE \
-Dcom.third.party.talkative.lib.level=SEVERE \
${MY_JAVA_APP_MAINCLASS_AND_ARGUMENTS}
Properties
using load(is) (see here how LogManager
determines which file to read).level
and java.util.logging.ConsoleHandler.level
using setProperty(key, value) with the value obtained from the system propertyByteArrayOutputStream
using store(os, null)ByteArrayInputStream
(see also this discussion) and pass it to readConfiguration(is)as before, you can do it either in your main
method or in a constructor of a class pointed by java.util.logging.config.class
system property.
You can even pass your log Level as a user defined property.
-DmyProp.logLevel=FINE
In your code:
String logLevel = System.getProperties("myProp.logLevel");
But I have the idea that your are looking for a more "built-in" and automatically handled property, right? AFAIK, it doesn't exist, but maybe I'm wrong.
you can configure your code to set the level based on an envrioment variable :
String sLoglevel= System.getenv("LOGLEVEL");
int ilevel = loglevel.parseInt(sLoglevel);
//set the log level based on retrieved value