I have multiple applications using log4j for their logging, each loading settings from separate log4j.properties loaded from the classpath (just a file on disk, not in a .jar or anything that would make it read-only). In each of these applications, I want to allow updating the log level through the regular UI.
I use a common utility class for this, which is shared between applications. I can do that for the lifetime of the app, but since the changes aren't persisted back out to the appropriate log4j.properties file, on next restart, it's reset to the specific level in the properties file.
Since it's just loaded from the classpath, I don't know the full path to the logfile in each application, and since it's a common class, I'd rather not hardcode paths. Is there a way to get log4j to write back its changes to its on-disk configuration?
I suggest you flip the problem on its head.
Always write changes to the log4j.properties file on disk, and then install the listener that checks for changes in that file and updates the appropriate log levels.
Related
I have an existing application that logs messages using the java.util.logging API. As far as I can see, there are no configuration files for it in the framework, though there is some code to create a file appender. When I run the application, I get log messages to the console and to a file.
Now, I need to incorporate a library that uses Log4j 2. When I do so, I lose the console logging from the main application (though log messages still get written to the file appender that is created programmatically).
I imagine that, since the file appender is working in the original application, that I can solve my problem by also programmatically creating a console appender in the main application. However, I don't know if that's right or a kludge.
So, my question: is there anything general that I need to know about making java.util.logging and Log4j 2 interoperate? If the original application is not coded properly or according to best practices, I can change it.
Now, I need to incorporate a library that uses Log4j 2. When I do so, I lose the console logging from the main application (though log messages still get written to the file appender that is created programmatically).
The
Log4jBridgeHandler will remove handlers if the install method is called from code. You can always print the log tree to see what handlers are attached or attach a tool like JConsole to inspect the logger tree with and without the 3rd party lib.
I imagine that, since the file appender is working in the original application, that I can solve my problem by also programmatically creating a console appender in the main application. However, I don't know if that's right or a kludge.
Programmatic configuration of the logger tree should be done with the LogManager config option:
A property "config". This property is intended to allow arbitrary configuration code to be run. The property defines a whitespace or comma separated list of class names. A new instance will be created for each named class. The default constructor of each class may execute arbitrary code to update the logging configuration, such as setting logger levels, adding handlers, adding filters, etc.
Create a stand alone named class that just installs the handlers in the constructor.
Set the java.util.logging.config.class system parameter to the name of your class.
Otherwise if you have a logging.properties you set config to your class name.
So, my question: is there anything general that I need to know about making java.util.logging and Log4j 2 interoperate? If the original application is not coded properly or according to best practices, I can change it.
The java.util.logging.LogManager can only see classes on the system class loader. In that case log configuration in code is required to gain access to the correct classloader.
It might be easier to remove all JUL configuration and bridge to Log4j2. You can then leverage the configuration needed through that framework.
I have an existing web application which uses log4j for logging purposes and it will create a log file in my local system. Now, I have to migrate that web application to AWS platform. In order to move it to AWS, what changes need to done in terms of logging? How should be the log4j.properties file? Is there any need to change the application code?
No changes are required to your application; log4j will still work.
You do not want to fill up the file system with logs, but you also want to keep an appropriate amount of logging in case you have an issue you need to debug.
Log4j will handle its own log rotation. You will want to make sure your log4j.properties file is set up to keep logs for a certain length of time.
Make sure your logging directory exists on the new server and/or create it with the correct permissions. Or change the log4j.properties file.
log4j.appender.R.File=/some/dir/logs/your_app.log
I am rather confused by how to configure Log4j I have picked up following snippets, but something written that pulls these concepts together would be useful.
Log4j looks for properties/xml files in the CLASSPATH
You can supply
your own file using PropertyConfigurator.configure(filename) - what
if you call this twice. Are the files effectively merged or is only
the last one used.
You can supply an explicit file using -D on the
command line
I want to be able to
Supply a basic config file that remains static
Allow an individual developer to add an additional file with extra options without having ot exit this main file.
According to this documentation
The existing configuration is not cleared nor reset.
log4j itself stops at the first log4j.properties it find.
So when you call configure, my guess is:
if some configuration is already done then the current will be merged.
if configuration has not been done then log4j will not attempt to read any other log4j.properties
Your best best is to probably call configure with global and then with developer-specific file. But this should be easy to test.
We are having a debate at my office around what can and cannot go in a JAR file. It has been suggested that it is poor form to have anything that is not a .class file go into a JAR. We currently have some XML configurations for Ibatis/etc, some property files.. the usual. However, there is a push to extract all such files from JARs and put them onto the local file system of each deployment machine. Does this sound reasonable?
it is poor form to have anything that
is not a .class file go into a JAR
That is nonsense. It is in fact very good form to put resources like icons and other data files that user used by the code into the JAR together with the code. This is what the getResource() and getResourceAsStream() methods of Class and ClassLoader are for, and it makes for much more robust applications than messing around with resource paths manually.
However, config files are possibly a different matter. If they're meant to be changed during or after deployment, then having them inside a JAR file is rather inconvenient, and having them in a separate directory is preferable.
If you make changes in a configuration file inside a JAR (even without altering any line of Java code), the whole JAR needs to be rebuilt and redeployed. Does this sound reasonable?
It's absolutely OK to put non-class files in a JAR file, especially resources that the application needs (images, localized strings, etc.) Knowing this, you must decide which scenario fits your situation:
If the configuration is fixed and will only change when a new JAR file is deployed, put it in the JAR.
If the configuration must be altered, either manually or by the application, store it on the filesystem.
If you choose the latter, note that it's good practice to include a default configuration in the JAR file to handle the case when the external configuration file is missing. The default can be loaded directly from the JAR or copied to the filesystem to become the new editable configuration.
It does not sound reasonable to me. I believe, that some application's configuration should be in jar file. Such things as ORM mappings, spring config, custom spring namespace XSD, other XSDs, etc.. should be in most cases in jar. It's important part of deployment artifact.
The fact, that it's not class file, does not mean, that it should be taken out of jar just because it's theoretically can be modified without building a new jar. Can you imagine a modification of *.hbm.xml in production? for me it sounds very scary.
I think some configuration, like spring xml, is meant in most cases to better organize your application and dependencies, but not to change them at runtime in production.
Do you want or expect them to be changed without a new release of the code? Then you need to extract them.
If the answer to the question in no than you shouldn't extract them, as it would allow support to tinker around with them without going through the release process. (Of course this is also possible if they are in the JAR but slightly less tempting.)
Update: But since you mentioned multiple deployment machines, there's a third option: extract them and place them in a commonly accessible area on a network drive. Manually editable config files which are replicated on several machines (but should be identical) are notorious for getting out of sync.
ORM tools (such as Hibernate or IBatis) are not really supposed to be modified once the application is deployed. So, no, I would say that it doesn't make sense for that kind of files.
Depending on your requirements, application-wide configuration files can be placed outside the Jar/War so that they can be modified without having to rebuild the jar.
Do keep in mind that modifying application parameters in production is, imho, a bad practice. Changes should be tested first in some pre-production environment.
I have a web application that reads content from a property file. When will this property file be loaded into memory. ie. Once I deploy the application with some content in the prop file, and after deployment , I change the contents of the prop file, will the changes be reflected or do I have to redeploy?
EDIT : An accessor class' static block reads content from the property file, which is a part of a deployed web application. Now after deployment, i change the property file contents. Will the accessor class read the changes or will it take up the old values?
EDIT2 : when the class is reloaded, will it surely take up the new modified file or rather take up the file cached during deployment(if at all it is cached)
Assuming that the property file is being loaded by the Properties class, then the property file will be loaded once when the Properties#load() method is called. It will not automatically be reloaded unless your application specifically supports reloading or if your web container restarts the web application during hot deployment.
update: Since the property file is loaded in a static initializer, then the property file will be reloaded when the class is reloaded (e.g. when the web app is hot deployed). If you want to debug this, a simple println() in the static initializer will show you when this happens.
It depends on the app server - generally, you'd have to redeploy. But some app servers, in certain configurations may monitor files and kick off a redeploy when they detect file changes. (as an example - I believe Tomcat will automatically redeploy when it detects file changes in exploded deployments.)
If this file is loaded by your class than I am pretty sure it won't reload it by it self.
If I were you I would have a separate thread that in given time intervals wakes up, checks whether the file modification date has changed and if it did than reloads it.
Apache Commons Configuration provides automatic reloading/saving of file-based configurations.