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.
Related
I am novice in log4j framework. I was going through tutorial they all say that "Loggers are stored in a namespace hierarchy " ?
Is it some this related to object instantiation of loggers?
And what logger.getLogger(App.class) actually does? does it create a separate instance of logger for App.class?
The Logger object is main object to log any message. Logger objects encapsulate logging messages and do not have any information about destination or formatting.
The Logger objects acting within a particular instance of app follow a PARENT-CHILD hierarchy.
At the top of the hierarchy a root logger exist. This root logger exists outside the scope of custom logger hierarchy. All the other application-specific Logger objects are child objects to the root logger. This parent-child relationship of logger signifies the dependency of loggers acting within the same application. A child Logger can inherit properties from its parent loggers.
If you create 4 loggers "com.foo.apple", "com.foo.juice", "com.bar.tomato", "com.bar.potato" you will have hierarchy like:
com
.foo
.apple
.juice
.bar
.tomato
.potato
It comes to play when you configuring your loggers. For example LogLevel -
you could set DEBUG for "com" node, set WARN for "com.foo", and set ERROR for "com.foo.juice". Logger "com.foo.apple" would be at WARN level, loggers "com.bar", "com.bar.tomato", "com.bar.potato" would be at DEBUG level in this case.
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.
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.
How can i get all loggers used used in log4j2? In log4j i could use getCurrentLoggers like described here: Number of loggers used
get all loggers used in log4j2:
LoggerContext logContext = (LoggerContext) LogManager
.getContext(false);
Map<String, LoggerConfig> map = logContext.getConfiguration()
.getLoggers();
Attention:
use org.apache.logging.log4j.core.LoggerContext
not org.apache.logging.log4j.spi.LoggerContext
looks like i've found the way:
File configFile = new File("c:\\my_path\\log4j2.xml");
LoggerContext loggerContext = Configurator.initialize("my_config", null, configFile.toURI());
Configuration configuration = loggerContext.getConfiguration();
Collection<LoggerConfig> loggerConfigs = configuration.getLoggers().values();
YuriR's answer is incomplete in that it does not point that LoggerConfig objects are returned, not Logger. This is the fundamental difference between Log4j1 and Log4j2 - Loggers cannot be dirrectly manipulated in Log4j2. See Log4j2 Architecture for details.
If you are running in a web app, you may have multiple LoggerContexts.
Please take a look at how LoggerConfigs are exposed via JMX in the org.apache.logging.log4j.core.jmx.Server class.
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
Collection<? extends Logger> loggers = ctx.getLoggers();
It's important to note that LoggerConfig objects are being returned by getLoggers() and NOT the loggers themselves. As vacant78 pointed out, this is only good for setting the configuration for loggers that have yet to be instantiated. If you already have a bunch of loggers already instantiated, changing the configuration using this method does no good.
For example, to change the level of logging at runtime, refer to this link, which utilizes an undocumented API within Apache (no surprise there) that will change all your currently instantiated logger levels: Programmatically change log level in Log4j2
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.