Im using Log4j and i have the following problem: is there a way to add one more logger from your code ? (not root logger).
In my config file, i set up the following two loggers :
log4j.rootCategory=INFO, ALogFile
log4j.logger.BLog=INFO,BLog
I would like to remove second line from config file and add BLog from code. Is that possible?
The equivalent code should be:
Logger logger = Logger.getLogger("BLog");
logger.setLevel(Level.INFO);
logger.addAppender(Logger.getRootLogger().getAppender("BLog")); // see notes below
I.e. you obtain a Logger object for the name BLog, you then set the level to INFO and attach the appender you've presumable defined elsewhere in your config file, called BLog.
Note: based on the answers from this related question, you may need to attach the appender to a logger in order to be able to reference it, as my code does above. Or just define the appender in your code.
Related
In Log4j 1.2, you could simply take a logger and add an appender at runtime. This was handy for test purposes for instance. We used to create a mock appender and add it to the logger. Subsequently we could make different assertions.
What is the equivalent thing with log4j2?
This example for instance shows how other people were adding test appenders.
The log4j2 page shows a few examples on how to add appenders. However, they add appenders to the overall context. Which seems different from adding appenders for one specific logger.
Another observation is that if you use org.apache.logging.log4j.core.Logger as opposed to org.apache.logging.log4j.Logger, you can still add appenders. However most people use org.apache.logging.log4j.Logger. And in fact, LogManager returns an instance of org.apache.logging.log4j.Logger. So, I am not sure how to connect these two classes and whether they should be connected at all.
Another observation is that if I call
LogManager.getContext().getConfiguration().getLoggers()
I can get a ist of all LoggerConfig objects in the context. I subsequently add appenders to any LoggerConfig object. The question however is, how do I get the LoggerConfig related to an instance of org.apache.logging.log4j.Logger?
This is confusing me.
org.apache.logging.log4j.Logger is an interface located in the log4j-api module. org.apache.logging.log4j.core.Logger is a concrete class (implementing the above interface) which lives in the log4j-core module.
LogManager (also in the log4j-api module) returns something that implements the org.apache.logging.log4j.Logger interface, and if the log4j-core module is in the classpath this will be an instance of org.apache.logging.log4j.core.Logger.
So you can cast the returned Logger to org.apache.logging.log4j.core.Logger and add the Appender.
Each core Logger has a LoggerConfig (1-to-1 relationship). You can find the LoggerConfig that corresponds to the desired Logger because they have the same name.
By the below post i can able to configure log4j to log in N different file.
Creating multiple log files of different content with log4j
log4j: Log output of a specific class to a specific appender
But i question is FOO.java should able to log in 2 different files. Normal debug/infos in general logger and some statistics in different logger.
I use slf4j and log4j.. I can able to change the logging framework if needed.
Normally, loggers are named after the class, but you don't have to do that. You can name the logger something totally different, or use the class name with some prefix or suffix, e.g. for class org.example.Foo:
org.example.Foo <-- Standard logger name
org.example.Foo.stats
stats.org.example.Foo
Foo.stats
stats.Foo
stats.Bar
Using a prefix will allow you to redirect statistics from all sources (classes) to a separate file, in one config entry.
You decide what is appropriate for you.
I want to write a testng test case to verify that the logs (log4j) generated are following exactly the given conversion pattern from the log4j.properties file. As an example if I have conversion pattern : [%d] %-5p [%t]: %m%n a sample log would looks like [2015-07-07 16:42:09,937] DEBUG [main]: Message 1 I want to make sure that the log follows the exact pattern.
So for now what I'm doing is first read all the logs in to a String array and loop that array to find whether the expected log without the date i.e. DEBUG [main]: Message 1 contains in the recorded.
Is this way of testing log records is correct ?
If you have any idea about a good way to test logs rather than this please point out.
There are any solutions. The first in my mind is:
Configure your log4j to write on System.out and use the SystemOutRule.
public void MyTest {
#Rule
public final SystemOutRule systemOutRule = new SystemOutRule().enableLog();
#Test
public void writesTextToSystemOut() {
System.out.print("hello world");
assertEquals("hello world", systemOutRule.getLog());
}
}
See: https://stefanbirkner.github.io/system-rules/index.html
This solution is logger implementation independent if the logger writes to System.out and/or System.err.
More log4J aware:
Use a mock framework - #slartidan says - and mock the appender implementation.
Based on your preferred mock framework and log4J 1.x or log4J 2.x the solution is quite different.
Log4J 1.2
Create a mock logger appender and add this appender on logger:
Logger.getLogger("...").addAppender( mockedAppender );
See: https://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/Category.html#addAppender%28org.apache.log4j.Appender%29
Log4J 2.x
Extending ConfigurationFactory and Configuration (only in test artefact) and add the mocked appender.
The easiest way to create a custom Configuration is to extend one of the standard Configuration classes (XMLConfiguration, JSONConfiguration) and then create a new ConfigurationFactory for the extended class. After the standard configuration completes the custom configuration can be added to it.
http://logging.apache.org/log4j/2.x/manual/customconfig.html (includes complete example)
I use a property file for java.util.logging and want to log all classes under package:
aaa.bbb.ccc.*
the normal way (i.e. info, fine, finer) but class
aaa.bbb.ccc.ddd.MyClass
in its own logging file "My Class.log" with level finer.
The config should be done only via a properties file. How would this look like?
I tried various ways (e.g. different handlers) but not any succeeded: It never worked that both log files are written to.
To make the problem more concrete - the config I tried:
handler.performance.class=com.logging.handler.FileHandler
handler.performance.file=${LOGGING_ROOT}/performance.log
handler.performance.level=FINE
handler.fine.class=com.logging.handler.FileHandler
handler.fine.file=${LOGGING_ROOT}/finer.log
handler.fine.level=FINE
handler.async.class=com.logging.handler.AsyncBufferHandler
handler.async.level=ALL
handler.async.targets=fine
handler.asyncperf.class=com.logging.handler.AsyncBufferHandler
handler.asyncperf.level=ALL
handler.asyncperf.targets=performance
com.myapp.handlers=async,console
com.myapp.useParentHandlers=false
com.myapp.common.logging.handlers=asyncperf
com.myapp.common.logging.useParentHandlers=false
The class I want to log to this separate performance log is located beneath com.myapp.common.logging...
Found the solution - it was a wrong initialization:
The logger should be initialized with:
Logger.getLogger(MyClass.class.getName())
Then the config:
com.myapp.common.logging.MyClass.handlers=asyncperf
com.myapp.common.logging.MyClass.useParentHandlers=false
logs all logging messages of this class in the specified separate file as desired!
Define two File appenders for the two target files
Define one root logger to use the first appender
Define a second logger for the special class, to use the other appender
set additivity of the logger to false in order to make any message go to one but not both files
I think that you have problem because you can't configure 2 default FileHandlers, only one of them. So try to implement your personal subclass of FileHandler and configure it as a separate handler.
I don't remember if we can configure logger for separate class or only for package, so try also configure handlers to package of MyClass.
I've written a log4j appender that will take a certain message type and dump it to a MongoDB cluster. Let's call it "Audit"
I want to be able to do something like this:
logger.debug (new AuditEntry (...));
from ANY class and have log4j automatically route any log messages of type "AuditEntry" to my Audit appender. Is this possible? The only way I've been able to do this so far is to add it the appender to the rootLogger chain:
log4j.rootLogger=DEBUG, Console, Audit
But then of course the AuditEntry also is toString()'d out to the Console -- I'd like to avoid this if possible.
I have thought of one solution but I'm not sure if it's the best solution. Make the Audit filter the first in the chain:
log4j.rootLogger=DEBUG, Audit, Console
and then inside my log4j appender call "clearFilterChain()" I haven't tried this yet... nor have I found any documentation on this function.
Any other solutions?