JUL (an abbreviation of java.util.logging) is a logging utility that comes by default with Java SE, the standard library.
From looking up how to use it, there seems to be general confusion how to set it up, a situation that seems to cause developers to resort to other logging frameworks; or worse, mixing multiple ones together. Not any of the solutions and examples available online that I looked at worked on my setup, using JDK 17 and Gradle, either.
There is a solution, however.
One approach was to set the JVM parameters that point to a properties file which contains the configuration for the logger:
-Djava.util.logging.config.file=/path/to/logging.properties
The catch? This alone does not work. Debugging the code I figured out the properties contained in the file were not applied to the properties of the LogManager at all, such as message format or logging level. It simply contained its standard values.
Time for an important piece of information: The LogManager is a central Class in JUL, where all Logger instances inherit properties (such as their log levels) from the moment you call Logger.getLogger(…).
Ergo, something is missing here! But based on that information alone we can figure it out:
One has to complement a piece of code that reads the configuration howsoever, wherever and then apply it to the LogManager. Once I programmatically loaded the properties file using LoadManager.readConfiguration(), the configuration was also applied and worked properly.
In my particular case I was using a LibGDX and FileHandle. For other setups, replace the Gdx.files.internal() call with new File() and obtain the InputStream from there.
InputStream stream = null;
try {
LogManager logManager = LogManager.getLogManager();
FileHandle internal = Gdx.files.internal("logging.properties");
stream = internal.read();
logManager.readConfiguration( stream );
stream.close();
} catch (IOException e) {
// TODO error handling
}
Note, this isn’t an ideal solution, but I want to list it as framework-dependent solution regardless to illustrate the code for loading such configuration files can look wildly different. I think it can be seen as explanation why this particular bit is missing in JUL.
For a better, more flexible use that also makes use of the JVM parameter, it has to look something like this:
String julProperty = System.getProperty("java.util.logging.config.file");
FileInputStream fis = new FileInputStream( julProperty );
LoadManager.readConfiguration(fis);
Once the LogManager received your configuration in this way, the logging framework will act as you intended.
I hope this information is helpful to you. Let me know if you have questions or other solutions.
Links
- You might want to check this list of available JUL properties on jenkov.com
- Shoutout to the excellent articles provided at mkyong.com which inspired this particular solution