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 ho...@apache.org on 2004/05/15 17:41:12 UTC
cvs commit: logging-log4j-sandbox/src/java/org/apache/log4j/servlet InitShutdownController.java
hoju 2004/05/15 08:41:12
Modified: src/java/org/apache/log4j/servlet
InitShutdownController.java
Log:
Improvements suggested by Andreas Werner (modularizing the methods and a few bug fixes), plus I now take care to modify the thread context class loader during initialization to avoid class cast exceptions based on the following article...
http://www-106.ibm.com/developerworks/websphere/library/techarticles/0310_searle/searle.html
Note that this class, currently, is meant to work with Log4j-1.2.8. The current CVS of Log4j-1.3.0 is not compatible. That should change in a future version.
Jake
Revision Changes Path
1.4 +254 -168 logging-log4j-sandbox/src/java/org/apache/log4j/servlet/InitShutdownController.java
Index: InitShutdownController.java
===================================================================
RCS file: /home/cvs/logging-log4j-sandbox/src/java/org/apache/log4j/servlet/InitShutdownController.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- InitShutdownController.java 28 Feb 2004 13:55:05 -0000 1.3
+++ InitShutdownController.java 15 May 2004 15:41:12 -0000 1.4
@@ -39,7 +39,9 @@
* and {@link InitServlet}, this class can be used by any class at runtime to
* control initialization and shutdown of Log4j loggers and appenders.</p>
*
+ * @see http://nagoya.apache.org/wiki/apachewiki.cgi?Log4JProjectPages/AppContainerLogging
* @author <a href="mailto:hoju@visi.com">Jacob Kjome</a>
+ * @author Andreas Werner
* @since 1.3
*/
public class InitShutdownController {
@@ -107,155 +109,237 @@
* @param context the current servlet context
*/
public static void initializeLog4j(final ServletContext context) {
+ ClassLoader savedClassLoader = null;
+
+ try {
+ savedClassLoader = Thread.currentThread().getContextClassLoader();
+
+ //attempt to set the thread context class loader to the current class
+ //loader to avoid ClassCastExceptions when this library is in a parent
+ //class loader (along with log4j.jar) and a webapp includes log4j.jar
+ //in WEB-INF/lib, but not this library (assuming they aren't both in
+ //log4j.jar).
+ //based on the following article...
+ //http://www-106.ibm.com/developerworks/websphere/library/techarticles/0310_searle/searle.html
+ Thread.currentThread().setContextClassLoader(
+ InitShutdownController.class.getClassLoader());
+ } catch (SecurityException se) {
+ //oh, well, we tried. Security is turned on and we aren't allowed to
+ //tamper with the thread context class loader. You're on your own!
+ }
+
+ try {
+ //Attempt to set the repository selector no matter what else happens
+ setSelector(context);
+
+ String configPath = getLog4jConfigPathFromContext(context);
+
+ if ((configPath != null) && (configPath.length() >= 1)) {
+ setLog4jLogHome(context);
+
+ if (context.getRealPath("/") != null) {
+ configureLog4jFromFile(configPath, context);
+ } else {
+ configureLog4jFromURL(configPath, context);
+ }
+ } else {
+ if (configPath == null) {
+ LogLog.error("Missing log4j-config servlet parameter missing.");
+ } else {
+ LogLog.error("Zero length Log4j config file path given.");
+ }
+
+ displayConfigNotFoundMessage();
+ }
+ } finally {
+ if (savedClassLoader != null) {
+ //reset the thread context class loader to the original saved class
+ //loader now that our purpose (avoiding class cast exceptions) has been
+ //served
+ Thread.currentThread().setContextClassLoader(savedClassLoader);
+ }
+ }
+ }
+
+ /**
+ * Determines the path to log4j config file from the servlet context param
+ * 'logj4-config'. The path is assumed to be relative to the current context.
+ * If set, the path is normalized with any preceeding slash removed as the
+ * other methods expect the path to be formatted this way.
+ *
+ * @param context The servlet context
+ * @return the path to the log4j config file within the context or null if
+ * the 'log4j-config' context param is not set.
+ */
+ private static String getLog4jConfigPathFromContext(
+ final ServletContext context) {
String configPath = context.getInitParameter(PARAM_LOG4J_CONFIG_PATH);
- // if the log4j-config parameter is not set, then no point in trying
if (configPath != null) {
if (configPath.startsWith("/")) {
configPath = (configPath.length() > 1) ? configPath.substring(1) : "";
}
+ }
- // if the configPath is an empty string, then no point in trying
- if (configPath.length() >= 1) {
- // set up log path System property
- String logHome = context.getInitParameter(PARAM_LOG4J_LOG_HOME);
-
- if (logHome != null) {
- // set up custom log path system property
- setFileAppenderSystemProperty(logHome, context);
- }
+ return configPath;
+ }
- boolean isXMLConfigFile = (configPath.endsWith(".xml")) ? true : false;
- String contextPath = context.getRealPath("/");
+ /**
+ * Determines the log4j home to use. If the context parameter
+ * 'log4j-log-home' is set, this is used as the environment variable.
+ * Otherwise the the default 'WEB-INF/logs' is used.
+ *
+ * @param context the current servlet context
+ */
+ private static void setLog4jLogHome(final ServletContext context) {
+ // set up log path System property
+ String logHome = context.getInitParameter(PARAM_LOG4J_LOG_HOME);
+
+ if (logHome != null) {
+ // set up custom log path system property
+ setFileAppenderSystemProperty(logHome, context);
+ } else {
+ String contextPath = context.getRealPath("/");
- if (contextPath != null) {
- // The webapp is deployed directly off the filesystem,
- // not from a .war file so we *can* do File IO.
- // This means we can use configureAndWatch() to re-read
- // the the config file at defined intervals.
- // Now let's check if the given configPath actually exists.
- if (logHome == null) {
- // no log path specified in web.xml. Setting to default
- logHome = contextPath + DEFAULT_LOG_HOME;
- setFileAppenderSystemProperty(logHome, context);
- }
-
- String systemConfigPath =
- configPath.replace('/', File.separatorChar);
- File log4jFile = new File(contextPath + systemConfigPath);
-
- if (log4jFile.canRead()) {
- log4jFile = null;
-
- String timerInterval =
- context.getInitParameter(PARAM_LOG4J_WATCH_INTERVAL);
- long timerIntervalVal = 0L;
-
- if (timerInterval != null) {
- try {
- timerIntervalVal = Integer.valueOf(timerInterval).longValue();
- } catch (NumberFormatException nfe) {
- //ignore...we just won't use configureAndWatch if there is no
- //valid int
- ;
- }
- }
-
- setSelector(context);
- context.log(
- "Configuring Log4j from File: " + contextPath + systemConfigPath);
-
- if (timerIntervalVal > 0) {
- context.log(
- "Configuring Log4j with watch interval: " + timerIntervalVal
- + "ms");
-
- if (isXMLConfigFile) {
- DOMConfigurator.configureAndWatch(
- contextPath + systemConfigPath, timerIntervalVal);
- } else {
- PropertyConfigurator.configureAndWatch(
- contextPath + systemConfigPath, timerIntervalVal);
- }
- } else {
- if (isXMLConfigFile) {
- DOMConfigurator.configure(contextPath + systemConfigPath);
- } else {
- PropertyConfigurator.configure(contextPath + systemConfigPath);
- }
- }
- } else {
- //The given configPath does not exist. So, let's just let Log4j
- //look for the default files (log4j.properties or log4j.xml) on
- //its own.
- displayConfigNotFoundMessage();
- }
+ if (contextPath != null) {
+ //no log path specified in web.xml. Setting to default within current
+ //context path
+ logHome = contextPath + DEFAULT_LOG_HOME;
+ setFileAppenderSystemProperty(logHome, context);
+ }
+ }
+ }
- //end log4jFile.canRead() check
- } else {
- //The webapp is deployed from a .war file, not directly
- //off the file system so we *cannot* do File IO.
- //Note that we *won't* be able to use configureAndWatch() here
- //because that requires an absolute system file path.
- //Now let's check if the given configPath actually exists.
- URL log4jURL = null;
-
- try {
- log4jURL = context.getResource("/" + configPath);
- } catch (MalformedURLException murle) {
- //ignore...we check for null later
- ;
- }
-
- if (log4jURL != null) {
- setSelector(context);
- context.log("Configuring Log4j from URL at path: /" + configPath);
-
- if (isXMLConfigFile) {
- try {
- DOMConfigurator.configure(log4jURL);
-
- //catch (javax.xml.parsers.FactoryConfigurationError fce) {}
- } catch (Exception e) {
- //report errors to server logs
- LogLog.error(e.getMessage());
- }
- } else {
- Properties log4jProps = new Properties();
-
- try {
- log4jProps.load(log4jURL.openStream());
- PropertyConfigurator.configure(log4jProps);
-
- //catch (java.io.IOException ioe) {}
- } catch (Exception e) {
- //report errors to server logs
- LogLog.error(e.getMessage());
- }
- }
- } else {
- //The given configPath does not exist. So, let's just let Log4j
- //look for the default files (log4j.properties or log4j.xml) on
- //its own.
- displayConfigNotFoundMessage();
- }
+ /**
+ * Configures log4j via url
+ *
+ * @param configPath the location of the log4j configuration file
+ * relative to the context path
+ * @param context the current servlet context
+ */
+ private static void configureLog4jFromURL(
+ final String configPath, final ServletContext context) {
+ //The webapp is deployed from a .war file, not directly off the file system
+ //so we *cannot* do File IO. Note that we *won't* be able to use
+ //configureAndWatch() here because that requires an absolute system file
+ //path.
+ boolean isXMLConfigFile = (configPath.endsWith(".xml")) ? true : false;
+
+ URL log4jURL = null;
+
+ try {
+ log4jURL = context.getResource("/" + configPath);
+ } catch (MalformedURLException murle) {
+ //ignore...we check for null later
+ ;
+ }
- //end log4jURL null check
- }
+ //Now let's check if the given configPath actually exists.
+ if (log4jURL != null) {
+ context.log("Configuring Log4j from URL at path: /" + configPath);
+
+ if (isXMLConfigFile) {
+ try {
+ DOMConfigurator.configure(log4jURL);
- //end contextPath null check
+ //catch (javax.xml.parsers.FactoryConfigurationError fce) {}
+ } catch (Exception e) {
+ //report errors to server logs
+ LogLog.error(e.getMessage());
+ }
} else {
- LogLog.error("Zero length Log4j config file path given.");
- displayConfigNotFoundMessage();
+ Properties log4jProps = new Properties();
+
+ try {
+ log4jProps.load(log4jURL.openStream());
+ PropertyConfigurator.configure(log4jProps);
+
+ //catch (java.io.IOException ioe) {}
+ } catch (Exception e) {
+ //report errors to server logs
+ LogLog.error(e.getMessage());
+ }
}
+ } else {
+ //The given configPath does not exist. So, let's just let Log4j look for
+ //the default files (log4j.properties or log4j.xml) on its own.
+ displayConfigNotFoundMessage();
+ }
+ }
+
+ /**
+ * Configures log4j from a File
+ *
+ * @param systemConfigPath the fully qualified system path location of the
+ * log4j configuration file
+ * @param context the current servlet context
+ */
+ private static void configureLog4jFromFile(
+ final String configPath, final ServletContext context) {
+ //The webapp is deployed directly off the filesystem, not from a .war file
+ //so we *can* do File IO. This means we can use configureAndWatch() to
+ //re-read the the config file at defined intervals.
+ boolean isXMLConfigFile = (configPath.endsWith(".xml")) ? true : false;
+
+ String contextPath = context.getRealPath("/");
+ String systemConfigPath = configPath.replace('/', File.separatorChar);
+ File log4jFile = new File(contextPath + systemConfigPath);
+
+ //Now let's check if the given configPath actually exists.
+ if (log4jFile.canRead()) {
+ log4jFile = null;
- //end configPath length check
+ long timerIntervalVal = getTimerIntervalFromContext(context);
+ context.log(
+ "Configuring Log4j from File: " + contextPath + systemConfigPath);
+
+ if (timerIntervalVal > 0) {
+ context.log(
+ "Configuring Log4j with watch interval: " + timerIntervalVal + "ms");
+
+ if (isXMLConfigFile) {
+ DOMConfigurator.configureAndWatch(
+ contextPath + systemConfigPath, timerIntervalVal);
+ } else {
+ PropertyConfigurator.configureAndWatch(
+ contextPath + systemConfigPath, timerIntervalVal);
+ }
+ } else {
+ if (isXMLConfigFile) {
+ DOMConfigurator.configure(contextPath + systemConfigPath);
+ } else {
+ PropertyConfigurator.configure(contextPath + systemConfigPath);
+ }
+ }
} else {
- LogLog.error("Missing log4j-config servlet parameter missing.");
+ // The given configPath does not exist. So, let's just
+ // let Log4j look for the default files (
+ // log4j.properties or log4j.xml) on its own.
displayConfigNotFoundMessage();
}
+ }
- //end configPath null check
+ /**
+ * Retrieves the timer interval from the servlet context.
+ *
+ * @param context the current servlet context
+ */
+ private static long getTimerIntervalFromContext(
+ final ServletContext context) {
+ String timerInterval =
+ context.getInitParameter(PARAM_LOG4J_WATCH_INTERVAL);
+ long timerIntervalVal = 0L;
+
+ if (timerInterval != null) {
+ try {
+ timerIntervalVal = Integer.valueOf(timerInterval).longValue();
+ } catch (NumberFormatException nfe) {
+ //ignore...we just won't use configureAndWatch if there is no valid int
+ ;
+ }
+ }
+
+ return timerIntervalVal;
}
/**
@@ -277,52 +361,54 @@
final String logHome, final ServletContext context) {
String logHomePropName = null;
String customPropName = context.getInitParameter(PARAM_LOG4J_SYSPROP_NAME);
+ File logHomeDir = new File(logHome);
- if (customPropName != null) {
- logHomePropName = customPropName;
- } else {
- File logHomeDir = new File(logHome);
-
- if (logHomeDir.exists() || logHomeDir.mkdirs()) {
- /*String tempdir =
- "" + context.getAttribute("javax.servlet.context.tempdir");
- int lastSlash = tempdir.lastIndexOf(File.separator);
-
- if ((tempdir.length() - 1) > lastSlash) {
- logHomePropName = tempdir.substring(lastSlash + 1) + ".log.home";
- }*/
- String contextPath = "";
-
- try {
- //use a more standard way to obtain the context path name
- //which should work across all servers. The tmpdir technique
- //(above) depends upon the naming scheme that Tomcat uses.
- String path = context.getResource("/").getPath();
-
- //first remove trailing slash, then take what's left over
- //which should be the context path less the preceeding
- //slash such as "MyContext"
- contextPath = path.substring(0, path.lastIndexOf("/"));
- contextPath =
- contextPath.substring(contextPath.lastIndexOf("/") + 1);
- } catch (Exception e) {
- ;
- }
-
- logHomePropName = contextPath + ".log.home";
+ if (logHomeDir.exists() || logHomeDir.mkdirs()) {
+ if (customPropName != null) {
+ logHomePropName = customPropName;
+ } else {
+ logHomePropName = getContextPath(context) + ".log.home";
}
- }
- if (logHomePropName != null) {
context.log(
"Setting system property [ " + logHomePropName + " ] to [ " + logHome
+ " ]");
System.setProperty(logHomePropName, logHome);
- } else {
- context.log(
- "Unable to derive log4j system property name. Consider setting the "
- + "\"log4j-sysprop-name\" context parameter. No system property set.");
}
+ }
+
+ /**
+ * Retrieves the context path of the web application from the servlet context.
+ *
+ * @param context the current servlet context
+ * @return the derived context path, guaranteed non-null
+ */
+ private static String getContextPath(final ServletContext context) {
+ //old way to determine context path
+ //String tempdir = "" +
+ //context.getAttribute("javax.servlet.context.tempdir");
+ //int lastSlash = tempdir.lastIndexOf(File.separator);
+ //if ((tempdir.length() - 1) > lastSlash) {
+ // logHomePropName = tempdir.substring(lastSlash + 1) + ".log.home";
+ //}
+ String contextPath = "";
+
+ try {
+ //use a more standard way to obtain the context path name
+ //which should work across all servers. The tmpdir technique
+ //(above) depends upon the naming scheme that Tomcat uses.
+ String path = context.getResource("/").getPath();
+
+ //first remove trailing slash, then take what's left over
+ //which should be the context path less the preceeding
+ //slash such as "MyContext"
+ contextPath = path.substring(0, path.lastIndexOf("/"));
+ contextPath = contextPath.substring(contextPath.lastIndexOf("/") + 1);
+ } catch (Exception e) {
+ ;
+ }
+
+ return contextPath;
}
/**
---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-dev-unsubscribe@logging.apache.org
For additional commands, e-mail: log4j-dev-help@logging.apache.org