When is ".level" required in java util logging properties? - java

I've seen java util logging configured in a number of ways. Usually the fully qualified class name is used for the logger name. In the corresponding logging.properties file, I've seen log level configured at either the package level or the class level in a couple different ways. For example, to set the loglevel to FINE for com.example.MyClass:
com.example.level = FINE
com.example.* = FINE
com.example.MyClass = FINE
com.example.MyClass.level = FINE
Do all four of these variants work (assuming they are not overridden later in the file)?
Are any of the options "more correct" than the others?
Does java.util.logging just assume .level if its not there?
I tried finding the definitive guidance on this config file but stopped at
https://docs.oracle.com/javase/8/docs/technotes/guides/logging/overview.html#a1.8 which seems quite underspecified.

Do all four of these variants work (assuming they are not overridden later in the file)?
Most of the online tutorials I've seen use the explicit .level suffix...is that preferred (and why)?
Under the standard LogManager, com.example.* = FINE and com.example.MyClass = FINE would not change the level. The key has to end with .level in order to change the level.
Per the LogManager documentation:
All properties whose names end with ".level" are assumed to define log levels for Loggers. Thus "foo.level" defines a log level for the logger called "foo" and (recursively) for any of its children in the naming hierarchy. Log Levels are applied in the order they are defined in the properties file. Thus level settings for child nodes in the tree should come after settings for their parents. The property name ".level" can be used to set the level for the root of the tree.
If you are using a subclass of LogManager then you need to consult that documentation to verify the syntax.
Does java.util.logging just assume .level if its not there?
According to the documentation it does not. If you declare something without the .level it would just be considered a LogManager entry.
Are any of the options "more correct" than the others?
The LogManager properties file can't create loggers. This means that your log file must match how the code is creating the loggers. For instance, if your file is using com.example.level = FINE and your code is using com.example.MyClass1 and com.example.MyClass2 as the logger name you will never see MyClass1 or MyClass2 switch to FINE because the code never created package parent logger. Root is the parent of all named loggers so that is the ideal way to change multiple loggers at once. If you need to do anything really complicated then you use the config option supported by the LogManager.

Related

What the difference in LoggerFactory.getLogger "root" vs "class" name?

I'm trying to find the answer about the differences between:
class MyClass {
private static Logger logger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
}
and:
class MyClass {
private static Logger logger = LoggerFactory.getLogger(MyClass.class);
}
Is it only useful with you are planning to do a fine logging setup? Like separate the log of the class in a different file, print more/less informations for each one, etc.
I have this doubt because most of my classes I use LoggerFactory.getLogger(MyClass.class) but I think the LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME) is enough in the most of the cases.
Thanks!
Is it only useful with you are planning to do a fine logging setup? Like separate the log of the class in a different file, print more/less informations for each one, etc.
This is correct. By controlling your logging down to the class level, by giving each class their own logger, you can more finely control the logging. For example, we typically log all log entries (regardless of level) for classes in our packages, e.g. my.employer.com.team.project. We then log ERROR for all other loggers. We then have the ability to view all the loggers that are being used on the application and can remotely enable/disable any logger we want in real-time.
I have this doubt because most of my classes I use LoggerFactory.getLogger(MyClass.class) but I think the LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME) is enough in the most of the cases.
If you give all your classes the same logger, then they will all behave in the same way. I think you are right that for most cases you will treat all your classes' logging the same way, but that is not always the case. Also, if you are writing library code, then you must not use the root logger because now you remove the ability of the user's of your library to tune your libraries' logs.

Log level in Jerseys new LoggingFeature

I am trying to log with Jersey 2.23. Since this version, the class LoggingFilter is deprecated, as one can read for example here: https://jersey.java.net/documentation/latest/logging_chapter.html. So I have to use LoggingFeature instead.
What did not work was the register method of ResourceConfig as it is explained in this documentation. But in the end the property method worked:
client.property(LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_SERVER, "WARN");
This prints every message as a warning. Unfortunately it is documented nowhere (at least I couldn't find anything) which values are allowed. Obviously it has to be a String, because I get a log message that there is no way to transform the value into a String, when I try anything else than a String. Now I want to log this messages with level TRACE and I can't find a suiting String to achieve this. "TRACE" and "FINE" did not work for example, in these cases nothing is logged. I have to mention that I use Log4j2 together with the Slf4jBridgeHandler because Jersey uses JUL.
I struggled with this myself for several hours before finally uncovering the "mystery" today.
It is somewhat counter-intuitive but the level you are setting with the LOGGING_FEATURE_LOGGER_LEVEL_SERVER is actually the minimum level the server's logger must be set to in order to print your logs. I had assumed, based on the name, that this was setting the actual logger level -- implying that setting it to FINER or FINEST would produce more output. Instead it is simply "turning off" logging unless a specific level is met.
As an example, if you set it to WARNING then you will see the logs as long as the server/client is set to print at least WARNING level. The levels as defined by java.util.logging are:
SEVERE (highest value)
WARNING
INFO
CONFIG
FINE
FINER
FINEST (lowest value)
So by setting it to WARNING (the literal WARN does not work for me in 2.23.1) you will see the logs because, by default, logging is typically at INFO level.
An alternate solution is to change the default logging level in your logging.properties file which is typically in $JAVA_HOME/jre/lib/logging.properties. You could, for example, make the following changes to the file and you would no longer need to set any special properties in your code:
java.util.logging.ConsoleHandler.level = FINEST
org.glassfish.jersey.test.JerseyTest.level = FINEST
The obvious disadvantage to this is that it will effect anything you run from this JDK/JRE. There are ways you can override this standard location and use an alternate logging.properties file but it depends on how you're executing your code so I will let you research that based on your circumstances.
One example would be this thread which explains how to do it when using Maven: Logging level under maven surefire

Adding Multiple Handlers to Logger

I'm using java.util.logging. In my code, I'm adding multiple handlers to my logger. I have 1 ConsoleHandler and 1 FileHandler. I only want levels above Info (inclusive) to be printed to the console and all levels to be printed to the log file. When I try to set the logging levels of the 2 file handlers accordingly, and add the handlers to the logger, the log file ends up only including levels above Info (as specified by the ConsoleHandler). Does this mean I cannot specify two different file handlers for one logger? How can I resolve this issue and get the desired functionality? Really appreciate your help.
I solved my question myself. You need to set the level of the logger to Level.FINEST before adding the handlers to it because the logger by default is set to a level higher than FINEST. Therefore setting the ConsoleHandler's level to FINEST without changing the level of the logger will not produce the required results.

Filtering a subclass in log4j

I have a message driven system with, say, com.example.BaseMessagingAgent class, which is a basic class for many message agents. This base class logs message events. There are many subclasses of this base class, implementing different specific agents of system. Let us com.example.MyAgent which extends com.example.BaseMessagingAgent is one of them.
I want to log messages only related to class MyAgent. But I cannot define logging as:
log4j.logger.com.example.MyAgent=DEBUG, APPENDER
because logging occurs in parent class com.example.BasicMessagingAgent - I will record nothing.
And I also do not want to set logging in base class:
log4j.logger.com.example.BaseMessagingAgent=DEBUG, APPENDER
because it will log events for all agents, and I will have a lot of unnecessary logging.
Does enyone know how to limit logging to only one subclass?
You should write a filter for Log4j since AFAIK there is no way to put such information on log4j.properties file. More details at http://books.google.it/books?id=vHvY008Zq-YC&lpg=PA95&ots=yi335bZU7z&dq=&pg=PA95#v=onepage&q&f=false
It's pretty simple, actually.
First, add the appender to the root logger. Really. It will make your life much more simple.
Now configure the whole thing:
log4j.rootLogger=DEBUG, APPENDER
log4j.logger.com=ERROR
log4j.logger.com.example.MyAgent=DEBUG
The default for all classes below "com.*" will be to log only errors. The sole exception is com.example.MyAgent which will log at debug level.
You need to set the root logger to DEBUG as well or it will throw away all the DEBUG log messages.
The next step is to use one logger per instance. To get that, simply remove the static in the line which you create your logger and replace BaseMessagingAgent with getClass()
I know, it looks like overkill but that's how log4j works. Also creating a logger per instance isn't very expensive (unless you create millions of MyAgent per second).
If you really want to add an appender to a single class, then don't forget to turn off additivity (...Class.additivity=false) or you will get all log messages twice.

How to set javax logger handle to be refactor sensitive

Someone might yell at me to read the faqqing faq, but I'm in a hurry ...
Does anyone have a way to make javax or log4j logger refactor-sensitive?
Say, that currently utils.Something has the logger handle:
final static private Logger logger = Logger.getLogger(Something.class.getName());
And logging.properties has
.level = warning
utils.Something.level=info
Then using Eclipse to refactor Something to
nutilla.Somewhere
resulting in my logger handle and logger property becoming out of sync.
Perhaps, set logging levels programmatically?
Has anyone bothered to do it and was it worth the trouble?
Clarification:
After refactoring utils.Something to nutilla.Somewhere, the logger handle now would only log warning and not info, because of the entry in logging.properties file. So the question is, is there a way to replace the function of logging.properties file with programmatic means and if so, is it worth the trouble?
Reason and Motivation for question
I'm obstinate at not listening when advising me to avoid refactoring because ...
Refactoring is a constant habit of mine. I create classes by the hour, merge them, delete them, extract methods, etc ... I'm a restless class creator who finds no time wondering where to initially place a class. I dislike sitting down wasting time wondering where to place them initially - so I just place them in the most convenient package namespace.
After building a good amount of class/interface structure, it becomes apparent to me where certain classes, interfaces or methods shd have been then all the refactoring activities take place and ... tada ... that's when my logging.properties file is ruined a hundred lines.
If you configure logging using class (as opposed to package) names, checking "Update fully qualified class names in non-Java text files" in eclipse's rename refactoring dialog should do the trick.
I do not think there is a way out of the box that updated the package names and class names in your properties file as a result of refactoring actions.
You can:
update the properties file by hand when refactoring is done (refactoring should be an action that is not undertaken eveery week :=)
use fixed strings to create loggers (make logging more functional instead of physical)
load the properties file and adjust the property names on the basis of constants you declare in your class before initialising log4j with that properties collection
I would go for the first option myself, too much automagic behaviour can get you in a very non-transparent situation quickly.
I wouldn't use it (I think it makes more sense to be careful when refactoring) but here it goes:
private static Logger logger = Logger.getLogger(new Exception().getStackTrace()[0].getClassName());

Categories