Some Log4j Configurators have a configureAndWatch()
method, that starts a Thread to watch the file used for configuration (XML
file or properties
file) and trigger a reconfigure if the file changes.
However, if you rely on the Log4j
default initialization procedure, you never get a chance to call configureAndWatch()
. You don't even know the file that was used to configure with (it might not even be a file.)
Is there a good way to get configureAndWatch()
style behavior, allowing changing of the log configuration on the fly, while still using the default initialization procedure? I am assuming that your configuration URL ultimately resolves to a file that can be watched, as a URL on another server would probably not be something you would want to pull every 60 seconds.
(I see that the configureAndWatch()
method is not safe in a Java EE environment because of the separate thread, and I see that some app servers have their own mechanism for watching the log4j
configuration file, but the program I am working on at the moment is not running in Java EE .)
I've scrapped everything in the answer before and started over now that I better understand what you want.
The following paragraph describes the real sequence that log4j uses to determine what the log4j config file name is. This code tries to follow those rules.
http://logging.apache.org/log4j/1.2/manual.html#defaultInit
It determines what log4j configuration file to use and then sets up the PropertyConfigurator using the file it found. This will only work if the file is located on the file system. It will not work if the file is inside a jar or at a remote HTTP URL.
String prop = System.getProperty("log4j.configuration");
if (prop == null) prop = "log4j.properties";
URL log4jConfig = Loader.getResource(prop);
if (log4jConfig.getProtocol().equalsIgnoreCase("file")) {
PropertyConfigurator.configureAndWatch(log4jConfig.getFile().substring(1), 10000);
}
else {
// cannot monitor if file changed because URL is not a file
}
However, if you rely on the Log4j default initialization procedure, you never get a chance to call configureAndWatch(). You don't even know the file that was used to configure with (it might not even be a file.)
You have posted some related questions which I have already answered in [1] and [2], so this answer is building upon the explanations of the others. Again, I am using AspectJ:
Sample application class:
import org.apache.log4j.Logger;
public class Log4jDemo {
private static Logger logger = Logger.getLogger("scrum-master.de");
public static void main(String[] args) throws InterruptedException {
while (true) {
logger.info("Log message");
Thread.sleep(2000);
}
}
}
Aspect capturing the default URL and handing it over to configureAndWatch
:
import java.io.File;
import java.net.URISyntaxException;
import java.net.URL;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.LogManager;
import org.apache.log4j.PropertyConfigurator;
import org.aspectj.lang.SoftException;
public aspect Log4jAspect {
after(URL defaultURL) returning :
within(LogManager) &&
cflow(staticinitialization(LogManager)) &&
call(* OptionConverter.selectAndConfigure(URL, ..)) &&
args(defaultURL, ..)
{
try {
PropertyConfigurator.configureAndWatch(new File(defaultURL.toURI()).getAbsolutePath(), 2000);
} catch (URISyntaxException e) {
throw new SoftException(e);
}
}
}
I tested it with -Dlog4j.configDebug=true
from Eclipse, changing the output channel back and forth from System.log
(black colour in Eclipse console) to System.err
(red colour, here not visible) in log4j.properties, and it worked nicely. In the log output you also see the debug info for reconfiguration after a detected file change:
log4j: Trying to find [log4j.xml] using context classloader sun.misc.Launcher$AppClassLoader@f4a24a.
log4j: Trying to find [log4j.xml] using sun.misc.Launcher$AppClassLoader@f4a24a class loader.
log4j: Trying to find [log4j.xml] using ClassLoader.getSystemResource().
log4j: Trying to find [log4j.properties] using context classloader sun.misc.Launcher$AppClassLoader@f4a24a.
log4j: Using URL [file:/C:/Dokumente%20und%20Einstellungen/Robin/Eigene%20Dateien/java-src/dummy2/bin/log4j.properties] for automatic log4j configuration.
log4j: Reading configuration from URL file:/C:/Dokumente%20und%20Einstellungen/Robin/Eigene%20Dateien/java-src/dummy2/bin/log4j.properties
log4j: Parsing for [root] with value=[debug, stdout].
log4j: Level token is [debug].
log4j: Category root set to DEBUG
log4j: Parsing appender named "stdout".
log4j: Parsing layout options for "stdout".
log4j: Setting property [conversionPattern] to [%d{ABSOLUTE} %5p %c{1}:%L - %m%n].
log4j: End of parsing for "stdout".
log4j: Setting property [target] to [System.err].
log4j: Parsed "stdout" options.
log4j: Finished configuring.
log4j: Parsing for [root] with value=[debug, stdout].
log4j: Level token is [debug].
log4j: Category root set to DEBUG
log4j: Parsing appender named "stdout".
log4j: Parsing layout options for "stdout".
log4j: Setting property [conversionPattern] to [%d{ABSOLUTE} %5p %c{1}:%L - %m%n].
log4j: End of parsing for "stdout".
log4j: Setting property [target] to [System.err].
log4j: Parsed "stdout" options.
log4j: Finished configuring.
17:48:20,944 INFO de:10 - Log message
17:48:22,944 INFO de:10 - Log message
17:48:24,944 INFO de:10 - Log message
17:48:26,944 INFO de:10 - Log message
log4j: Parsing for [root] with value=[debug, stdout].
log4j: Level token is [debug].
log4j: Category root set to DEBUG
log4j: Parsing appender named "stdout".
log4j: Parsing layout options for "stdout".
log4j: Setting property [conversionPattern] to [%d{ABSOLUTE} %5p %c{1}:%L - %m%n].
log4j: End of parsing for "stdout".
log4j: Setting property [target] to [System.out].
log4j: Parsed "stdout" options.
log4j: Finished configuring.
17:48:28,944 INFO de:10 - Log message
17:48:30,944 INFO de:10 - Log message
17:48:32,944 INFO de:10 - Log message
17:48:34,944 INFO de:10 - Log message
log4j: Parsing for [root] with value=[debug, stdout].
log4j: Level token is [debug].
log4j: Category root set to DEBUG
log4j: Parsing appender named "stdout".
log4j: Parsing layout options for "stdout".
log4j: Setting property [conversionPattern] to [%d{ABSOLUTE} %5p %c{1}:%L - %m%n].
log4j: End of parsing for "stdout".
log4j: Setting property [target] to [System.err].
log4j: Parsed "stdout" options.
log4j: Finished configuring.
17:48:36,944 INFO de:10 - Log message
17:48:38,944 INFO de:10 - Log message
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With