Change global setting for Logger instances
Asked Answered
P

5

52

I'm using java.util.logging.Logger as the logging engine for my application. Each class uses it's own logger, i.e., each class has:

private final Logger logger = Logger.getLogger(this.getClass().getName());

I want to set a logging level for all my classes, and be able to change it (i.e., have the setting in one place). Is there a way to do this, other that using a global Level variable and manually set each logger to it?

Precautionary answered 10/6, 2011 at 14:19 Comment(0)
C
55

As Andy answered, in most cases you should use the property file and the VM argument, thus its independent from your code.

But if you want to go programatically for some reason (I myself had a good reason in one case) you can access the Handlers like this too:

Logger rootLogger = LogManager.getLogManager().getLogger("");
rootLogger.setLevel(Level.INFO);
for (Handler h : rootLogger.getHandlers()) {
    h.setLevel(Level.INFO);
}

EDIT I added the setLevel to the root logger as searchengine27 pointed out in in his answer.

The Handlers are File or Console Handlers that you setup via the properties or programatically too.

Or change filters like this:

Logger rootLogger = LogManager.getLogManager().getLogger("");
rootLogger.setFilter(new Filter() {
    @Override
    public boolean isLoggable(LogRecord record) {
            return "something".equals(record.getLoggerName());
    }
});
Cementation answered 10/6, 2011 at 15:8 Comment(5)
yeah, to anyone who sees this as the accepted answer: don't do this. just change the properties in the config file. The other answer should be the "accepted" one (i.e., setting java.util.logging.config.file=...). Code like this will just making switching to slf4j/logback that much harder :-)Aulos
I agree, using the config file is the way to go. Just wanted to show how to do it manually as this was asked in the question.Cementation
There are times when you need to do it programmatically, but it should NOT be the norm...it should be an exceptional need.Marlenmarlena
My use case for changing logging dynamically is in a Tomcat application where 99% of the time I don't need any logging other than CRITICAL, but when something is not working right, I'd like to turn up (down?) the level to INFO to see all my log messages.Tailback
It's common for CLI apps to have an option to set the log level. How else would you implement that if not allowing to set the root logger level programmatically?Darlinedarling
C
80

One easy way is to use a logging properties file, by including this VM argument:

-Djava.util.logging.config.file="logging.properties" 

where "logging.properties" is the path to a file containing logging configuration. For relative paths, the working directory of the process is significant.

In that file, include a line like this:

.level= INFO

This sets the global level, which can be overridden for specific handlers and loggers. For example, a specific logger's level can be overridden like this:

 com.xyz.foo.level = SEVERE

You can get a template for a logging properties file from jre6\lib\logging.properties.

Choppy answered 10/6, 2011 at 14:21 Comment(9)
+1 this should be the accepted answer, and this (simple, concise) answer should be linked to from all those java.util.logging questions in S.O. that incorrectly use the Java API to tweak java.util.logging. Don't know why this nuggget is practically buried in the java docs, everyone would need to do it. As it stands, just using slf4j+logback is easier than trying to figure out jul+logging.propertiesAulos
nb: if you have handlers that also set levels, you'll also have to set/reset these otherwise they will override your other logging levels. If the precedence rules are confusing, you can set both: java.util.logging.FileHandler.level=FINE + com.my.package.level=FINEAulos
I have spotted com.xyz.foo.level in my log manager instance, which led me to jre/lib/logging.properties and the fact that -Djava.util.logging.config.file="WEB-INF/classes/logging.properties" is required, as JVM won't bother to search classpath.Ticktacktoe
Interestingly, per-logger level properties (.level and [package].level) aren't working for me in Java 8. All the other properties work as they're supposed to. I have to explicitly add per-handler level properties ([handler].level).Unknot
@AndyThomas is there a way of doing this WITHOUT the JVM argument?Leid
@AlvaroPedraza - You can set levels or filters programmatically, as discussed in other answers. Regardless, it's useful to be able to change these in production, without requiring a new build. The logging properties file provides one such configuration mechanism.Choppy
@AndyThomas I forgot to say without JVM arguments AND only with configuration (i.e. NOT programmatically)Leid
Note: you should also set handlers property in your own properties file to make it work. For example, if you want to log message in the console, just set handlers= java.util.logging.ConsoleHandler.Nolly
@Zenexer, I was having the same problem, but I just realized that the package levels were working, just not how I thought they were. The package levels are being set, but the handler levels ultimately determine what comes out of the handler.Chateau
C
55

As Andy answered, in most cases you should use the property file and the VM argument, thus its independent from your code.

But if you want to go programatically for some reason (I myself had a good reason in one case) you can access the Handlers like this too:

Logger rootLogger = LogManager.getLogManager().getLogger("");
rootLogger.setLevel(Level.INFO);
for (Handler h : rootLogger.getHandlers()) {
    h.setLevel(Level.INFO);
}

EDIT I added the setLevel to the root logger as searchengine27 pointed out in in his answer.

The Handlers are File or Console Handlers that you setup via the properties or programatically too.

Or change filters like this:

Logger rootLogger = LogManager.getLogManager().getLogger("");
rootLogger.setFilter(new Filter() {
    @Override
    public boolean isLoggable(LogRecord record) {
            return "something".equals(record.getLoggerName());
    }
});
Cementation answered 10/6, 2011 at 15:8 Comment(5)
yeah, to anyone who sees this as the accepted answer: don't do this. just change the properties in the config file. The other answer should be the "accepted" one (i.e., setting java.util.logging.config.file=...). Code like this will just making switching to slf4j/logback that much harder :-)Aulos
I agree, using the config file is the way to go. Just wanted to show how to do it manually as this was asked in the question.Cementation
There are times when you need to do it programmatically, but it should NOT be the norm...it should be an exceptional need.Marlenmarlena
My use case for changing logging dynamically is in a Tomcat application where 99% of the time I don't need any logging other than CRITICAL, but when something is not working right, I'd like to turn up (down?) the level to INFO to see all my log messages.Tailback
It's common for CLI apps to have an option to set the log level. How else would you implement that if not allowing to set the root logger level programmatically?Darlinedarling
B
26

So I don't entirely like all of the answers here, so I'm going to chime in.

Config file use

You're seeing a lot of answers in here telling you to use the config file because it is best practice. I want to explain better how to do this programatically, but before I do, I want to say that I can see where they are coming from, and in the mood of being objective, I will enlighten you a bit (especially because nobody says why its bad practice). I actually want to share what somebody said in a separate StackOverflow answer that is in relation to setting the logger level programatically (Why are the Level.FINE logging messages not showing?):

This is not recommended, for it would result in overriding the global configuration. Using this throughout your code base will result in a possibly unmanageable logger configuration.

On that note, I think Andy Thomas has a goodish answer related to not doing it non-programatically.

Programatically setting the Level

That being said, I want to go into a bit more detail about doing it programatically, because I think it has its uses.

Imagine a scenario where you are writing something with a command line interface and you have an option to specify the verbosity of your execution, or even where it goes to (as in dynamic log files). I may be mistaken, but you would probably not want to do this statically in a .conf file. Especially so if you don't want to make your userbase responsible for setting these things (for whatever arbitrary reason) in the config file. This comes at the expense of the above quote, however. Here is an example of how you can do it programatically, keeping all of the existing handlers to whatever level they are at already, and only FileHandler's assume the new level:

public static void setDebugLevel(Level newLvl) {
    Logger rootLogger = LogManager.getLogManager().getLogger("");
    Handler[] handlers = rootLogger.getHandlers();
    rootLogger.setLevel(newLvl);
    for (Handler h : handlers) {
        if(h instanceof FileHandler)
            h.setLevel(newLvl);
    }
}

I wanted to expand on this, over the accepted answer for one reason in particular. When doing it programatically, you just want to make sure that you set the level for the logger and the handler(s). The way it works, is it will check to see if the request is too low for the logger, and if it is it will discard it. Then the handler(s) have the same check, so you will want to make sure both the loggers and handlers are set to the level you want it.

Blagoveshchensk answered 5/9, 2014 at 0:50 Comment(5)
Also, if you are building a desktop swing or fxapplication. you will want to set the logging dynamically to get as much information as possible.Saba
Just to clarify, "" is the root logger, not an anonymous logger.Unknot
You are correct. I updated the variable name in the code snippet to make it more clear.Blagoveshchensk
upvoted this for emphasizing that you set the level for the logger and the handler(s)Outshout
How to do it for specific logger. eg Logger logger = Logger.getLogger(ArrayBackedByteStream.class.getName());Expunge
S
7

One-liner Java 8 approach to morja's answer:

Arrays.stream(LogManager.getLogManager().getLogger("").getHandlers()).forEach(h -> h.setLevel(Level.INFO));
Sunbeam answered 17/3, 2017 at 14:48 Comment(0)
A
3

JUL(java.util.logging) is java default logger within jvm.

Java Logging Technology--see Overview

So you may find that there is a default config file already in C:\Program Files\Java\jre1.8.0_221\lib\logging.properties

I recommend that you create a new config file under your project to override the default setting, do as following:

config file name, logging.properties, all log level can be found in Class Level

handlers= java.util.logging.ConsoleHandler
.level= INFO
java.util.logging.ConsoleHandler.level = ALL
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format= [%1$tF %1$tT] [%4$-7s] %5$s %n

# your specific logger level
com.xyz.foo.level = SEVERE

Then add jvm option to enable the config

java -Djava.util.logging.config.file="logging.properties" -Duser.country=CN -Duser.language=en

user.country and user.language may have an effect on log message localization

Agone answered 17/12, 2019 at 3:28 Comment(1)
I like this answerCondyloma

© 2022 - 2024 — McMap. All rights reserved.