You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4j-dev@logging.apache.org by mw...@apache.org on 2006/04/06 07:32:41 UTC
svn commit: r391905 - in /logging/log4j/trunk: docs/
src/java/org/apache/log4j/ src/java/org/apache/log4j/joran/
src/java/org/apache/log4j/spi/ src/java/org/apache/log4j/watchdog/
src/java/org/apache/log4j/xml/ tests/input/watchdog/ tests/src/java/org/...
Author: mwomack
Date: Wed Apr 5 22:32:38 2006
New Revision: 391905
URL: http://svn.apache.org/viewcvs?rev=391905&view=rev
Log:
Cleaned up FileWatchdog implementation, added back configureAndWatch methods for DOMConfigurator and PropertyConfigurator, added more FileWatchdog related tests.
Added:
logging/log4j/trunk/src/java/org/apache/log4j/spi/ConfiguratorEx.java (with props)
logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test3_1.xml (with props)
logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test5_1.xml (with props)
logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test5_2.xml (with props)
logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test6_1.properties (with props)
logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test6_2.properties (with props)
logging/log4j/trunk/tests/witness/watchdog/watchdog.FileWatchdog.test5.txt (with props)
logging/log4j/trunk/tests/witness/watchdog/watchdog.FileWatchdog.test6.txt (with props)
Removed:
logging/log4j/trunk/src/java/org/apache/log4j/watchdog/TimedLocationWatchdog.java
Modified:
logging/log4j/trunk/docs/HISTORY.txt
logging/log4j/trunk/src/java/org/apache/log4j/PropertyConfigurator.java
logging/log4j/trunk/src/java/org/apache/log4j/joran/JoranConfigurator.java
logging/log4j/trunk/src/java/org/apache/log4j/watchdog/FileWatchdog.java
logging/log4j/trunk/src/java/org/apache/log4j/watchdog/Watchdog.java
logging/log4j/trunk/src/java/org/apache/log4j/watchdog/WatchdogSkeleton.java
logging/log4j/trunk/src/java/org/apache/log4j/xml/DOMConfigurator.java
logging/log4j/trunk/tests/src/java/org/apache/log4j/watchdog/FileWatchdogTestCase.java
Modified: logging/log4j/trunk/docs/HISTORY.txt
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/docs/HISTORY.txt?rev=391905&r1=391904&r2=391905&view=diff
==============================================================================
--- logging/log4j/trunk/docs/HISTORY.txt (original)
+++ logging/log4j/trunk/docs/HISTORY.txt Wed Apr 5 22:32:38 2006
@@ -11,6 +11,8 @@
- Release of version 1.3-alpha-9
Release date: TBD
+ - Cleaned up FileWatchdog implementation.
+
January 30th, 2006
- Release of version 1.3alpha-8
Modified: logging/log4j/trunk/src/java/org/apache/log4j/PropertyConfigurator.java
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/src/java/org/apache/log4j/PropertyConfigurator.java?rev=391905&r1=391904&r2=391905&view=diff
==============================================================================
--- logging/log4j/trunk/src/java/org/apache/log4j/PropertyConfigurator.java (original)
+++ logging/log4j/trunk/src/java/org/apache/log4j/PropertyConfigurator.java Wed Apr 5 22:32:38 2006
@@ -22,16 +22,13 @@
import org.apache.log4j.config.ConfiguratorBase;
import org.apache.log4j.config.PropertySetter;
import org.apache.log4j.helpers.OptionConverter;
+import org.apache.log4j.helpers.Constants;
import org.apache.log4j.or.RendererMap;
-import org.apache.log4j.spi.Configurator;
-import org.apache.log4j.spi.ErrorItem;
-import org.apache.log4j.spi.LoggerFactory;
-import org.apache.log4j.spi.LoggerRepository;
-import org.apache.log4j.spi.LoggerRepositoryEx;
//import org.apache.log4j.config.PropertySetterException;
-import org.apache.log4j.spi.OptionHandler;
-import org.apache.log4j.spi.RendererSupport;
+import org.apache.log4j.spi.*;
+import org.apache.log4j.watchdog.FileWatchdog;
+import org.apache.log4j.plugins.PluginRegistry;
import java.io.FileInputStream;
import java.io.IOException;
@@ -43,6 +40,8 @@
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;
+import java.net.URL;
+import java.net.MalformedURLException;
/**
@@ -85,7 +84,8 @@
@author Ceki Gülcü
@author Anders Kristensen
@since 0.8.1 */
-public class PropertyConfigurator extends ConfiguratorBase {
+public class PropertyConfigurator extends ConfiguratorBase
+ implements ConfiguratorEx {
static final String CATEGORY_PREFIX = "log4j.category.";
static final String LOGGER_PREFIX = "log4j.logger.";
static final String FACTORY_PREFIX = "log4j.factory";
@@ -101,6 +101,9 @@
public static final String LOGGER_FACTORY_KEY = "log4j.loggerFactory";
private static final String INTERNAL_ROOT_NAME = "root";
+ private static Object watchdogLock = new Object();
+ private static FileWatchdog fileWatchdog = null;
+
/**
Used internally to keep track of configured appenders.
*/
@@ -348,6 +351,57 @@
}
/**
+ Like {@link #configureAndWatch(String, long)} except that the
+ default delay of 60 seconds is used.
+
+ @deprecated Use org.apache.log4j.watchdog.FileWatchdog directly.
+
+ @param configFilename A log4j configuration file in XML format.
+
+ */
+ static public void configureAndWatch(String configFilename) {
+ configureAndWatch(configFilename, 60000);
+ }
+
+ /**
+ Read the configuration file <code>configFilename</code> if it
+ exists. Moreover, a thread will be created that will periodically
+ check if <code>configFilename</code> has been created or
+ modified. The period is determined by the <code>delay</code>
+ argument. If a change or file creation is detected, then
+ <code>configFilename</code> is read to configure log4j.
+
+ @deprecated Use org.apache.log4j.watchdog.FileWatchdog directly.
+
+ @param configFilename A log4j configuration file in XML format.
+ @param delay The delay in milliseconds to wait between each check.
+ */
+ static public void configureAndWatch(String configFilename, long delay) {
+ synchronized(watchdogLock) {
+ PluginRegistry pluginRegistry =
+ ((LoggerRepositoryEx)LogManager.getLoggerRepository()).getPluginRegistry();
+
+ // stop existing watchdog
+ if (fileWatchdog != null) {
+ pluginRegistry.stopPlugin(fileWatchdog.getName());
+ fileWatchdog = null;
+ }
+
+ // create the watchdog
+ fileWatchdog = new FileWatchdog();
+ fileWatchdog.setName("PropertyConfigurator.FileWatchdog");
+ fileWatchdog.setConfigurator(PropertyConfigurator.class.getName());
+ fileWatchdog.setFile(configFilename);
+ fileWatchdog.setInterval(delay);
+ fileWatchdog.setInitialConfigure(true);
+
+ // register and start the watchdog
+ pluginRegistry.addPlugin(fileWatchdog);
+ fileWatchdog.activateOptions();
+ }
+ }
+
+ /**
Read configuration options from <code>properties</code>.
See {@link #doConfigure(String, LoggerRepository)} for the expected format.
@@ -358,20 +412,20 @@
try {
// we start by attaching a temporary list appender
attachListAppender(repository);
-
+
boolean attachedConsoleApepnder = false;
if ((value != null) && OptionConverter.toBoolean(value, true)) {
attachTemporaryConsoleAppender(repository);
attachedConsoleApepnder = true;
}
-
+
// As soon as we start configuration process, the pristine flag is set to
// false.
if(repository instanceof LoggerRepositoryEx) {
((LoggerRepositoryEx) repository).setPristine(false);
}
-
+
String thresholdStr =
OptionConverter.findAndSubst(THRESHOLD_PREFIX, properties);
@@ -430,7 +484,7 @@
doConfigure(props, repository);
}
-
+
/**
* Read configuration options from input stream <code>configStream</code>.
* @since 1.3
@@ -438,7 +492,7 @@
* @param repository
*/
public void doConfigure(InputStream configStream,
- LoggerRepository repository) {
+ LoggerRepository repository) {
Properties props = new Properties();
getLogger(repository).debug(
"Reading configuration from input stream");
@@ -679,7 +733,7 @@
PropertySetter layoutPS = new PropertySetter(layout);
layoutPS.setLoggerRepository(repository);
layoutPS.setProperties(props, layoutPrefix + ".");
-
+
activateOptions(layout);
getLogger(repository).debug(
"End of parsing for \"" + appenderName + "\".");
Modified: logging/log4j/trunk/src/java/org/apache/log4j/joran/JoranConfigurator.java
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/src/java/org/apache/log4j/joran/JoranConfigurator.java?rev=391905&r1=391904&r2=391905&view=diff
==============================================================================
--- logging/log4j/trunk/src/java/org/apache/log4j/joran/JoranConfigurator.java (original)
+++ logging/log4j/trunk/src/java/org/apache/log4j/joran/JoranConfigurator.java Wed Apr 5 22:32:38 2006
@@ -42,6 +42,7 @@
import org.apache.log4j.joran.spi.SimpleRuleStore;
import org.apache.log4j.spi.ErrorItem;
import org.apache.log4j.spi.LoggerRepository;
+import org.apache.log4j.spi.ConfiguratorEx;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
@@ -68,7 +69,8 @@
* @author Curt Arnold
* @author <a href="http://www.qos.ch/log4j/">Ceki Gülcü</a>
*/
-public class JoranConfigurator extends ConfiguratorBase {
+public class JoranConfigurator extends ConfiguratorBase
+ implements ConfiguratorEx {
private Interpreter joranInterpreter;
private LoggerRepository repository;
Added: logging/log4j/trunk/src/java/org/apache/log4j/spi/ConfiguratorEx.java
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/src/java/org/apache/log4j/spi/ConfiguratorEx.java?rev=391905&view=auto
==============================================================================
--- logging/log4j/trunk/src/java/org/apache/log4j/spi/ConfiguratorEx.java (added)
+++ logging/log4j/trunk/src/java/org/apache/log4j/spi/ConfiguratorEx.java Wed Apr 5 22:32:38 2006
@@ -0,0 +1,19 @@
+package org.apache.log4j.spi;
+
+import java.io.InputStream;
+
+/**
+ * Defines extended methods for Configurators to implement.
+ *
+ * @author Mark Womack
+ * @since 1.3
+ */
+public interface ConfiguratorEx {
+ /**
+ * Configures using an InputStream for input.
+ *
+ * @param stream
+ * @param repository
+ */
+ public void doConfigure(InputStream stream, LoggerRepository repository);
+}
Propchange: logging/log4j/trunk/src/java/org/apache/log4j/spi/ConfiguratorEx.java
------------------------------------------------------------------------------
svn:executable = *
Modified: logging/log4j/trunk/src/java/org/apache/log4j/watchdog/FileWatchdog.java
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/src/java/org/apache/log4j/watchdog/FileWatchdog.java?rev=391905&r1=391904&r2=391905&view=diff
==============================================================================
--- logging/log4j/trunk/src/java/org/apache/log4j/watchdog/FileWatchdog.java (original)
+++ logging/log4j/trunk/src/java/org/apache/log4j/watchdog/FileWatchdog.java Wed Apr 5 22:32:38 2006
@@ -16,21 +16,28 @@
package org.apache.log4j.watchdog;
-import java.io.File;
-import java.net.URL;
+import org.apache.log4j.spi.LoggerRepository;
+import org.apache.log4j.spi.LoggerRepositoryEx;
+import org.apache.log4j.scheduler.Job;
+
+import java.io.*;
/**
* Implements a watchdog to watch a file. When the file changes, determined by
* a change in the file's modification date, the contents of the file are use to
* reconfigure the log4j environment.
*/
-public class FileWatchdog extends TimedLocationWatchdog {
+public class FileWatchdog extends WatchdogSkeleton implements Job {
+
+ public static final long DEFAULT_INTERVAL = 60000;
private String filePath;
+ private long interval = DEFAULT_INTERVAL;
+ private boolean initialConfigure = false;
/** The file being watched. */
private File watchedFile;
- private URL watchedURL;
+ private long lastModTime = -1;
/**
* Sets the path of the file to use and watch for configuration changes.
@@ -49,11 +56,60 @@
public String getFile() {
return filePath;
}
+
+ /**
+ * Sets the interval of time between checks for file modifications.
+ *
+ * @param interval
+ */
+ public void setInterval(long interval) {
+ this.interval = interval;
+ }
+
+ /**
+ * Returns the interval of time between checks for file modifications.
+ *
+ * @return interval of time
+ */
+ public long getInterval() {
+ return interval;
+ }
+
+ /**
+ * Set to true if watchdog should configure with file before starting watch
+ * in activateOptions.
+ *
+ * @param initialConfigure
+ */
+ public void setInitialConfigure(boolean initialConfigure) {
+ this.initialConfigure = initialConfigure;
+ }
+
+ /**
+ * Returns true if watchdog will configure before starting watch in
+ * activateOptions.
+ *
+ * @return
+ */
+ public boolean getInitialConfigure() {
+ return initialConfigure;
+ }
+
+ /**
+ * Returns the last modification time of the watched file.
+ *
+ * @return
+ */
+ public long getLastModTime() {
+ return lastModTime;
+ }
+
/**
* Sets up the reference to the file being watched, then calls the version
* in the super class.
*/
public void activateOptions() {
+ getLogger().debug("activateOptions called for watchdog " + this.getName());
if (filePath == null) {
getLogger().error("watchdog \"{}\" not configured with path to watch",
@@ -62,42 +118,83 @@
}
watchedFile = new File(filePath);
- try {
- //
- // attempt to invoke JDK 1.4's File.toURI and URI.toURL methods
- // which do a better job of escaping file names than File.toURL.
- Object uri = File.class.getMethod("toURI", null).invoke(watchedFile, null);
- watchedURL = (URL) uri.getClass().getMethod("toURL", null).invoke(uri, null);
- } catch(Exception ex) {
- try {
- watchedURL = watchedFile.toURL();
- } catch(java.net.MalformedURLException ex2) {
- this.getLogger().error("Watchdog {} unable to express filename {} as a URL",
- this.getName(), watchedFile.getName());
- }
+
+ // do an initial configure or record the current mod time
+ if (initialConfigure) {
+ execute();
+ } else if (watchedFile.exists()) {
+ lastModTime = watchedFile.lastModified();
+ }
+
+ LoggerRepository repo = getLoggerRepository();
+ if (repo instanceof LoggerRepositoryEx) {
+ ((LoggerRepositoryEx) repo).getScheduler().schedule(this,
+ System.currentTimeMillis() + interval, interval);
+ } else {
+ this.getLogger().error("{} watchdog requires repository that supports LoggerRepositoryEx",
+ this.getName());
}
- super.activateOptions();
}
+ /**
+ * Implements the Job interface for the Scheduler. When this method is called
+ * by the Scheduler it checks the current modification time of the watched
+ * source with the last recorded modification time. If the modification times
+ * are different, then the log4j environment is reconfigured using the
+ * watched source for the configuration data.
+ */
+ public void execute() {
+ getLogger().debug("FileWatchdog \"{}\" executing", this.getName());
+ if (watchedFile.exists()) {
+ long curModTime = watchedFile.lastModified();
+ getLogger().debug("Checking times for watchdog " + this.getName() +
+ " :(lastModTime - " + lastModTime + ") ?? (curModTime - " +
+ curModTime + ")");
+ if (curModTime != lastModTime) {
+ if (reconfigure()) {
+ lastModTime = curModTime;
+ getLogger().debug("Reconfiguration successful for watchdog " +
+ this.getName());
+ } else {
+ getLogger().debug("Reconfiguration not successful for watchdog " +
+ this.getName() + ", not updating mod time");
+ }
+ } else {
+ getLogger().debug("Times matched, doing nothing");
+ }
+ } else {
+ getLogger().debug("File does not exist, doing nothing");
+ }
+ }
/**
- * Returns the modification of the file being watched.
- *
- * @return The modification time of the file.
+ * Shutdown this watchdog. Since implemented as a scheduled Job, this method
+ * simply removes the watchdog from the Scheduler.
*/
- public long getModificationTime() {
- return watchedFile.lastModified();
+ public void shutdown() {
+ LoggerRepository repo = getLoggerRepository();
+ if (repo instanceof LoggerRepositoryEx) {
+ ((LoggerRepositoryEx) repo).getScheduler().delete(this);
+ }
}
-
/**
* Reconfigures the log4j environment using the file as the source of the
* configuration data.
*/
- public void reconfigure() {
- if (watchedFile.exists() && watchedURL != null) {
- reconfigureByURL(watchedURL);
- } else {
- this.getLogger().warn("{} watchdog cannot find file {}",
- this.getName(), watchedFile.getName());
+ public boolean reconfigure() {
+ InputStream stream = null;
+ try {
+ stream = new FileInputStream(watchedFile);
+ return reconfigureByStream(stream);
+ } catch (FileNotFoundException e) {
+ return false;
+ } finally {
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (IOException e2) {
+ // ignore
+ }
+ }
}
}
}
Modified: logging/log4j/trunk/src/java/org/apache/log4j/watchdog/Watchdog.java
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/src/java/org/apache/log4j/watchdog/Watchdog.java?rev=391905&r1=391904&r2=391905&view=diff
==============================================================================
--- logging/log4j/trunk/src/java/org/apache/log4j/watchdog/Watchdog.java (original)
+++ logging/log4j/trunk/src/java/org/apache/log4j/watchdog/Watchdog.java Wed Apr 5 22:32:38 2006
@@ -62,7 +62,9 @@
/**
* Called to reconfigure the log4j environment when the monitored data
* source has been updated.
+ *
+ * @return True if reconfiguration was without errors
*/
- public void reconfigure();
+ public boolean reconfigure();
}
Modified: logging/log4j/trunk/src/java/org/apache/log4j/watchdog/WatchdogSkeleton.java
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/src/java/org/apache/log4j/watchdog/WatchdogSkeleton.java?rev=391905&r1=391904&r2=391905&view=diff
==============================================================================
--- logging/log4j/trunk/src/java/org/apache/log4j/watchdog/WatchdogSkeleton.java (original)
+++ logging/log4j/trunk/src/java/org/apache/log4j/watchdog/WatchdogSkeleton.java Wed Apr 5 22:32:38 2006
@@ -18,12 +18,15 @@
import org.apache.log4j.PropertyConfigurator;
+import org.apache.log4j.config.ConfiguratorBase;
import org.apache.log4j.spi.Configurator;
+import org.apache.log4j.spi.ConfiguratorEx;
import org.apache.log4j.plugins.PluginSkeleton;
import org.apache.log4j.helpers.OptionConverter;
-import java.io.InputStream;
import java.net.URL;
+import java.io.InputStream;
+import java.util.List;
/**
Implements the required interface for Watchdog objects.
@@ -34,7 +37,7 @@
required. Developers may choose to implement their own version of the
Watchdog interface (which extends the base Plugin interface) if they so
choose.
-
+
<p>This implementation provides two helper methods, reconfigureByURL and
reconfigureByInputStream. Either of these methods can be called from the
implemented reconfigure method, as required by the specific type of data
@@ -42,18 +45,18 @@
that can be described by a URL (ie file, url). The rconfigureByInputStream
method is meant for sources where onl a stream of data is available
(ie socket).
-
+
<p>Subclasses of this implementation are required to implement their own
version of the abstract reconfigure method.
@author Mark Womack <mw...@apache.org>
@since 1.3
*/
-public abstract class WatchdogSkeleton
+public abstract class WatchdogSkeleton
extends PluginSkeleton implements Watchdog {
-
+
protected String configuratorClassName;
-
+
/**
* Sets the Configurator class used for reconfiguration.
*
@@ -63,7 +66,7 @@
public void setConfigurator(String configuratorClassName) {
this.configuratorClassName = configuratorClassName;
}
-
+
/**
* Returns the configurator class used for reconfiguration.
*
@@ -77,8 +80,8 @@
* Called to reconfigure the log4j environment when the monitored data
* source has been updated. Must be implemented by subclasses.
*/
- public abstract void reconfigure();
-
+ public abstract boolean reconfigure();
+
/**
* Helper method to get an instance of the configurator class.
*
@@ -87,21 +90,21 @@
*/
protected Configurator getConfiguratorInstance() {
// create an instance of the configurator class
- Configurator configurator = null;
-
+ Configurator configurator;
+
// if we were configured with a configurator class name, use it
if (configuratorClassName != null) {
configurator = (Configurator) OptionConverter.instantiateByClassName(
- configuratorClassName, Configurator.class, null);
+ configuratorClassName, Configurator.class, null);
}
// otherwise, default to PropertyConfigurator
else {
configurator = new PropertyConfigurator();
}
-
+
return configurator;
}
-
+
/**
* Helper method to reconfigure using a URL.
* The input parameter, configurationURL, should be a URL pointing to
@@ -109,24 +112,88 @@
*
* @param srcURL The url that contains the data to be used for
* reconfiguration.
+ * @return True if the reconfiguration was without error
*/
- protected void reconfigureByURL(URL srcURL) {
+ protected boolean reconfigureByURL(URL srcURL) {
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("watchdog \"{}\" reconfiguring from url: {}",
this.getName(), srcURL);
}
-
+
// create an instance of the configurator class
Configurator configurator = getConfiguratorInstance();
-
+
// if able to create configurator, then reconfigure using input stream
if (configurator != null) {
configurator.doConfigure(srcURL, this.getLoggerRepository());
+ if (configurator instanceof ConfiguratorBase) {
+ ConfiguratorBase baseConfigurator = (ConfiguratorBase)configurator;
+ List errorList = baseConfigurator.getErrorList();
+ getLogger().error("errors reported during reconfiguration: ");
+ if (errorList.size() != 0) {
+ for (int x = 0; x < errorList.size(); x++) {
+ getLogger().debug("error " + x + ": " + errorList.get(x));
+ }
+ return false;
+ }
+ }
+ }
+ else {
+ getLogger().error(
+ "watchdog \"{}\" could not create configurator, ignoring new configuration settings",
+ this.getName());
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Helper method to reconfigure using an InputStream.
+ *
+ * @param stream The stream of data to be used for reconfiguration.
+ * @return True if the reconfiguration was without error
+ */
+ protected boolean reconfigureByStream(InputStream stream) {
+ if (this.getLogger().isDebugEnabled()) {
+ this.getLogger().debug("watchdog \"{}\" reconfiguring by stream",
+ this.getName());
}
- else {
- getLogger().error(
+
+ // create an instance of the configurator class
+ Configurator configurator = getConfiguratorInstance();
+ ConfiguratorEx configuratorEx = null;
+
+ if (configurator instanceof ConfiguratorEx) {
+ configuratorEx = (ConfiguratorEx)configurator;
+ } else {
+ getLogger().error(
+ "watchdog \"{}\" could not create configurator, configurator class is not of type ConfiguratorEx",
+ this.getName());
+ }
+
+ // if able to create configurator, then reconfigure using input stream
+ if (configuratorEx != null) {
+ configuratorEx.doConfigure(stream, this.getLoggerRepository());
+ if (configuratorEx instanceof ConfiguratorBase) {
+ ConfiguratorBase baseConfigurator = (ConfiguratorBase)configuratorEx;
+ List errorList = baseConfigurator.getErrorList();
+ getLogger().error("errors reported during reconfiguration: ");
+ if (errorList.size() != 0) {
+ for (int x = 0; x < errorList.size(); x++) {
+ getLogger().debug("error " + x + ": " + errorList.get(x));
+ }
+ return false;
+ }
+ }
+ }
+ else {
+ getLogger().error(
"watchdog \"{}\" could not create configurator, ignoring new configuration settings",
this.getName());
- }
+ return false;
+ }
+
+ return true;
}
}
Modified: logging/log4j/trunk/src/java/org/apache/log4j/xml/DOMConfigurator.java
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/src/java/org/apache/log4j/xml/DOMConfigurator.java?rev=391905&r1=391904&r2=391905&view=diff
==============================================================================
--- logging/log4j/trunk/src/java/org/apache/log4j/xml/DOMConfigurator.java (original)
+++ logging/log4j/trunk/src/java/org/apache/log4j/xml/DOMConfigurator.java Wed Apr 5 22:32:38 2006
@@ -19,6 +19,9 @@
import org.apache.log4j.LogManager;
import org.apache.log4j.joran.JoranConfigurator;
import org.apache.log4j.spi.LoggerRepository;
+import org.apache.log4j.spi.LoggerRepositoryEx;
+import org.apache.log4j.plugins.PluginRegistry;
+import org.apache.log4j.watchdog.FileWatchdog;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
@@ -29,6 +32,7 @@
import org.xml.sax.helpers.DefaultHandler;
import java.net.URL;
+import java.net.MalformedURLException;
import javax.xml.parsers.SAXParser;
@@ -62,6 +66,10 @@
@deprecated Replaced by the much more flexible {@link org.apache.log4j.joran.JoranConfigurator}.
@since 0.8.3 */
public class DOMConfigurator extends JoranConfigurator {
+
+ private static Object watchdogLock = new Object();
+ private static FileWatchdog fileWatchdog = null;
+
public static void configure(String file) {
JoranConfigurator joran = new JoranConfigurator();
joran.doConfigure(file, LogManager.getLoggerRepository());
@@ -92,6 +100,57 @@
doConfigure(action, repository);
}
+ /**
+ Like {@link #configureAndWatch(String, long)} except that the
+ default delay of 60 seconds is used.
+
+ @deprecated Use org.apache.log4j.watchdog.FileWatchdog directly.
+
+ @param configFilename A log4j configuration file in XML format.
+
+ */
+ static public void configureAndWatch(String configFilename) {
+ configureAndWatch(configFilename, 60000);
+ }
+
+ /**
+ Read the configuration file <code>configFilename</code> if it
+ exists. Moreover, a thread will be created that will periodically
+ check if <code>configFilename</code> has been created or
+ modified. The period is determined by the <code>delay</code>
+ argument. If a change or file creation is detected, then
+ <code>configFilename</code> is read to configure log4j.
+
+ @deprecated Use org.apache.log4j.watchdog.FileWatchdog directly.
+
+ @param configFilename A log4j configuration file in XML format.
+ @param delay The delay in milliseconds to wait between each check.
+ */
+ static public void configureAndWatch(String configFilename, long delay) {
+ synchronized(watchdogLock) {
+ PluginRegistry pluginRegistry =
+ ((LoggerRepositoryEx)LogManager.getLoggerRepository()).getPluginRegistry();
+
+ // stop existing watchdog
+ if (fileWatchdog != null) {
+ pluginRegistry.stopPlugin(fileWatchdog.getName());
+ fileWatchdog = null;
+ }
+
+ // create the watchdog
+ fileWatchdog = new FileWatchdog();
+ fileWatchdog.setName("DOMConfigurator.FileWatchdog");
+ fileWatchdog.setConfigurator(DOMConfigurator.class.getName());
+ fileWatchdog.setFile(configFilename);
+ fileWatchdog.setInterval(delay);
+ fileWatchdog.setInitialConfigure(true);
+
+ // register and start the watchdog
+ pluginRegistry.addPlugin(fileWatchdog);
+ fileWatchdog.activateOptions();
+ }
+ }
+
/**
* Class that "parses" a DOM element by replaying the
* corresponding SAX events.
Added: logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test3_1.xml
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test3_1.xml?rev=391905&view=auto
==============================================================================
--- logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test3_1.xml (added)
+++ logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test3_1.xml Wed Apr 5 22:32:38 2006
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE log4j:configuration >
+
+<log4j:configuration xmlns:log4j="http://logging.apache.org/">
+
+<!-- we just want a badly configured file here -->
+
+<!--/log4j:configuration-->
Propchange: logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test3_1.xml
------------------------------------------------------------------------------
svn:executable = *
Added: logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test5_1.xml
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test5_1.xml?rev=391905&view=auto
==============================================================================
--- logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test5_1.xml (added)
+++ logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test5_1.xml Wed Apr 5 22:32:38 2006
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE log4j:configuration >
+
+<log4j:configuration xmlns:log4j="http://logging.apache.org/">
+
+ <appender name="A1" class="org.apache.log4j.FileAppender">
+
+ <param name="Append" value="false" />
+ <param name="File" value="output/watchdog.FileWatchdog.test5.txt" />
+
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%p - %m%n"/>
+ </layout>
+ </appender>
+
+ <appender name="A2" class="org.apache.log4j.ConsoleAppender">
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%d{ABSOLUTE} %c [%p] - %m%n"/>
+ </layout>
+ </appender>
+
+ <logger name="org.apache.log4j">
+ <level value="info"/>
+ </logger>
+
+ <logger name="test.FileWatchdogTestCase">
+ <appender-ref ref="A1" />
+ <level value="debug"/>
+ </logger>
+
+ <logger name="org.apache.log4j.watchdog">
+ <level value="debug"/>
+ </logger>
+
+ <root>
+ <appender-ref ref="A2"/>
+ <level value="debug" />
+ </root>
+
+</log4j:configuration>
Propchange: logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test5_1.xml
------------------------------------------------------------------------------
svn:executable = *
Added: logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test5_2.xml
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test5_2.xml?rev=391905&view=auto
==============================================================================
--- logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test5_2.xml (added)
+++ logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test5_2.xml Wed Apr 5 22:32:38 2006
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE log4j:configuration >
+
+<log4j:configuration xmlns:log4j="http://logging.apache.org/">
+
+ <logger name="test.FileWatchdogTestCase">
+ <level value="info"/>
+ </logger>
+
+</log4j:configuration>
Propchange: logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test5_2.xml
------------------------------------------------------------------------------
svn:executable = *
Added: logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test6_1.properties
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test6_1.properties?rev=391905&view=auto
==============================================================================
--- logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test6_1.properties (added)
+++ logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test6_1.properties Wed Apr 5 22:32:38 2006
@@ -0,0 +1,20 @@
+log4j.debug=TRUE
+log4j.threshold=ON
+
+log4j.rootLogger=DEBUG,A2
+
+log4j.appender.A1=org.apache.log4j.FileAppender
+log4j.appender.A1.File=output/watchdog.FileWatchdog.test6.txt
+log4j.appender.A1.Append=false
+log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+log4j.appender.A1.layout.ConversionPattern=%p - %m%n
+
+log4j.appender.A2=org.apache.log4j.ConsoleAppender
+log4j.appender.A2.layout=org.apache.log4j.PatternLayout
+log4j.appender.A2.layout.ConversionPattern=%d{ABSOLUTE} %c [%p] - %m%n
+
+#log4j.logger.org.apache.log4j=WARN
+log4j.logger.test.FileWatchdogTestCase=DEBUG,A1
+log4j.logger.org.apache.log4j.watchdog.FileWatchdogTestCase=DEBUG
+log4j.logger.org.apache.log4j=INFO
+log4j.logger.org.apache.log4j.watchdog=DEBUG
Propchange: logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test6_1.properties
------------------------------------------------------------------------------
svn:executable = *
Added: logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test6_2.properties
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test6_2.properties?rev=391905&view=auto
==============================================================================
--- logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test6_2.properties (added)
+++ logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test6_2.properties Wed Apr 5 22:32:38 2006
@@ -0,0 +1,10 @@
+log4j.debug=TRUE
+log4j.threshold=ON
+
+log4j.appender.A1=org.apache.log4j.FileAppender
+log4j.appender.A1.File=output/watchdog.FileWatchdog.test6.txt
+log4j.appender.A1.Append=true
+log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+log4j.appender.A1.layout.ConversionPattern=%p - %m%n
+
+log4j.logger.test.FileWatchdogTestCase=INFO,A1
Propchange: logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test6_2.properties
------------------------------------------------------------------------------
svn:executable = *
Modified: logging/log4j/trunk/tests/src/java/org/apache/log4j/watchdog/FileWatchdogTestCase.java
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/src/java/org/apache/log4j/watchdog/FileWatchdogTestCase.java?rev=391905&r1=391904&r2=391905&view=diff
==============================================================================
--- logging/log4j/trunk/tests/src/java/org/apache/log4j/watchdog/FileWatchdogTestCase.java (original)
+++ logging/log4j/trunk/tests/src/java/org/apache/log4j/watchdog/FileWatchdogTestCase.java Wed Apr 5 22:32:38 2006
@@ -29,7 +29,7 @@
import org.apache.log4j.spi.LoggerRepositoryEx;
import org.apache.log4j.joran.JoranConfigurator;
import org.apache.log4j.Level;
-
+import org.apache.log4j.xml.DOMConfigurator;
public class FileWatchdogTestCase extends TestCase {
@@ -46,8 +46,16 @@
private void copyFile(File src, File dst) throws Exception {
if (dst.exists()) {
- assertTrue(dst.delete());
+ for (int x = 0; x < 5; x++) {
+ if (x == 4) {
+ assertTrue("File " + dst.getAbsolutePath() +
+ " not deleted", false);
+ }
+ if (dst.delete()) break;
+ Thread.sleep(750);
+ }
}
+
FileOutputStream out = new FileOutputStream(dst);
FileInputStream in = new FileInputStream(src);
byte[] buffer = new byte[1024];
@@ -101,9 +109,10 @@
}
// basic test of plugin in standalone mode
- public void test1() throws Exception {
+ public void testJoranConfigurator() throws Exception {
LogManager.getLoggerRepository().resetConfiguration();
-
+ logger.setLevel(Level.DEBUG);
+
File outFile = new File(getOutputFile("test1"));
if (outFile.exists()) {
assertTrue(outFile.delete());
@@ -120,14 +129,14 @@
// move the first config file into place
copyFile(sourceFile1, configFile);
assertTrue(configFile.exists());
-
+
testLogger.debug("first config file in place: " + configFile.getAbsolutePath());
// configure environment to first config file
JoranConfigurator configurator = new JoranConfigurator();
configurator.doConfigure(configFile.getAbsolutePath(),
LogManager.getLoggerRepository());
-
+
testLogger.debug("log4j configured with configFile");
// now watch the file for changes
@@ -138,7 +147,7 @@
watchdog.setConfigurator(JoranConfigurator.class.getName());
((LoggerRepositoryEx) LogManager.getLoggerRepository()).getPluginRegistry().addPlugin(watchdog);
watchdog.activateOptions();
-
+
testLogger.debug("watchdog activated");
// output some test messages
@@ -147,16 +156,16 @@
logger.warn("warn message");
logger.error("error message");
logger.fatal("fatal message");
-
+
testLogger.debug("first set of test messages output");
Thread.sleep(2000);
-
+
testLogger.debug("about to copy second config file");
-
+
// copy over a new version of the config file
copyFile(sourceFile2, configFile);
-
+
testLogger.debug("second config file copied");
// wait a few seconds for the watchdog to react
@@ -171,7 +180,7 @@
logger.warn("warn message");
logger.error("error message");
logger.fatal("fatal message");
-
+
testLogger.debug("second set of test messages output");
assertTrue(Compare.compare(getOutputFile("test1"),
@@ -181,88 +190,398 @@
testLogger.debug("looping for level check");
}
fail("Expected change in level did not occur within 20 seconds.");
+ }
+
+ // basic test of plugin in standalone mode with PropertyConfigurator
+ public void testPropertyConfigurator() throws Exception {
+ LogManager.getLoggerRepository().resetConfiguration();
+ logger.setLevel(Level.DEBUG);
+
+ File outFile = new File(getOutputFile("test2"));
+ if (outFile.exists()) {
+ assertTrue(outFile.delete());
}
- // basic test of plugin in standalone mode with PropertyConfigurator
- public void test2() throws Exception {
- LogManager.getLoggerRepository().resetConfiguration();
-
- File outFile = new File(getOutputFile("test2"));
- if (outFile.exists()) {
- assertTrue(outFile.delete());
+ // set up the needed file references
+ File sourceFile1 = new File(getSourceConfigFile("test2", 1));
+ File sourceFile2 = new File(getSourceConfigFile("test2", 2));
+ assertTrue(sourceFile1.exists());
+ assertTrue(sourceFile2.exists());
+
+ File configFile = new File(getConfigFile("test2"));
+
+ // move the first config file into place
+ copyFile(sourceFile1, configFile);
+ assertTrue(configFile.exists());
+
+ testLogger.debug("first config file in place: " + configFile.getAbsolutePath());
+
+ // configure environment to first config file
+ PropertyConfigurator configurator = new PropertyConfigurator();
+ configurator.doConfigure(configFile.getAbsolutePath(),
+ LogManager.getLoggerRepository());
+
+ testLogger.debug("log4j configured with configFile");
+
+ // now watch the file for changes
+ FileWatchdog watchdog = new FileWatchdog();
+ watchdog.setName("test2");
+ watchdog.setFile(configFile.getAbsolutePath());
+ watchdog.setInterval(1000);
+ watchdog.setConfigurator(PropertyConfigurator.class.getName());
+ ((LoggerRepositoryEx) LogManager.getLoggerRepository()).getPluginRegistry().addPlugin(watchdog);
+ watchdog.activateOptions();
+
+ testLogger.debug("watchdog activated");
+
+ // output some test messages
+ logger.debug("debug message");
+ logger.info("info message");
+ logger.warn("warn message");
+ logger.error("error message");
+ logger.fatal("fatal message");
+
+ testLogger.debug("first set of test messages output");
+
+ Thread.sleep(2000);
+
+ testLogger.debug("about to copy second config file");
+
+ // copy over a new version of the config file
+ copyFile(sourceFile2, configFile);
+
+ testLogger.debug("second config file copied");
+
+ // wait a few seconds for the watchdog to react
+ for (int i = 0; i < 40; i++) {
+ testLogger.debug("sleeping for 500 ms");
+ Thread.sleep(500);
+ testLogger.debug("level for logger " + logger.getName() + " is " + logger.getLevel());
+ if (logger.getLevel() == Level.INFO) {
+ // output some test messages
+ logger.debug("debug message");
+ logger.info("info message");
+ logger.warn("warn message");
+ logger.error("error message");
+ logger.fatal("fatal message");
+
+ testLogger.debug("second set of test messages output");
+ Thread.sleep(500);
+
+ assertTrue("output does not match", Compare.compare(getOutputFile("test2"),
+ getWitnessFile("test2")));
+ return;
+ }
+ testLogger.debug("looping for level check");
+ }
+ fail("Expected change in level did not occur within 20 seconds.");
+ }
+
+ public void testJoranConfigurationError() throws Exception {
+ LogManager.getLoggerRepository().resetConfiguration();
+ logger.setLevel(Level.DEBUG);
+
+ File outFile = new File(getOutputFile("test3"));
+ if (outFile.exists()) {
+ assertTrue(outFile.delete());
+ }
+
+ // set up the needed file references
+ File sourceFile1 = new File(getSourceXMLConfigFile("test3", 1));
+ File sourceFile2 = new File(getSourceXMLConfigFile("test1", 2));
+ assertTrue(sourceFile1.exists());
+ assertTrue(sourceFile2.exists());
+
+ // config file should not exist yet
+ File configFile = new File(getXMLConfigFile("test3"));
+ assertFalse(configFile.exists());
+
+ // now watch the nonexistent file for changes
+ FileWatchdog watchdog = new FileWatchdog();
+ watchdog.setName("test3");
+ watchdog.setFile(configFile.getAbsolutePath());
+ watchdog.setInterval(1000);
+ watchdog.setConfigurator(JoranConfigurator.class.getName());
+ ((LoggerRepositoryEx) LogManager.getLoggerRepository()).getPluginRegistry().addPlugin(watchdog);
+ watchdog.activateOptions();
+
+ testLogger.debug("watchdog activated");
+
+ // the file does not exist, so the modification time should never change
+ long modTime = watchdog.getLastModTime();
+ for (int count = 0; count < 5; count++) {
+ if (modTime != watchdog.getLastModTime()) {
+ assertTrue("watchdog mod time changed when no file", false);
}
+ Thread.sleep(500);
+ }
- // set up the needed file references
- File sourceFile1 = new File(getSourceConfigFile("test2", 1));
- File sourceFile2 = new File(getSourceConfigFile("test2", 2));
- assertTrue(sourceFile1.exists());
- assertTrue(sourceFile2.exists());
+ testLogger.debug("no file, mod time not changed: " + modTime);
- File configFile = new File(getConfigFile("test2"));
+ // move the bad config file into place
+ copyFile(sourceFile1, configFile);
+ assertTrue(configFile.exists());
+
+ testLogger.debug("bad config file put into place");
+
+ // the file is "bad", so the modification time should never change
+ for (int count = 0; count < 7; count++) {
+ if (modTime != watchdog.getLastModTime()) {
+ assertTrue("watchdog mod time changed for bad file", false);
+ }
+ Thread.sleep(500);
+ }
- // move the first config file into place
- copyFile(sourceFile1, configFile);
- assertTrue(configFile.exists());
-
- testLogger.debug("first config file in place: " + configFile.getAbsolutePath());
+ testLogger.debug("bad file, mod time not changed: " + modTime);
- // configure environment to first config file
- PropertyConfigurator configurator = new PropertyConfigurator();
- configurator.doConfigure(configFile.getAbsolutePath(),
- LogManager.getLoggerRepository());
-
- testLogger.debug("log4j configured with configFile");
+ // move the good config file into place
+ copyFile(sourceFile2, configFile);
+ assertTrue(configFile.exists());
+
+ testLogger.debug("moved good config file into place");
+
+ // the file is good, so the modification time and level should change
+ for (int count = 0; count < 7; count++) {
+ if (modTime != watchdog.getLastModTime()) {
+ assertTrue(logger.getLevel() == Level.INFO);
+ break;
+ }
- // now watch the file for changes
- FileWatchdog watchdog = new FileWatchdog();
- watchdog.setName("test2");
- watchdog.setFile(configFile.getAbsolutePath());
- watchdog.setInterval(1000);
- watchdog.setConfigurator(PropertyConfigurator.class.getName());
- ((LoggerRepositoryEx) LogManager.getLoggerRepository()).getPluginRegistry().addPlugin(watchdog);
- watchdog.activateOptions();
-
- testLogger.debug("watchdog activated");
+ if (count == 6) {
+ assertTrue("mod time for good file never changed", false);
+ }
- // output some test messages
- logger.debug("debug message");
- logger.info("info message");
- logger.warn("warn message");
- logger.error("error message");
- logger.fatal("fatal message");
-
- testLogger.debug("first set of test messages output");
+ Thread.sleep(500);
+ }
- Thread.sleep(2000);
-
- testLogger.debug("about to copy second config file");
-
- // copy over a new version of the config file
- copyFile(sourceFile2, configFile);
-
- testLogger.debug("second config file copied");
+ testLogger.debug("good file, modTime changed: " + modTime);
+ }
- // wait a few seconds for the watchdog to react
- for (int i = 0; i < 40; i++) {
- testLogger.debug("sleeping for 500 ms");
- Thread.sleep(500);
- testLogger.debug("level for logger " + logger.getName() + " is " + logger.getLevel());
- if (logger.getLevel() == Level.INFO) {
- // output some test messages
- logger.debug("debug message");
- logger.info("info message");
- logger.warn("warn message");
- logger.error("error message");
- logger.fatal("fatal message");
-
- testLogger.debug("second set of test messages output");
+ public void testPropertyConfigurationError() throws Exception {
+ LogManager.getLoggerRepository().resetConfiguration();
+ logger.setLevel(Level.DEBUG);
+
+ File outFile = new File(getOutputFile("test4"));
+ if (outFile.exists()) {
+ assertTrue(outFile.delete());
+ }
- assertTrue(Compare.compare(getOutputFile("test2"),
- getWitnessFile("test2")));
- return;
- }
- testLogger.debug("looping for level check");
+ // set up the needed file references
+ // need a "bad" property file
+ //File sourceFile1 = new File(getSourceConfigFile("test4", 1));
+ File sourceFile2 = new File(getSourceConfigFile("test2", 2));
+ //assertTrue(sourceFile1.exists());
+ assertTrue(sourceFile2.exists());
+
+ // config file should not exist yet
+ File configFile = new File(getConfigFile("test4"));
+ assertFalse(configFile.exists());
+
+ // now watch the nonexistent file for changes
+ FileWatchdog watchdog = new FileWatchdog();
+ watchdog.setName("test4");
+ watchdog.setFile(configFile.getAbsolutePath());
+ watchdog.setInterval(1000);
+ watchdog.setConfigurator(PropertyConfigurator.class.getName());
+ ((LoggerRepositoryEx) LogManager.getLoggerRepository()).getPluginRegistry().addPlugin(watchdog);
+ watchdog.activateOptions();
+
+ testLogger.debug("watchdog activated");
+
+ // the file does not exist, so the modification time should never change
+ long modTime = watchdog.getLastModTime();
+ for (int count = 0; count < 5; count++) {
+ if (modTime != watchdog.getLastModTime()) {
+ assertTrue("watchdog mod time changed when no file", false);
}
- fail("Expected change in level did not occur within 20 seconds.");
+ Thread.sleep(500);
+ }
+
+ testLogger.debug("no file, mod time not changed: " + modTime);
+
+/* need a "bad" property file
+ // move the bad config file into place
+ copyFile(sourceFile1, configFile);
+ assertTrue(configFile.exists());
+
+ testLogger.debug("bad config file put into place");
+
+ // the file is "bad", so the modification time should never change
+ for (int count = 0; count < 7; count++) {
+ if (modTime != watchdog.getLastModTime()) {
+ assertTrue("watchdog mod time changed for bad file", false);
+ }
+ Thread.sleep(500);
+ }
+
+ testLogger.debug("bad file, mod time not changed: " + modTime);
+*/
+
+ // move the good config file into place
+ copyFile(sourceFile2, configFile);
+ assertTrue(configFile.exists());
+
+ testLogger.debug("moved good config file into place");
+
+ // the file is good, so the modification time and level should change
+ for (int count = 0; count < 7; count++) {
+ if (modTime != watchdog.getLastModTime()) {
+ assertTrue(logger.getLevel() == Level.INFO);
+ break;
+ }
+
+ if (count == 6) {
+ assertTrue("mod time for good file never changed", false);
+ }
+
+ Thread.sleep(500);
+ }
+
+ testLogger.debug("good file, modTime changed: " + modTime);
+ }
+
+ public void testDOMConfigureAndWatch() throws Exception {
+ LogManager.getLoggerRepository().resetConfiguration();
+ logger.setLevel(Level.DEBUG);
+
+ File outFile = new File(getOutputFile("test5"));
+ if (outFile.exists()) {
+ assertTrue(outFile.delete());
+ }
+
+ // set up the needed file references
+ File sourceFile1 = new File(getSourceXMLConfigFile("test5", 1));
+ File sourceFile2 = new File(getSourceXMLConfigFile("test5", 2));
+ assertTrue(sourceFile1.exists());
+ assertTrue(sourceFile2.exists());
+
+ File configFile = new File(getXMLConfigFile("test5"));
+
+ // move the first config file into place
+ copyFile(sourceFile1, configFile);
+ assertTrue(configFile.exists());
+
+ testLogger.debug("first config file in place: " + configFile.getAbsolutePath());
+
+ // now watch the file for changes
+ DOMConfigurator.configureAndWatch(configFile.getAbsolutePath(), 1000);
+
+ testLogger.debug("configureAndWatch activated");
+
+ // output some test messages
+ logger.debug("debug message");
+ logger.info("info message");
+ logger.warn("warn message");
+ logger.error("error message");
+ logger.fatal("fatal message");
+
+ testLogger.debug("first set of test messages output");
+
+ Thread.sleep(2000);
+
+ testLogger.debug("about to copy second config file");
+
+ // copy over a new version of the config file
+ copyFile(sourceFile2, configFile);
+
+ testLogger.debug("second config file copied");
+
+ // wait a few seconds for the watchdog to react
+ for (int i = 0; i < 40; i++) {
+ testLogger.debug("sleeping for 500 ms");
+ Thread.sleep(500);
+ testLogger.debug("level for logger " + logger.getName() + " is " + logger.getLevel());
+ if (logger.getLevel() == Level.INFO) {
+ // output some test messages
+ logger.debug("debug message");
+ logger.info("info message");
+ logger.warn("warn message");
+ logger.error("error message");
+ logger.fatal("fatal message");
+
+ testLogger.debug("second set of test messages output");
+ Thread.sleep(500);
+
+ assertTrue("output does not match", Compare.compare(getOutputFile("test5"),
+ getWitnessFile("test5")));
+ return;
+ }
+ testLogger.debug("looping for level check");
+ }
+ fail("Expected change in level did not occur within 20 seconds.");
+ }
+
+ /* there is a bug in property configurator where it will not work a second
+ time, so commenting this out for now
+ public void testPropertyConfigureAndWatch() throws Exception {
+ LogManager.getLoggerRepository().resetConfiguration();
+ logger.setLevel(Level.DEBUG);
+
+ File outFile = new File(getOutputFile("test6"));
+ if (outFile.exists()) {
+ assertTrue(outFile.delete());
+ }
+
+ // set up the needed file references
+ File sourceFile1 = new File(getSourceConfigFile("test6", 1));
+ File sourceFile2 = new File(getSourceConfigFile("test6", 2));
+ assertTrue(sourceFile1.exists());
+ assertTrue(sourceFile2.exists());
+
+ File configFile = new File(getConfigFile("test6"));
+
+ // move the first config file into place
+ copyFile(sourceFile1, configFile);
+ assertTrue(configFile.exists());
+
+ testLogger.debug("first config file in place: " + configFile.getAbsolutePath());
+
+ // now watch the file for changes
+ PropertyConfigurator.configureAndWatch(configFile.getAbsolutePath(), 1000);
+
+ testLogger.debug("configureAndWatch activated");
+
+ // output some test messages
+ logger.debug("debug message");
+ logger.info("info message");
+ logger.warn("warn message");
+ logger.error("error message");
+ logger.fatal("fatal message");
+
+ testLogger.debug("first set of test messages output");
+
+ Thread.sleep(2000);
+
+ testLogger.debug("about to copy second config file");
+
+ // copy over a new version of the config file
+ copyFile(sourceFile2, configFile);
+
+ testLogger.debug("second config file copied");
+
+ // wait a few seconds for the watchdog to react
+ for (int i = 0; i < 40; i++) {
+ testLogger.debug("sleeping for 500 ms");
+ Thread.sleep(500);
+ testLogger.debug("level for logger " + logger.getName() + " is " + logger.getLevel());
+ if (logger.getLevel() == Level.INFO) {
+ // output some test messages
+ logger.debug("debug message");
+ logger.info("info message");
+ logger.warn("warn message");
+ logger.error("error message");
+ logger.fatal("fatal message");
+
+ testLogger.debug("second set of test messages output");
+ Thread.sleep(1000);
+
+ assertTrue("output does not match", Compare.compare(getOutputFile("test6"),
+ getWitnessFile("test6")));
+ return;
+ }
+ testLogger.debug("looping for level check");
}
+ fail("Expected change in level did not occur within 20 seconds.");
+ }
+ */
}
Added: logging/log4j/trunk/tests/witness/watchdog/watchdog.FileWatchdog.test5.txt
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/witness/watchdog/watchdog.FileWatchdog.test5.txt?rev=391905&view=auto
==============================================================================
--- logging/log4j/trunk/tests/witness/watchdog/watchdog.FileWatchdog.test5.txt (added)
+++ logging/log4j/trunk/tests/witness/watchdog/watchdog.FileWatchdog.test5.txt Wed Apr 5 22:32:38 2006
@@ -0,0 +1,9 @@
+DEBUG - debug message
+INFO - info message
+WARN - warn message
+ERROR - error message
+FATAL - fatal message
+INFO - info message
+WARN - warn message
+ERROR - error message
+FATAL - fatal message
Propchange: logging/log4j/trunk/tests/witness/watchdog/watchdog.FileWatchdog.test5.txt
------------------------------------------------------------------------------
svn:executable = *
Added: logging/log4j/trunk/tests/witness/watchdog/watchdog.FileWatchdog.test6.txt
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/witness/watchdog/watchdog.FileWatchdog.test6.txt?rev=391905&view=auto
==============================================================================
--- logging/log4j/trunk/tests/witness/watchdog/watchdog.FileWatchdog.test6.txt (added)
+++ logging/log4j/trunk/tests/witness/watchdog/watchdog.FileWatchdog.test6.txt Wed Apr 5 22:32:38 2006
@@ -0,0 +1,9 @@
+DEBUG - debug message
+INFO - info message
+WARN - warn message
+ERROR - error message
+FATAL - fatal message
+INFO - info message
+WARN - warn message
+ERROR - error message
+FATAL - fatal message
Propchange: logging/log4j/trunk/tests/witness/watchdog/watchdog.FileWatchdog.test6.txt
------------------------------------------------------------------------------
svn:executable = *
---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-dev-unsubscribe@logging.apache.org
For additional commands, e-mail: log4j-dev-help@logging.apache.org
Re: svn commit: r391905 - in /logging/log4j/trunk: docs/ src/java/org/apache/log4j/ src/java/org/apache/log4j/joran/ src/java/org/apache/log4j/spi/ src/java/org/apache/log4j/watchdog/ src/java/org/apache/log4j/xml/ tests/input/watchdog/ tests/src/java/org/
Posted by Curt Arnold <ca...@apache.org>.
On Apr 7, 2006, at 1:10 AM, Curt Arnold wrote:
>
> On Apr 6, 2006, at 11:12 PM, Mark Womack wrote:
>> Hm. That implies that the Watchdog will need to be configured
>> with what kind of input type to give to the configurator, since
>> InputSource will not generically work with all configurators (like
>> PropertyConfigurator). Or I could add doConfigure(File) to
>> ConfiguratorEx. That is probably better.
>>
>
> I don't see any reason why PropertyConfigurator could not have a
> doConfigure(InputSource) method. ConfiguratorEx is a new
> interface, so there is no compatibility issue. If a configurator
> wants to support ConfiguratorEx, it can add a doConfigure
> (InputSource, LoggerRepository).
>
>
>> But another question is what is going to happen when I add
>> HttpWatchdog and SocketWatchdog this weekend? How would they
>> resolve the location of the filespec? Or would it need to specify
>> the ENTITY in a different way, maybe as a url?
>
> An HttpWatchdog (or any watchdog that is representing a resource
> that can be addressed with a URL) would just call
> configurator.doConfigure(new InputSource("http://www.example.org/
> foo/log4j.xml"), repository) which would provide the base URL for
> any entities (so in the example the external entity would be
> resolved as http://www.example.org/foo/stdAppenders.xml). Don't
> know about the SocketAppender, I assume that you'd only have a
> Reader or an InputStream (both of which can be represented in an
> InputSource). You couldn't use a configuration file with external
> entities with relative URL's since there'd be no base URL, however
> that should be acceptable. It wouldn't be like the file scenario
> where it would successfully parse on the initial pass and then
> start failing on the watchdog.
>
And forget what I just said about InputSource. Unfortunately, there
is not a reliable mechanism to convert File paths to URL on earlier
JDK's. You may have to resort to using an approach like I did with
the DOMConfigurator (in log4j 1.2) and JoranConfigurator where you
create a distinct object that packages all the necessary
information. It may be as simple as having Watchdog take a Runnable
and invoking run() every time the monitored resource changes.
---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-dev-unsubscribe@logging.apache.org
For additional commands, e-mail: log4j-dev-help@logging.apache.org
Re: svn commit: r391905 - in /logging/log4j/trunk: docs/ src/java/org/apache/log4j/ src/java/org/apache/log4j/joran/ src/java/org/apache/log4j/spi/ src/java/org/apache/log4j/watchdog/ src/java/org/apache/log4j/xml/ tests/input/watchdog/ tests/src/java/org/
Posted by Curt Arnold <ca...@apache.org>.
On Apr 6, 2006, at 11:12 PM, Mark Womack wrote:
> Hm. That implies that the Watchdog will need to be configured with
> what kind of input type to give to the configurator, since
> InputSource will not generically work with all configurators (like
> PropertyConfigurator). Or I could add doConfigure(File) to
> ConfiguratorEx. That is probably better.
>
I don't see any reason why PropertyConfigurator could not have a
doConfigure(InputSource) method. ConfiguratorEx is a new interface,
so there is no compatibility issue. If a configurator wants to
support ConfiguratorEx, it can add a doConfigure(InputSource,
LoggerRepository).
> But another question is what is going to happen when I add
> HttpWatchdog and SocketWatchdog this weekend? How would they
> resolve the location of the filespec? Or would it need to specify
> the ENTITY in a different way, maybe as a url?
An HttpWatchdog (or any watchdog that is representing a resource that
can be addressed with a URL) would just call configurator.doConfigure
(new InputSource("http://www.example.org/foo/log4j.xml"), repository)
which would provide the base URL for any entities (so in the example
the external entity would be resolved as http://www.example.org/foo/
stdAppenders.xml). Don't know about the SocketAppender, I assume
that you'd only have a Reader or an InputStream (both of which can be
represented in an InputSource). You couldn't use a configuration
file with external entities with relative URL's since there'd be no
base URL, however that should be acceptable. It wouldn't be like the
file scenario where it would successfully parse on the initial pass
and then start failing on the watchdog.
---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-dev-unsubscribe@logging.apache.org
For additional commands, e-mail: log4j-dev-help@logging.apache.org
Re: svn commit: r391905 - in /logging/log4j/trunk: docs/ src/java/org/apache/log4j/ src/java/org/apache/log4j/joran/ src/java/org/apache/log4j/spi/ src/java/org/apache/log4j/watchdog/ src/java/org/apache/log4j/xml/ tests/input/watchdog/ tests/src/java/org/
Posted by Mark Womack <mw...@apache.org>.
> Using an InputStream is a problem since it would cause any XML
> configuration that contained external entities to fail to parse. For
> example, if you have a document like:
>
> <!DOCTYPE log4j:configuration [
> <!ENTITY stdAppenders SYSTEM 'stdAppenders.xml'>
> ]>
> <log4j:configuration>
> <!-- include standard appenders -->
> &stdAppenders;
> ...
> </log4j:configuration>
>
> This document would successfully parse when
> DOMConfigurator.configurator(File) is called but would fail on
> DOMConfigurator(InputStream) since the base path needed to resolve the
> relative file spec stdAppenders.xml is not provided. From reading the
> code, I believe that configureAndWatch would likely succeed on the
> initial configuration but would fail on any subsequent configuration.
>
> Using org.xml.sax.InputSource instead of java.io.InputStream may be one
> way to address the problem.
Hm. That implies that the Watchdog will need to be configured with what
kind of input type to give to the configurator, since InputSource will not
generically work with all configurators (like PropertyConfigurator). Or I
could add doConfigure(File) to ConfiguratorEx. That is probably better.
But another question is what is going to happen when I add HttpWatchdog and
SocketWatchdog this weekend? How would they resolve the location of the
filespec? Or would it need to specify the ENTITY in a different way, maybe
as a url?
-Mark
---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-dev-unsubscribe@logging.apache.org
For additional commands, e-mail: log4j-dev-help@logging.apache.org
Re: svn commit: r391905 - in /logging/log4j/trunk: docs/ src/java/org/apache/log4j/ src/java/org/apache/log4j/joran/ src/java/org/apache/log4j/spi/ src/java/org/apache/log4j/watchdog/ src/java/org/apache/log4j/xml/ tests/input/watchdog/ tests/src/java/org/...
Posted by Curt Arnold <ca...@apache.org>.
On Apr 6, 2006, at 12:32 AM, mwomack@apache.org wrote:
> Author: mwomack
> Date: Wed Apr 5 22:32:38 2006
> New Revision: 391905
>
> URL: http://svn.apache.org/viewcvs?rev=391905&view=rev
> Log:
> Cleaned up FileWatchdog implementation, added back
> configureAndWatch methods for DOMConfigurator and
> PropertyConfigurator, added more FileWatchdog related tests.
>
....
> URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/src/java/org/
> apache/log4j/spi/ConfiguratorEx.java?rev=391905&view=auto
> ======================================================================
> ========
> --- logging/log4j/trunk/src/java/org/apache/log4j/spi/
> ConfiguratorEx.java (added)
> +++ logging/log4j/trunk/src/java/org/apache/log4j/spi/
> ConfiguratorEx.java Wed Apr 5 22:32:38 2006
> @@ -0,0 +1,19 @@
> +package org.apache.log4j.spi;
> +
> +import java.io.InputStream;
> +
> +/**
> + * Defines extended methods for Configurators to implement.
> + *
> + * @author Mark Womack
> + * @since 1.3
> + */
> +public interface ConfiguratorEx {
> + /**
> + * Configures using an InputStream for input.
> + *
> + * @param stream
> + * @param repository
> + */
> + public void doConfigure(InputStream stream, LoggerRepository
> repository);
> +}
>
Using an InputStream is a problem since it would cause any XML
configuration that contained external entities to fail to parse. For
example, if you have a document like:
<!DOCTYPE log4j:configuration [
<!ENTITY stdAppenders SYSTEM 'stdAppenders.xml'>
]>
<log4j:configuration>
<!-- include standard appenders -->
&stdAppenders;
...
</log4j:configuration>
This document would successfully parse when
DOMConfigurator.configurator(File) is called but would fail on
DOMConfigurator(InputStream) since the base path needed to resolve
the relative file spec stdAppenders.xml is not provided. From
reading the code, I believe that configureAndWatch would likely
succeed on the initial configuration but would fail on any subsequent
configuration.
Using org.xml.sax.InputSource instead of java.io.InputStream may be
one way to address the problem.
---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-dev-unsubscribe@logging.apache.org
For additional commands, e-mail: log4j-dev-help@logging.apache.org
Re: svn commit: r391905 - in /logging/log4j/trunk: docs/ src/java/org/apache/log4j/ src/java/org/apache/log4j/joran/ src/java/org/apache/log4j/spi/ src/java/org/apache/log4j/watchdog/ src/java/org/apache/log4j/xml/ tests/input/watchdog/ tests/src/java/org/
Posted by Curt Arnold <ca...@apache.org>.
On Apr 6, 2006, at 12:36 AM, Mark Womack wrote:
> I checked in a bunch of changes. Hopefully it isn't more broken
> than before. The tests for FileWatchdog are just too intricate.
> The config file could be getting read by watchdog, so can't be
> deleted as required in the tests, so I had to add some code to loop
> on deleting. Then it seems that it can take some time for the
> appender buffer to flush to the file, etc. Most of this intricacy
> is because of the nature of the test. In real world usage I don't
> think it would be this complex.
>
> We'll see if Gump complains tonight.
>
> -Mark
Also, I'm not sure how the FileWatchdog stuff would interact with
restoring DOMConfigurator for log4j 1.2 compatibility (http://
issues.apache.org/bugzilla/show_bug.cgi?id=39024).
configureAndWatch has some very peculiar behavior and I don't think
it will carry over into log4j 2.0. So perhaps, restoring the 1.2
DOMConfigurator and omitting configureAndWatch from JoranConfigurator
would make all the FileWatchdog stuff moot.
---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-dev-unsubscribe@logging.apache.org
For additional commands, e-mail: log4j-dev-help@logging.apache.org
Re: svn commit: r391905 - in /logging/log4j/trunk: docs/ src/java/org/apache/log4j/ src/java/org/apache/log4j/joran/ src/java/org/apache/log4j/spi/ src/java/org/apache/log4j/watchdog/ src/java/org/apache/log4j/xml/ tests/input/watchdog/ tests/src/java/org/
Posted by Mark Womack <mw...@apache.org>.
I checked in a bunch of changes. Hopefully it isn't more broken than
before. The tests for FileWatchdog are just too intricate. The config file
could be getting read by watchdog, so can't be deleted as required in the
tests, so I had to add some code to loop on deleting. Then it seems that it
can take some time for the appender buffer to flush to the file, etc. Most
of this intricacy is because of the nature of the test. In real world usage
I don't think it would be this complex.
We'll see if Gump complains tonight.
-Mark
---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-dev-unsubscribe@logging.apache.org
For additional commands, e-mail: log4j-dev-help@logging.apache.org