How to create log4j2 appender from java code? - java

I need to create separate logs for different object instances in my applications. For example if we work with books, i need separate log file for every book. It works fine with log4j2.xml file, but i may have hundreds of such objects in memory and i don't want to create such a long configuration file. I want to create appenders and loggers from code. I looked for working code example and found nothing.
I tried to use RollingFileAppender.createAppender but didn't found how to attach it to logger and failed to get proper values for this function parameters.
Please help with working code\configuration how to create separate log files per object property.
Probably it can be done with wildcards in appender\logger names in log4j2.xml or using renderer?

If splitting log file base on "book" is what you are looking for, instead of creating a very specific appender or configure log4j programmatically to deal with that, you should have a look at MDC.
With proper MDC setup, it should be straight-forward to split log files base on MDC content (e.g. in LogBack, there is a SiftingAppender. I believe there is similar 3rd-party appenders that do the same thing)

You could use the static method #initialize(String contextName, ClassLoader loader, String configLocation) (see source here) in org.apache.logging.log4j.core.config.Configurator.
(You can pass null for the class loader.)
Be aware that this class is not part of the public API so your code may break with any minor release.

Related

Can Log4j2 be configured with .xml and .properties at the same time?

As above, can log4j2 be configured at the same time with .xml and .properties?
And if it can, what takes priority, when changing shared configuration?
This is the direct answer
Firstly: Why would you want to have multiple configuration files? Seems to me like you should try to collate all of your configuration into one file if at all possible.
The documentation for Log4J2 says that the automatic configuration will search first for the System property "log4j.configurationFile", which points to one configuration file on the file system, which is loaded based on the type of file.
If that isn’t found, it will search for:
.properties
.yml
.json
.xml
In that order.
This to me means that you can only use one.
This provides another approach
You can, however programmatically configure the logger, which can combine a configuration file with a different set of configurations.
If you wanted to combine the Configurator method with XML configuration, for example, then apparently you have to use the ConfigurationFactory, which is something I have never done before, though if you understand the layout of the Log4J2 it doesn't look too difficult - basically extending ConfigurationFactory, overriding methods to configure things, then giving the Configurator the factory.
Additional links:
Here is the programmatic configuration documentation
Here is a helpful Baeldung articl for programmatic configuration

How to override a specific value of log4j.properties?

I'm using a jar that has log4j.properties included. One property of this jar maps to a static local resource with a path that does of course not exist on my system.
Problem: my custom log4j.properties is somehow not taken into account, even thought it is on the classpath.
What do I have to change so that the existing log4j from the jar remains valid, but only a specific value is overridden with my custom log4j?
log4j.appender.InfoFileAppender.File=d:/logs/info.log
To start with, Log4j should create the new file for you in most of the conditions. And if it cannot, read below.
By default, Log4j will load the first found "log4j.properties" in your class-path.
So in your case,
a) if you want to load a custom log4j property file of the name "log4j.properties" with changes, make sure that it appears first in your class-path order.
b) You can load multiple custom log4j settings from different files using the PropertyConfigurator provided by Log4j. Even if you do this, i don't think you can override a particular property of an appender, because log4j wont load an appender again if it is already loaded.
c) The best approach would be to reassign a new file to the appender programmatically during the start up of your application.So you should have a piece of code which execute during startup which uses the Logger API's to gets the appender of the required logger and reset it.
Ok, in general,i say your use case is to validate the file existence before an appender is created,
you can add that validation check using a custom Configurator.
Log4j will use PropertyConfigurator to load your log4j.properties. You can define your own Configurator implementation which extends from Propertyconfigurator and write the code to make sure that appender file location is a valid one, and if not valid set it to a different one.
Make sure that you set the system property log4j.configuratorClass to tell Log4j that your Configurator should be loaded. Here i think you just need to override the parseAppender method from PropertyConfigurator.
Old topic, but maybe useful for others who stumble upon it. I managed to overwrite a certain property this way:
http://aadityatiwari.com/2013/08/override-log4j-properties-at-runtime/
Of course, this won't help in your scenario, because you need to read the log4j.properties in memory first to override it.

Migration from log4j 1.x to log4j2

Hi I came across some code which is using log4j. I want to move to log4j2.
From http://logging.apache.org/log4j/2.x/manual/migration.html I came to that log4j-1.2-api.jar can be used. I have following question :
In code I have a custom appender (as given in that link I should not use internals of class Appender) is that mean I can't use log4j-1.2-api.jar ?
I also want to use asyn logging feature of log4j2 . How do I do that using log4j-1.2-api.jar.
Your custom appender may no longer work. Log4j2 has a lot of functionality, and depending on what your custom appender did, it could be that this functionality already exists in log4j2. You can ask on one of the mailing lists and if it is a function that could be useful for many users it may be added to log4j2.
To use the async loggers, you can either make all loggers async with a system property (http://logging.apache.org/log4j/2.x/manual/async.html#AllAsync) or mix synchronous and async loggers with configuration (http://logging.apache.org/log4j/2.x/manual/async.html#MixedSync-Async). Both should work when you drop in the log4j-1.2-api jar (in addition to the log4j-api and log4j-core jars, these two jars are always needed).
There is a migration guide. I used it successfully.
http://logging.apache.org/log4j/2.x/manual/migration.html
In log4j2 everything is cofigured using a XML file (or more XML files, e. g. for your test directory). The file should be named log4j2.xml.

Combining Application and Server Level logging with Log4J?

Is it possible to work with two different levels of logging simultaneously with Log4J/Tomcat? Here is my situation: I have a few webapps operating on the same Tomcat Server. Some of these applications have their own log4j properties file (legacy).
Something I want to add is a new logger with a JDBCAppender that will work across all of these applications (They're meant to be used together so having them log to the db we've selected would be VERY useful for us.) I've written the properties file entries in order to do this the way I want (and tested in one of those local property files for syntax purposes).
Is it possible to drop this new logger/JDCBAppender in a server-level log4j.properties file, and then have the webapps gain access to it? For instance, if I define the logger as 'com.xxx.yyy', then in any webapp that has a class in a 'com.xxx.yyy' package grab said logger with a call like:
private static Logger logger = Logger.getLogger(MyClass.class);
assuming the full declaration is com.xxx.yyy.MyClass.
I've tried dropping the log4j.properties file in the $CATALINA_HOME/lib directory as well as placing the necessary jar files in the same directory (as directed in the comments below) but when I launch my server, it doesn't seem to pick that one up, although it picks up the one from my webapp. I know the properties file has to be on the classpath for log4j to pick it up, but can there be some sort of similar-class path style issue if there is more than one log4j.properties file?
Update: I've updated the description of what I've tried.
I've done some additional research and learned that if multiple log4j.properties files are on the classpath, the system will use the first it finds, just like with java class/library files.
So in the end, the situation I was describing is not feasible, as adding a Server-level properties file would cause all my individual web-apps' legacy property files to be ignored. It may still be possible to do something similar, but my question was intended to focus specifically on the log4j.properties file.

How to include static information in logging with Log4j or similar?

We have an application where a log message without the context in which it was run (i.e. the database) does nearly never make sense. The information is always available, but it is quite cumbersome to include it everywhere by hand. Is there a more elegant way of doing it?
I was thinking along the lines of implementing a wrapper around logging that always includes the information. I have tried it, but I'd like the LogFactory (either slf4j or Log4j) to pick this class by default, and I don't know how to do that...
Any suggestions?
You could take a look at the NDC or MDC classes. You can push context information on the stack and include this automatically in your log messages.
You can find a small example here.
In your PatternLayout, use '%x' to log NDC information and '%X' for MDC.
For log4j, create a class extending from PatternLayout to create your own layout.

Categories