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
Related
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.
I want to do something which seems really straightforward: just pass a lot of logging commands (maybe all, but particularly WARN and ERROR levels) through a method in a simple utility class. I want to do this in particular so that during testing I can suppress the actual output to logging by mocking the method which does this call.
But I can't find out how, with ch.qos.logback.classic.Logger, to call a single method with the Level as a parameter ... obviously I could use a switch command based on this value, but in some logging frameworks there's a method or two which lets you pass the logging Level as a parameter. Seems a bit "primitive" not to provide this.
The method might look a bit like this:
Logger.log( Level level, String msg )
Later
Having now looked up the "XY problem" I understand the scepticism about this question. Dynamic logging is considered bad, at least in Java (possibly less so in Python)... now I know and understand that the preferred route is to configure the logging configuration appropriately for testing.
One minor point, though, if I may: although I haven't implemented this yet with this particular project, I generally find "just" tracing the stacktrace back to the beginning of the particular Thread insufficient, and this is what logback does (with Exceptions passed at WARN or ERROR levels). I plan to implement a system for recording "snapshots" of Threads when they run new Threads... which can then be listed (right back to the start of the app's first Thread) if an error occurs. This is, if you like, another justification for using something to "handle" outgoing log calls. I suppose that if I want to implement something like this I will instead have to try to extend some elements of logback in some way.
Which of the following is a better usage of logger?
Parametrize (log4j 2)
logger.info("User {} has logged in using id {}", map.get("Name"), user.getId());`
Using + operator (log4j)
logger.info("User"+ map.get("Name") +" has logged in using id " +user.getId());`
And why?
Even if there were nothing else, the additional StringBuilder shenanigans that happen when using + would make using parameters the obvious choice.
Not to mention that when concatenating the values, the toString() method of all the parameters will be called even if the logging level isn't enabled, meaning that you're wasting CPU to build a String that will never be logged.
This would have an (albeit minor) effect if there are lots of debug() statements, when DEBUG level is usually disabled in production environments.
Parameterized messages avoid formatting the text until Log4j is certain that the message will be logged. This allows you to avoid surrounding the logger.debug(...) call with checks like if (logger.isDebugEnabled())... which gives cleaner code.
This answer is based on modern logging frameworks, not outdated ones like Log4J.
When you say "outdated" you must be talking about Log4j 1.x. As of 2014, Log4j 2 is the cutting edge open source logging framework. It takes some ideas from SLF4J, like parameterized log messages, but adds a plugin system so you can easily add custom appenders, custom layouts and custom lookups. Furthermore Log4j 2 has support for custom log levels, lambda expressions and the lock-free and very performant Async Loggers. To spice things up, from release 2.6 Log4j 2 is garbage-free.
Kayaman is probably talking about Log4j 1, which has been End of Life since August 2015.
We are currently using CAL10N to localize log messages generated by SLF4J. To do this, we need to use the LocLogger class to define a logger for every class.
Few weeks into development, there comes a time where you have a few bug reports with logs attached - they do have nicely logged stack traces (thanks to SLF4J) for exceptions being thrown, but turns out we have a hard time figuring out the flow since since everyone's new to the code and the flow of things keeps changing every other day!
What we need is ENTRY/EXIT logs for every method. I was hoping that SLF4J will provide a way to do that in the least painful and fastest possible way: and ho behold! It certainly does!
The XLogger class provides methods that aid in such verbose logging (see this link), but after looking at the API docs, looks like both LocLogger and XLogger implement the Logger interface.
So the question is (we got to it finally!) - is it possible to use the LocLogger with all the localization benefits of CAL10N in peaceful harmony with XLogger, that provides all the verbose logging goodies?
No real answer for this yet - worked around it by leveraging a feature of the underlying implementation.
We're using log4j as the implementation under slf4j. The PatternLayout supports printing the package name+method name of the origination of the log message with these specifiers: %C.%M
So we simply log well-defined strings, +++ as the first line in every method and --- just before returning, to a logger for that class.
Solves the purpose, but not a solution to the original question.
Why is the Log4j rootLogger in my application not filtering log events according to level? In my log4j.properties, I have several loggers:
log4j.rootLogger=info,stdout
log4j.logger.com.name.myapp=debug,myapp
log4j.logger.org.castor=debug,castor
log4j.logger.org.exolab.castor=debug,castor
log4j.logger.org.hibernate=debug,hibernate
log4j.logger.org.springframework=debug,spring
Each of the loggers receive and record numerous log events at levels DEBUG and above, which is what I expect and desire. The rootLogger, however, despite being set to level INFO, is displaying all of these events, too, including the DEBUG events, which is not what I expect and not what I desire. Instead, I would expect it to filter the DEBUG events, but display only the events at level INFO and higher (WARN, ERROR, and FATAL), which is also what I want. Why is rootLogger displaying all of the events?
See this answer to a similar question about logger chaining in Log4j:
The way Log4j chaining works is a bit
counter intuitive (to me at least). If
the request level is equal to or above
the threshold of the most specific
matching logger, it is accepted. Once
the request is accepted, it gets
handled by the complete chain of
ancestors regardless of their
thresholds!
This means that no matter to what level you set the threshold of the root logger, it will always accept and output the log event that any other logger accepts, unless you disable chaining for that child logger or explicitly set the threshold of its appender to a higher level.
So, in this case, there are two ways that you can prevent root logger from capturing the events from the other loggers. The first is the more selective approach of disabling log event chaining:
log4j.additivity.com.name.myapp=false
log4j.additivity.org.castor=false
log4j.additivity.org.exolab.castor=false
log4j.additivity.org.hibernate=false
log4j.additivity.org.springframework=false
The second way is simpler, but more restrictive since it suppresses all events on the console that are lower than INFO (DEBUG and TRACE):
log4j.appender.stdout.Threshold=info
Check out the inheritance described in the intro. If you specify a level at the package level, it won't inherit the root logger's level. You're using debug in the packages you specify, not info. Specifying the level overrides whatever has been inherited.
If you want to inherit the root logger's level, get rid of the level specification in your logger configurations.
To retrieve the rootlogger, are you using Logger.getRootLogger()? If not, you may not be getting the real root logger. If so, make sure the Threshold of stdout isnt at debug; the Threshold of appenders override that of the logger Levels.