Multiple log4j xml files for multiple applications - java

I have 5 applications which have different log4j xml configuration file. And I want each of them to be configured according to the given file and logs correctly when called from one main method.

Log4j will automatically look for and use config files it finds on the classpath. It looks for files called log4j.properties and log4j.xml and possibly others.
Alternatively you can programatically load config using;
String filename = "/path/to/config/file.xml";
DOMConfigurator.configure(filename);

Related

Are there other ways to provide `-D` java configs?

I have a usecase to provide a logging.properties file to change the log levels. In logging frameworks like, slf4j-simple, we can directly provide the properties file in resources and it will pick it up. But when using slf4j-jdk14 we need to provide the properties file path as a run config.
java -Djava.util.logging.config.file=logging.properties -jar test.jar
I need a way to provide this -Djava.util.logging.config.file=logging.properties config to the jar in another way.
There is also an option as follows,
static {
System.setProperty("java.util.logging.config.file",
"logging.properties");
}
But I want to know, if there is a way to provide this config to jar in any other ways. Maybe specifying this config in another config file which would be automatically picked up.

How to know if logback configuration file has loaded?

I am new to SLF4j and I don't know if the logback.xml file has loaded properly or not. The logback.xml file is in PROJECTNAME/src/main/java where all my packages are found.
My questions are:
How can I know if the configuration file has properly loaded or not
?
How can restrict the logging only from an explicit set of class,
only to avoid logging from libraries
You can add the debug="true" attribute to the <configuration> element to enable debug of the logback configuration. It will print the configuration to the console. See https://logback.qos.ch/manual/configuration.html#dumpingStatusData.
Simple answer, if the configuration file is loaded properly, you will see results in log file or console, depending on your configuration.
By default, logback searches file in src/main/resources instead of src/main/java if I remember correctly.
In the configuration file, you can define log lever on a specific logger. Normally you'll still want to see logs of the libraries, but maybe only WARN or ERROR, so you could set the root level to WARN/ERROR, and add a logger of your root package with DEBUG/INFO level.
Also, use a logback-test file (under src/test/resources) for your own dev environment.

Using a default log4j2 configuration file from inside the jar

I placed a default log4j2 config file (log4j2.xml) in my application jar.
If the user doesn't define a own config file, I want to load my default config.
I could get a stream of the default config this way:
InputStream defaultConfigStream = MyApp.class.getClassLoader().getResourceAsStream("log4j2.xml");
But that won't help me, because following code takes a full path to the config file to check its existance and to load it.
System.setProperty("log4j.configurationFile", file.toUri().toURL().toString());
How can I accomplish that? I don't want to hardcode my default config settings, like here.
Use a DomConfigurator, see: https://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/DOMConfigurator.html, you can parse the XML and feed it to the configurator and when initializing logger it will automatically consider the configuration
As I found out, it's pretty simple. Like described in the documentation (point 7), Log4j2 will automatically look for a log4j2.xml on the classpath.
So if the user doesn't define a own config file, I don't call any method to load my default config.

log4j logger overwriting into jxl.log file

I am using log4j for logger purpose. At the same time I am also using JXL to read/write Excel file.
But instead of writing log into log4j logger file, it is writing into jxl.log file.
What can be issue?
Looks like you have been using jxl-2.6.3.jar or similar version.
Log4j picks up the first configuration file with default file name ( i.e. log4j.xml or log4j.properties ) in your classpath if you haven't specified a specific name via JVM parameters. As jxl-2.6.3.jar contains a log4j.xml you ended up printing everything to jxl.log as defined in the log4j.xml
The best way to deal with these kind of problems is to run your application with -Dlog4j.debug JVM parameter. This would print a few line snippet when the log4j is initialized.
log4j: Using URL [jar:file:/C:/YourApp/WEB-INF/lib/jxl-2.6.3.jar!/log4j.xml] for automatic log4j configuration.
log4j: Preferred configurator class: org.apache.log4j.xml.DOMConfigurator
...{Blah Blah Blah}
There are many ways in which you can solve this problem.
Use the newer versions of jxl which doesn't contain log4j.xml.
Make sure your log4j.properties file is on top of classpath.
Remove the log4j.xml from the jxl-2.6.3.jar (Dirty solution).
Pass the configuration file name in VM parameter as -Dlog4j.configuration=log4j.properties. This would atleast make sure log4j.xml inside jxl-2.6.3.jar will not be used. (But what if another jar with same name as log4j.properties?).
Rename your log4j.properties file to log4j-yourApp.properties and add VM parameter -Dlog4j.configuration=log4j-yourApp.properties This would definitely help and this is how it should be done to avoid these kind of situations.
More details on Log4j here

referring to log4j configuration file from a log4j configuration file on class path

I have a common jar that multiple web applications are using. All the web applications are using log4j. Each has their own log4j xml configuration file that are basically the same. I would like to put a common log4j configuration in the included jar file and in each individual web project, in that log4j configuration, I would like to be able to simply refer to the one in the jar file.
I'm not seeing anything in the documentation that explicitly says this is possible. I'm wondering if I might just remove the configuration file from the web projects and stick it in the common jar if it would get loaded automatically since it is on the class path?
In the end, I would like the ability to adjust logging on a particular application for debugging and troubleshooting without modifying the common configuration in the jar file.
I was on a project where I needed to manage dozens of web applications. Each of the apps were logging slightly differently and it was a pretty big pain to manage. I used a strategy similar to what you are describing to standardize on log4j and it has worked out pretty well.
Basically, I created a single common.jar which contains shared code. This jar contains a log4j.xml that sets log level to INFO and sets the default appender to stdout for common.jar. This log4j config is used as the baseline for all other apps.
For this example, pretend this class is inside common.jar:
public class ThirdPartyLib
{
protected static final Logger log = LogManager.getLogger("third-party-lib");
public void doSomething()
{
log.debug("Third Party App is about to Do something!");
log.info("Third Party App just did something");
}
}
Now, all other web applications can simply depend on common.jar. For example, pretend this class is inside myapp.war:
public class MyApp
{
public void CallThirdParty()
{
ThirdPartyLib lib = new ThirdPartyLib();
lib.doSomething();
}
}
Since log4j.xml is inside common.jar, this code will log something like this. In other words, there's no need to put log4j.xml inside myapp.war:
2011-01-03 15:49:22,451 [main] INFO third-party-lib - Third Party App just did something
Now, if you want/need to control logging in myapp.war, then simply place a log4j.xml inside myapp.war and override settings from common.jar. For example, you might set the level to DEBUG, and then you'll see:
2011-01-03 16:03:22,928 [main] DEBUG third-party-lib - Third Party App is about to Do something!
2011-01-03 16:03:22,928 [main] INFO third-party-lib - Third Party App just did something
UPDATE - Is it possible to configure each webapp to log to separate file?
Yes, definitely. For example, you can direct logs to a RollingFileAppender instead of stdout inside log4j.xml for myapp.war. This is handy because then you can have each individual webapp log to it's own separate file.
In addition, I wrote a servlet filter (similar to what gigadot suggested) which configures log4j to check for whether a log4j.xml exists at an external path (outside of each webapp's war). This way, the log4j.xml files are accessible outside the wars and we're able to set log levels without restarting the servlet container (tomcat, in this case). If the external log4j.xml doesn't exist, it defaults to use the log4j.xml on each apps classpath.
If you have multiple jar/war files, each file have its own log4j.xml and you don't want to worry about which log4j.xml get loaded, you can explicitly load the configuration yourself.
For a webapp project, put the following context listener as the first listener in your web.xml This will load log4j from your path of preferrence.
<listener>
<listener-class>mycompany.server.listener.Log4JInitServletContextListener</listener-class>
</listener>
Implementation of Log4JInitServletContextListener.
Note: if you have multiple log4j.xml in the same path (which is possible for multiple jar files), it will be confusing which one gets loaded. So try to have a unique package name for the configuration resource in your common jar.
As you can see, you can use this method to programatically load log4j.xml depending on condition too.
package mycompany.server.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.log4j.xml.DOMConfigurator;
public class Log4JInitServletContextListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent sce) {
org.w3c.dom.Element log4jConfigElement = parseFromInputStream(getClass().getResourceAsStream("/unique/package/name/in/common/jar/log4j.xml"););
DOMConfigurator.configure(log4jConfigElement);
}
// omit the rest and implementation of parseFromInputStream method
}
i am not sure that can help but you can set property file location like this,
java -Dlog4j.configuration=jar:file:/full/path/to/app.jar!/log4j.properties -jar app.jar

Categories

Resources