Combining Application and Server Level logging with Log4J? - java

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.

Related

Getting the Log4j settings from a custom properties file

I am working on a huge application which uses its on property file to set the global variables. I want to use the same one for setting the properties of Log4j log file instead of log4j.properties file due to some problems. How do I do this? Is there any way to set the properties of Log4j at run time?
If you just want to rename your log4j.properties file you can do this using a System Variable in your JVM startup (refer link)
-Dlog4j.configuration=test.properties
The Log4j API also allows configuration changes to the Loggers from within an application. Theoretically you could read your own property file and call the appropriate API calls. I'm not sure this approach is recommended - you might end up spending a lot of time getting it working that you could better use developing your application functionality.
Note: I dont know the nature of the huge application, but it if its running in an application server such as JBoss they often have their own dynamic logging 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.

How to create log4j2 appender from java code?

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.

Strategies for logging to application logs from library code?

Where I work we use Log4j for web application logging. The log4j.jar is at the application level, not the container level. We're using a daily rolling file appender. Our log4j.properties files define appenders based on the app package name, so only classes in our application's package and below get logged to our app's log file.
In my application, I'm extending our framework with some supporting classes. These classes are not in the application's package, as they are not exclusive to my application and will eventually be made into a jar library for use with other applications. Because of this, my logging statements are not picked up by my application's appender, and are thus not logged to my application's log files.
I want to allow the classes in my jar to log to the log file of the application using the classes. However, if I create an appender in my application's log4j properties file based on my classnames, I suspect that when multiple applications are using my jar, because of the identical class names in the log4j.properties files, only one application log file will receive my jar's logging statements, and that it will receive ALL the logging statements from EVERY application using that jar. I think this is the case, since we're using a static Logger.getLogger() call to retrieve the logger.
I first want to know if my fears are valid, if this is really what would happen when multiple web applications in the same or different containers are using my jar simultaneously.
I'd also like to know if there are "boundaries" on which this behavior changes. For example, does this problem exist regardless of whether log4j.jar is a container-level jar or an app-level jar, or if each container is running in a separate JVM?
Lastly, if this IS the case, I'd like to know what strategies I should use to overcome the problem.
Thanks in advance!
If log4j.jar is only in the web-app then the logs will stay separate so each web-app should have its own log4j.jar and log4j.properties so that all logs stay separate.
The problem is that the preffered pattern for log4j is to use static *Configurator methods, which don't go very well with application containers.
This article solved this problem for me when i came across it ...

What is the best way to deal with environment specific configuration in java?

I have an application running in tomcat that has a bunch of configuration files that are different for each environment it runs in (dev, testing, and production). But not every line in a config file will be different between environments so there's invariably duplicated information that doesn't get updated if something changes.
Is there a good framework/library that collapses the separate files into one with environment specific blocks? Or some other way of dealing with this?
Assign reasonable default values for all properties in the properties files distributed within your .war file.
Assign environment-specific values for the appropriate properties in webapp context (e.g. conf/server.xml or conf/Catalina/localhost/yourapp.xml)
Have your application check the context first (for the environment-specific values), and fall back on the default values in the app's properties values if no override is found.
A Properties file is what I've always used. It's editable by hand as well as in in your software and the Properties object can read itself in and write itself out to the filesystem. Here's the javadoc page:
http://java.sun.com/j2se/1.4.2/docs/api/java/util/Properties.html
If you use maven, you can use it's resource filtering abilities, along with profiles to generate a properties file for each environment you're deploying into.
As an added bonus, maven can also deploy your web app for you.
The duplication is not really a problem, having a central config file the the other files 'extend' is likely to casue more of a headache in the long term.
My advice is to use ant to load (copy and move) the appropriate file(s) into place and then launch the app (bundle into war?). Just have a different task for each environment. So you will have three config files (dev.config, test.config and production.config) which will be moved and overwrite the config in the /WEB-INF folder depending on the task that you are running.
I would suggest to have a separate config file for environment parameters alone if you want to avoid cluttering. Then you will have one more config file to manage. This is a trade off between number of config files vs complexity of each config file.

Categories