log4j property configuration question - java

I have to stop showing logging messages of some methods within the system without changing a Java code (loggers)...
I was thinking, is it possible to configure log4j.properties, where I could skip the logging for certain method? and is it possible to do log on method level at all with log4j?
Thanks,
K.

log4j does not support this level of configuration. But you can implement an appender that will extends your current appender (for example, create a MyConsoleAppender that extends ConsoleAppender). Then, add a check for the method that you which to skip in the checkEntryConditions() method.

Related

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

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.

How to modify a message in Log4J 2?

I'm trying to MODIFY, not DENY, certain messages before being logged using Log4J 2. I'm currently trying to use a Filter, but I can't seem to be able to modify a message from any of it's methods.
Please be patient with me as I'm totally new to Log4j.
Log4j purposely does not let you modify the LogEvent as it might get passed on to other Filters and Appenders that expected the original event. However, the RewriteAppender will let you create a copy of the LogEvent that is modified and then pass that to a subordinate Appender. The RoutingAppender also supports a RewritePolicy that does the same thing.

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.

Log to a different file according to thread

I have an application with multiple "controllers", and I'd like to have each log to their own file. This is easy enough for their own code, but I'm also using some library code which uses commons logging. Could I somehow get that code to log to the controller-specific file as well?
I was thinking I could somehow do it by thread:
class Controller {
public void action() {
setCurrentThreadLogFile(myLogFile);
try {
Library.stuff();
} finally {
restoreCurrentThreadLogFile();
}
}
}
Currently I'm using commons-logging for my own logging as well, with log4j as backend. But I could change that, if needed, or use a mix (is that's possible within the commons logging framework).
One way I could do this would be to write my own commons logging implementation (possibly a wrapper around log4j), but is there an existing solution?
You probably want to be looking at mapped diagnostic contexts (MDCs). Commons logging does not support these but Log4J does, so you would have to go directly to Log4J to set this up. You will probably have to roll your own filter to filter using the MDC and apply to the appenders.
If you willing to change logging implementations then you could use SL4J as the logging facade and Logback as the logging implementation. Have the controller or some sort of filter/interceptor add a discriminator value for a key you are going to use to discriminate the controllers with to the MDC. Use a SiftingAppender to separate the log event into separate files.
A logger per thread? Put the logger in a ThreadLocal. If you are using java.util.logging, a Handler could make this transparent to the caller.

Categories