Say I have a class like this:
public class MyClass
{
private Logger log = LoggerFactory.getLogger(MyClass.class); //org.slf4j.LoggerFactory
public void foo(Params p)
{
log.info("Foo params: " + p);
long t1 = System.currentTimeMillis();
Result r = someMethod(p);
long t2 = System.currentTimeMillis();
log.info("Foo result: " + r)
log.info("Foo time taken: + (t2-t1)/1000);
}
}
Now when it comes to printing this info, I want to be able to turn on and off the different types of info (Parameters, Results, Time Taken).
The problem with using logging levels to differentiate, is that the finer levels of granularity also encompass the coarser levels.
How can I easily set this up?
It sounds like the most straight forward solution is to leverage distinct categories for what you're logging. Using this as an example
You would simply pass those names in as logger factory categories.
You set different logging behaviour by creating custom logging classes.
Here's my solution:
Setup in Log4j.properties
When using these loggers:
To use these logger:
Log output:
Note that LoggerOne isn't printing, because it is set to ERROR in the properties file.
To redirect these seperate log files, you need to set up new appenders and loggers.
I think what John Ament meant, is that the logger name (or category, as it is also sometimes called) can be freely chosen. The call
is mostly just a convenience for calling
There is no requirement from the logging framework that you name your loggers according to the full name of the class. This is just a convention supported by the first getLogger overload above.
So instead of having three different Logger implementations with the same name as in your example:
You can simple use the standard Logger implementation with 3 different names:
Since log4j loggers are hierarchical, you can control them together or indivially as needed. So if you wanted to enable all of them:
If you later need to turn results off:
In the same way you can send the output to different destinations if needed.
Using markers
All of the above was written using only the basic functionality available in any SLF4J implementation. If you are using Log4j 2 or are willing to switch to logback, you can instead use markers to achieve the same, but on a global level. Thus, instead of having multiple loggers in the class, you could have multiple markers, like so:
This will allow you to toggle logging of parameters, results and durations globally, by using Log4j 2.0 MarkerFilter or logback MarkerFilter.
Configuration in Log4j 2.0
Log4j 2.0 gives you a lot of flexibility in how to use MarkerFilter:
Configuration in logback
In logback the story is more complex, depending on what you wish to achieve. To turn off all logging of a given marker globally, simply use MarkerFilter. This is a TurboFilter, so it applies to the entire logging context. If you want to log different markers to separate sources, you could use SiftingAppender and write a marker-based discriminator by extending AbstractDiscriminator. Since logback does not support filters directly on loggers, if you need to configure output per-class per-marker, like turning off logging of results for MyClass but keeping it on for other classes, you should use class-specific markers instead of global ones.
Here is a sample implementation of a marker-based discriminator for use with SiftingAppender:
This implementation is heavily inspired by the standard ContextBasedDiscriminator. You would use MarkerBasedDiscriminator like this: