diff options
6 files changed, 752 insertions, 54 deletions
diff --git a/qpid/java/broker/bin/qpid-server b/qpid/java/broker/bin/qpid-server index e5a9e998e2..7482ad63ef 100755 --- a/qpid/java/broker/bin/qpid-server +++ b/qpid/java/broker/bin/qpid-server @@ -23,6 +23,12 @@ if [ -z "$QPID_HOME" ]; then export PATH=${PATH}:${QPID_HOME}/bin fi +if [ -z "$QPID_LOG4J_SETTINGS" ]; then + # Disable the Log4J default initialization process, allowing the broker to + # perform the configuration using etc/log4j.xml + QPID_LOG4J_SETTINGS="-Dlog4j.defaultInitOverride=true" +fi + # Set classpath to include Qpid jar with all required jars in manifest QPID_LIBS=$QPID_HOME/lib/qpid-all.jar:$QPID_HOME/lib/bdbstore-launch.jar @@ -34,6 +40,6 @@ export JAVA=java \ QPID_CLASSPATH=$QPID_LIBS \ QPID_RUN_LOG=2 -QPID_OPTS="$QPID_OPTS -Damqj.read_write_pool_size=32" +QPID_OPTS="$QPID_OPTS $QPID_LOG4J_SETTINGS -Damqj.read_write_pool_size=32" . qpid-run org.apache.qpid.server.Main "$@" diff --git a/qpid/java/broker/bin/qpid-server.bat b/qpid/java/broker/bin/qpid-server.bat index 2687baa111..7fff183192 100755..100644 --- a/qpid/java/broker/bin/qpid-server.bat +++ b/qpid/java/broker/bin/qpid-server.bat @@ -20,6 +20,9 @@ @echo off
REM Script to run the Qpid Java Broker
+rem stop the Log4J default initialisation, let the broker do it using etc/log4j.xml
+if "%QPID_LOG4J_SETTINGS%" == "" set QPID_LOG4J_SETTINGS=-Dlog4j.defaultInitOverride=true
+
rem Guess QPID_HOME if not defined
set CURRENT_DIR=%cd%
if not "%QPID_HOME%" == "" goto gotHome
@@ -194,7 +197,7 @@ rem QPID_OPTS intended to hold any -D props for use rem user must enclose any value for QPID_OPTS in double quotes
:runCommand
set MODULE_JARS=%QPID_MODULE_JARS%
-set COMMAND="%JAVA_HOME%\bin\java" %JAVA_VM% %JAVA_MEM% %JAVA_GC% %QPID_OPTS% %SYSTEM_PROPS% -cp "%CLASSPATH%;%MODULE_JARS%" org.apache.qpid.server.Main %QPID_ARGS%
+set COMMAND="%JAVA_HOME%\bin\java" %JAVA_VM% %JAVA_MEM% %JAVA_GC% %QPID_OPTS% %QPID_LOG4J_SETTINGS% %SYSTEM_PROPS% -cp "%CLASSPATH%;%MODULE_JARS%" org.apache.qpid.server.Main %QPID_ARGS%
if "%debug%" == "true" echo %CLASSPATH%;%LAUNCH_JAR%;%MODULE_JARS%
if "%debug%" == "true" echo %COMMAND%
diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java b/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java new file mode 100644 index 0000000000..53134250ab --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java @@ -0,0 +1,250 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.log4j.xml; + +import java.io.File; +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.qpid.server.logging.management.LoggingManagementMBean; +import org.apache.qpid.server.logging.management.LoggingManagementMBean.QpidLog4JSaxErrorHandler; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; + +/** + * Substitute for the Log4J XMLWatchdog (as used by DOMConfigurator.configureAndWatch) + * + * Extends the default behaviour with a strict parser check on the XML file before allowing the reconfiguration to proceed, + * ensuring that any parser error or warning prevents initiation of a configuration update by Log4J, which aborts mid-update + * upon fatal errors from the parser and proceeds in the event of 'regular' parser errors and warnings, in all cases allowing + * startup to proceed with whatever half-baked configuration then exists. + */ +public class QpidLog4JConfigurator +{ + //lock to protect access to the configuration file + private static final ReentrantLock LOCK = new ReentrantLock(); + private static Logger _logger; + + private QpidLog4JConfigurator() + { + //no instances + } + + public static void configure(String filename) throws IOException, ParserConfigurationException, + SAXException, IllegalLoggerLevelException + { + try + { + LOCK.lock(); + + strictlyParseXMLConfigFile(filename); + checkLoggerLevels(filename); + + DOMConfigurator.configure(filename); + } + finally + { + LOCK.unlock(); + } + } + + public static void configureAndWatch(String filename, long delay) throws IOException, ParserConfigurationException, + SAXException, IllegalLoggerLevelException + { + strictlyParseXMLConfigFile(filename); + checkLoggerLevels(filename); + + QpidLog4JXMLWatchdog watchdog = new QpidLog4JXMLWatchdog(filename); + watchdog.setDelay(delay); + watchdog.start(); + } + + private static void strictlyParseXMLConfigFile(String fileName) throws IOException, SAXException, + ParserConfigurationException + { + try + { + LOCK.lock(); + + //check file was specified, exists, and is readable + if(fileName == null) + { + throw new IOException("Provided log4j XML configuration filename was null"); + } + + File configFile = new File(fileName); + + if (!configFile.exists()) + { + throw new IOException("The log4j XML configuration file does not exist: " + fileName); + } + else if (!configFile.canRead()) + { + throw new IOException("The log4j XML configuration file is not readable: " + fileName); + } + + //parse it + DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder; + + ErrorHandler errHandler = new QpidLog4JSaxErrorHandler(); + + docFactory.setValidating(true); + docBuilder = docFactory.newDocumentBuilder(); + docBuilder.setErrorHandler(errHandler); + docBuilder.setEntityResolver(new Log4jEntityResolver()); + docBuilder.parse(fileName); + } + finally + { + LOCK.unlock(); + } + } + + private static class QpidLog4JXMLWatchdog extends XMLWatchdog + { + public QpidLog4JXMLWatchdog(String filename) + { + super(filename); + } + + public void doOnChange() + { + try + { + LOCK.lock(); + + try + { + strictlyParseXMLConfigFile(filename); + } + catch (Exception e) + { + //logger will be instantiated following first configuration success, which has been pre-validated + //and so the null check should never actually be required. + if(_logger != null) + { + _logger.warn("Parsing the log4j XML configuration file generated errors/warnings. " + + "The new configuration was not applied. Correct the issues to prompt " + + "another update attempt: " + e.getMessage()); + } + return; + } + + try + { + checkLoggerLevels(filename); + } + catch (Exception e) + { + //logger will be instantiated following first configuration success, which has been pre-validated + //and so the null check should never actually be required. + if(_logger != null) + { + _logger.warn("Errors were found when validating the logger level values in the " + + "log4j XML configuration file. The new configuration was not applied. " + + "Correct the issues to prompt another update attempt: " + e.getMessage()); + } + return; + } + + //everything checked was ok, let the normal update process proceed + super.doOnChange(); + + //a configuration has now been applied, enable logging for future attempts + if(_logger == null) + { + _logger = Logger.getLogger(QpidLog4JConfigurator.class); + } + + _logger.info("Applied log4j configuration from: " + filename); + } + finally + { + LOCK.unlock(); + } + + } + } + + protected static void checkLoggerLevels(String filename) throws IllegalLoggerLevelException, IOException + { + //check that the logger levels specified in the XML are actually valid + + try + { + LOCK.lock(); + + Map<String, String> loggersLevels; + loggersLevels = LoggingManagementMBean.retrieveConfigFileLoggersLevels(filename); + + for (String loggerName : loggersLevels.keySet()) + { + String levelString = loggersLevels.get(loggerName); + checkLevel(loggerName,levelString); + } + + //check the root logger level + String rootLoggerlevelString = LoggingManagementMBean.retrieveConfigFileRootLoggerLevel(filename); + checkLevel("Root", rootLoggerlevelString); + } + finally + { + LOCK.unlock(); + } + } + + private static void checkLevel(String loggerName, String levelString) throws IllegalLoggerLevelException + { + if("null".equalsIgnoreCase(levelString) || "inherited".equalsIgnoreCase(levelString)) + { + //the string "null" signals to inherit from a parent logger + return; + } + + Level level = Level.toLevel(levelString); + + //above Level.toLevel call returns a DEBUG Level if the request fails. Check the result. + if (level.equals(Level.DEBUG) && !(levelString.equalsIgnoreCase("debug"))) + { + //received DEBUG but we did not ask for it, the Level request failed. + throw new IllegalLoggerLevelException("Level '" + levelString + "' specified for Logger '" + loggerName + "' is invalid"); + } + } + + public static class IllegalLoggerLevelException extends Exception + { + private static final long serialVersionUID = 1L; + + public IllegalLoggerLevelException(String msg) + { + super(msg); + } + } +} + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index eac027afc6..8566ba6270 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -27,9 +27,9 @@ import org.apache.commons.cli.OptionBuilder; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; -import org.apache.log4j.BasicConfigurator; import org.apache.log4j.Logger; -import org.apache.log4j.xml.DOMConfigurator; +import org.apache.log4j.PropertyConfigurator; +import org.apache.log4j.xml.QpidLog4JConfigurator; import org.apache.mina.common.ByteBuffer; import org.apache.mina.common.FixedSizeByteBufferAllocator; import org.apache.mina.common.IoAcceptor; @@ -56,9 +56,11 @@ import org.apache.qpid.server.transport.QpidAcceptor; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.net.BindException; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.util.Properties; /** * Main entry point for AMQPD. @@ -200,7 +202,7 @@ public class Main } catch (InitException e) { - System.out.println(e.getMessage()); + System.out.println("Initialisation Error : " + e.getMessage()); _brokerLogger.error("Initialisation Error : " + e.getMessage()); shutdown(1); } @@ -498,7 +500,7 @@ public class Main return ip; } - private void configureLogging(File logConfigFile, int logWatchTime) + private void configureLogging(File logConfigFile, int logWatchTime) throws InitException, IOException { if (logConfigFile.exists() && logConfigFile.canRead()) { @@ -509,18 +511,43 @@ public class Main System.out.println("log file " + logConfigFile.getAbsolutePath() + " will be checked for changes every " + logWatchTime + " seconds"); // log4j expects the watch interval in milliseconds - DOMConfigurator.configureAndWatch(logConfigFile.getAbsolutePath(), logWatchTime * 1000); + try + { + QpidLog4JConfigurator.configureAndWatch(logConfigFile.getPath(), logWatchTime * 1000); + } + catch (Exception e) + { + throw new InitException(e.getMessage(),e); + } } else { - DOMConfigurator.configure(logConfigFile.getAbsolutePath()); + try + { + QpidLog4JConfigurator.configure(logConfigFile.getPath()); + } + catch (Exception e) + { + throw new InitException(e.getMessage(),e); + } } } else { System.err.println("Logging configuration error: unable to read file " + logConfigFile.getAbsolutePath()); - System.err.println("Using basic log4j configuration"); - BasicConfigurator.configure(); + System.err.println("Using the fallback internal log4j.properties configuration"); + + InputStream propsFile = this.getClass().getResourceAsStream("/log4j.properties"); + if(propsFile == null) + { + throw new IOException("Unable to load the fallback internal log4j.properties configuration file"); + } + else + { + Properties fallbackProps = new Properties(); + fallbackProps.load(propsFile); + PropertyConfigurator.configure(fallbackProps); + } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java index 3cebb1353b..396e81e690 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java @@ -24,7 +24,9 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Enumeration; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.apache.qpid.management.common.mbeans.LoggingManagement; import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; @@ -34,6 +36,8 @@ import org.apache.log4j.Level; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.apache.log4j.xml.Log4jEntityResolver; +import org.apache.log4j.xml.QpidLog4JConfigurator; +import org.apache.log4j.xml.QpidLog4JConfigurator.IllegalLoggerLevelException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -244,46 +248,50 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM } //handler to catch errors signalled by the JAXP parser and throw an appropriate exception - private class SaxErrorHandler implements ErrorHandler + public static class QpidLog4JSaxErrorHandler implements ErrorHandler { - public void error(SAXParseException e) throws SAXException { - throw new SAXException("Error parsing XML file: " + e.getMessage()); + throw new SAXException(constructMessage("Error parsing XML file", e)); } public void fatalError(SAXParseException e) throws SAXException { - throw new SAXException("Fatal error parsing XML file: " + e.getMessage()); + throw new SAXException(constructMessage("Fatal error parsing XML file", e)); } public void warning(SAXParseException e) throws SAXException { - throw new SAXException("Warning parsing XML file: " + e.getMessage()); + throw new SAXException(constructMessage("Warning parsing XML file", e)); + } + + private static String constructMessage(final String msg, final SAXParseException ex) + { + return new String(msg + ": Line " + ex.getLineNumber()+" column " +ex.getColumnNumber() + ": " + ex.getMessage()); } } //method to parse the XML configuration file, validating it in the process, and returning a DOM Document of the content. - private synchronized Document parseConfigFile(String fileName) throws IOException + private static synchronized Document parseConfigFile(String fileName) throws IOException { //check file was specified, exists, and is readable if(fileName == null) { - _logger.warn("No log4j XML configuration file has been set"); - throw new IOException("No log4j XML configuration file has been set"); + _logger.warn("Provided log4j XML configuration filename is null"); + throw new IOException("Provided log4j XML configuration filename is null"); } File configFile = new File(fileName); if (!configFile.exists()) { - _logger.warn("Specified log4j XML configuration file does not exist: " + fileName); - throw new IOException("Specified log4j XML configuration file does not exist"); + _logger.warn("The log4j XML configuration file could not be found: " + fileName); + throw new IOException("The log4j XML configuration file could not be found"); } else if (!configFile.canRead()) { - _logger.warn("Specified log4j XML configuration file is not readable: " + fileName); - throw new IOException("Specified log4j XML configuration file is not readable"); + _logger.warn("The log4j XML configuration file is not readable: " + fileName); + throw new IOException("The log4j XML configuration file is not readable"); } //parse it @@ -291,7 +299,7 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM DocumentBuilder docBuilder; Document doc; - ErrorHandler errHandler = new SaxErrorHandler(); + ErrorHandler errHandler = new QpidLog4JSaxErrorHandler(); try { docFactory.setValidating(true); @@ -315,14 +323,14 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM catch (IOException e) { _logger.warn("Unable to parse the specified log4j XML file" + e); - throw new IOException("Unable to parse the specified log4j XML file", e); + throw new IOException("Unable to parse the specified log4j XML file: " + e.getMessage()); } return doc; } - private synchronized boolean writeUpdatedConfigFile(String log4jConfigFileName, Document doc) throws IOException + private static synchronized boolean writeUpdatedConfigFile(String log4jConfigFileName, Document doc) throws IOException { File log4jConfigFile = new File(log4jConfigFileName); @@ -389,20 +397,11 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM * and not the only possible child element. */ - - public synchronized TabularData viewConfigFileLoggerLevels() throws IOException + public static synchronized Map<String,String> retrieveConfigFileLoggersLevels(String fileName) throws IOException { - if (_loggerLevelTabularType == null) - { - _logger.warn("TabluarData type not set up correctly"); - return null; - } - - _logger.info("Getting logger levels from log4j configuration file"); - - Document doc = parseConfigFile(_log4jConfigFileName); + Document doc = parseConfigFile(fileName); - TabularData loggerLevelList = new TabularDataSupport(_loggerLevelTabularType); + HashMap<String,String> loggerLevelList = new HashMap<String,String>(); //retrieve the 'category' element nodes NodeList categoryElements = doc.getElementsByTagName("category"); @@ -436,17 +435,7 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM continue; } - try - { - Object[] itemData = {categoryName, priority}; - CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, COMPOSITE_ITEM_NAMES, itemData); - loggerLevelList.put(loggerData); - } - catch (OpenDataException e) - { - _logger.warn("Unable to create logger level list due to :" + e); - return null; - } + loggerLevelList.put(categoryName, priority); } //retrieve the 'logger' element nodes @@ -467,6 +456,30 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM Element levelElement = (Element) levelElements.item(0); level = levelElement.getAttribute("value").toUpperCase(); + loggerLevelList.put(loggerName, level); + } + + return loggerLevelList; + } + + public synchronized TabularData viewConfigFileLoggerLevels() throws IOException + { + if (_loggerLevelTabularType == null) + { + _logger.warn("TabluarData type not set up correctly"); + return null; + } + + _logger.info("Getting logger levels from log4j configuration file"); + + TabularData loggerLevelList = new TabularDataSupport(_loggerLevelTabularType); + + Map<String,String> levels = retrieveConfigFileLoggersLevels(_log4jConfigFileName); + + for (String loggerName : levels.keySet()) + { + String level = levels.get(loggerName); + try { Object[] itemData = {loggerName, level}; @@ -574,19 +587,17 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM * and not the only possible child element. */ - public synchronized String getConfigFileRootLoggerLevel() throws IOException + public static synchronized String retrieveConfigFileRootLoggerLevel(String fileName) throws IOException { - _logger.info("Getting root logger level from log4j configuration file"); - - Document doc = parseConfigFile(_log4jConfigFileName); + Document doc = parseConfigFile(fileName); //retrieve the optional 'root' element node NodeList rootElements = doc.getElementsByTagName("root"); if (rootElements.getLength() == 0) { - //there is not root logger definition - return null; + //there is no root logger definition + return "N/A"; } Element rootElement = (Element) rootElements.item(0); @@ -618,6 +629,11 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM } } + public synchronized String getConfigFileRootLoggerLevel() throws IOException + { + return retrieveConfigFileRootLoggerLevel(_log4jConfigFileName); + } + public synchronized boolean setConfigFileRootLoggerLevel(String level) throws IOException { //check that the specified level is a valid log4j Level diff --git a/qpid/java/broker/src/test/java/org/apache/log4j/xml/QpidLog4JConfiguratorTest.java b/qpid/java/broker/src/test/java/org/apache/log4j/xml/QpidLog4JConfiguratorTest.java new file mode 100644 index 0000000000..643f1fa48e --- /dev/null +++ b/qpid/java/broker/src/test/java/org/apache/log4j/xml/QpidLog4JConfiguratorTest.java @@ -0,0 +1,396 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.log4j.xml; + + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +import org.apache.log4j.xml.QpidLog4JConfigurator.IllegalLoggerLevelException; + +import junit.framework.TestCase; + +public class QpidLog4JConfiguratorTest extends TestCase +{ + private static final String NEWLINE = System.getProperty("line.separator"); + + private File _testConfigFile; + + private File createTempTestLog4JConfig(String loggerLevel,String rootLoggerLevel, boolean missingTagClose, boolean incorrectAttribute) + { + File tmpFile = null; + try + { + tmpFile = File.createTempFile("LogManMBeanTestLog4jConfig", ".tmp"); + tmpFile.deleteOnExit(); + + FileWriter fstream = new FileWriter(tmpFile); + BufferedWriter writer = new BufferedWriter(fstream); + + writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"+NEWLINE); + writer.write("<!DOCTYPE log4j:configuration SYSTEM \"log4j.dtd\">"+NEWLINE); + + writer.write("<log4j:configuration xmlns:log4j=\"http://jakarta.apache.org/log4j/\" debug=\"null\" " + + "threshold=\"null\">"+NEWLINE); + + writer.write(" <appender class=\"org.apache.log4j.ConsoleAppender\" name=\"STDOUT\">"+NEWLINE); + writer.write(" <layout class=\"org.apache.log4j.PatternLayout\">"+NEWLINE); + writer.write(" <param name=\"ConversionPattern\" value=\"%d %-5p [%t] %C{2} (%F:%L) - %m%n\"/>"+NEWLINE); + writer.write(" </layout>"+NEWLINE); + writer.write(" </appender>"+NEWLINE); + + String closeTag="/"; + if(missingTagClose) + { + closeTag=""; + } + + //Example of a 'category' with a 'priority' + writer.write(" <category additivity=\"true\" name=\"logger1\">"+NEWLINE); + writer.write(" <priority value=\"" + loggerLevel+ "\"" + closeTag + ">"+NEWLINE); + writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE); + writer.write(" </category>"+NEWLINE); + + String attributeName="value"; + if(incorrectAttribute) + { + attributeName="values"; + } + + //Example of a 'category' with a 'level' + writer.write(" <category additivity=\"true\" name=\"logger2\">"+NEWLINE); + writer.write(" <level " + attributeName + "=\"" + loggerLevel+ "\"/>"+NEWLINE); + writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE); + writer.write(" </category>"+NEWLINE); + + //Example of a 'logger' with a 'level' + writer.write(" <logger additivity=\"true\" name=\"logger3\">"+NEWLINE); + writer.write(" <level value=\"" + loggerLevel+ "\"/>"+NEWLINE); + writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE); + writer.write(" </logger>"+NEWLINE); + + //'root' logger + writer.write(" <root>"+NEWLINE); + writer.write(" <priority value=\"" + rootLoggerLevel+ "\"/>"+NEWLINE); + writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE); + writer.write(" </root>"+NEWLINE); + + writer.write("</log4j:configuration>"+NEWLINE); + + writer.flush(); + writer.close(); + } + catch (IOException e) + { + fail("Unable to create temporary test log4j configuration"); + } + + return tmpFile; + } + + + + //******* Test Methods ******* // + + public void testCheckLevelsAndStrictParser() + { + //try the valid logger levels + _testConfigFile = createTempTestLog4JConfig("all", "info", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("trace", "info", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("debug", "info", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("info", "info", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("warn", "info", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("error", "info", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("fatal", "info", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("off", "info", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("null", "info", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("inherited", "info", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + //now try an invalid logger level + _testConfigFile = createTempTestLog4JConfig("madeup", "info", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + fail("IllegalLoggerLevelException expected, invalid levels used"); + } + catch (IllegalLoggerLevelException e) + { + //expected, ignore + } + catch (IOException e) + { + fail("Incorrect Exception, expected an IllegalLoggerLevelException"); + } + + + + //now try the valid rootLogger levels + _testConfigFile = createTempTestLog4JConfig("info", "all", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("info", "trace", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("info", "debug", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("info", "info", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("info", "warn", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("info", "error", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("info", "fatal", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("info", "off", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("info", "null", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("info", "inherited", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("info", "debug", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + //now try an invalid logger level + _testConfigFile = createTempTestLog4JConfig("info", "madeup", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + fail("IllegalLoggerLevelException expected, invalid levels used"); + } + catch (IllegalLoggerLevelException e) + { + //expected, ignore + } + catch (IOException e) + { + fail("Incorrect Exception, expected an IllegalLoggerLevelException"); + } + + + + //now try invalid xml + _testConfigFile = createTempTestLog4JConfig("info", "info", true, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + fail("IOException expected, malformed XML used"); + } + catch (IllegalLoggerLevelException e) + { + fail("Incorrect Exception, expected an IOException"); + } + catch (IOException e) + { + //expected, ignore + } + + _testConfigFile = createTempTestLog4JConfig("info", "info", false, true); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + fail("IOException expected, malformed XML used"); + } + catch (IllegalLoggerLevelException e) + { + fail("Incorrect Exception, expected an IOException"); + } + catch (IOException e) + { + //expected, ignore + } + } +} |