From 7baf23b894093bcf83fe396b34a37ddf4fd80997 Mon Sep 17 00:00:00 2001 From: Keith Wall Date: Fri, 21 Sep 2012 12:34:14 +0000 Subject: QPID-4313: Address review comments from QPID-4109 (Reenable LoggingManagement) git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1388457 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/jmx/JMXService.java | 4 +- .../server/jmx/mbeans/LoggingManagementMBean.java | 53 +- .../jmx/mbeans/LoggingManagementMBeanTest.java | 6 +- .../management/jmx/LoggingManagementTest.java | 4 +- .../main/java/org/apache/qpid/server/Broker.java | 6 +- .../qpid/server/logging/log4j/LoggingFacade.java | 579 --------------------- .../logging/log4j/LoggingManagementFacade.java | 579 +++++++++++++++++++++ .../server/logging/log4j/LoggingFacadeTest.java | 245 --------- .../logging/log4j/LoggingManagementFacadeTest.java | 245 +++++++++ 9 files changed, 863 insertions(+), 858 deletions(-) delete mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/log4j/LoggingFacade.java create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/logging/log4j/LoggingManagementFacade.java delete mode 100644 qpid/java/broker/src/test/java/org/apache/qpid/server/logging/log4j/LoggingFacadeTest.java create mode 100644 qpid/java/broker/src/test/java/org/apache/qpid/server/logging/log4j/LoggingManagementFacadeTest.java (limited to 'qpid/java') diff --git a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXService.java b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXService.java index 7a232d2584..c1049fa3a0 100644 --- a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXService.java +++ b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXService.java @@ -39,7 +39,7 @@ import org.apache.qpid.server.jmx.mbeans.ConfigurationManagementMBean; import org.apache.qpid.server.jmx.mbeans.ServerInformationMBean; import org.apache.qpid.server.jmx.mbeans.Shutdown; import org.apache.qpid.server.jmx.mbeans.VirtualHostMBean; -import org.apache.qpid.server.logging.log4j.LoggingFacade; +import org.apache.qpid.server.logging.log4j.LoggingManagementFacade; import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.ConfigurationChangeListener; import org.apache.qpid.server.model.ConfiguredObject; @@ -83,7 +83,7 @@ public class JMXService implements ConfigurationChangeListener _shutdown = new Shutdown(_objectRegistry); _serverInfo = new ServerInformationMBean(_objectRegistry, _broker); _configManagement = new ConfigurationManagementMBean(_objectRegistry); - _loggingManagement = new LoggingManagementMBean(LoggingFacade.getCurrentInstance(), _objectRegistry); + _loggingManagement = new LoggingManagementMBean(LoggingManagementFacade.getCurrentInstance(), _objectRegistry); } public void start() throws IOException, ConfigurationException diff --git a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/LoggingManagementMBean.java b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/LoggingManagementMBean.java index 0dac8ebe37..d6f4b5d8c9 100644 --- a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/LoggingManagementMBean.java +++ b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/LoggingManagementMBean.java @@ -26,7 +26,7 @@ import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; import org.apache.qpid.server.jmx.AMQManagedObject; import org.apache.qpid.server.jmx.ManagedObject; import org.apache.qpid.server.jmx.ManagedObjectRegistry; -import org.apache.qpid.server.logging.log4j.LoggingFacade; +import org.apache.qpid.server.logging.log4j.LoggingManagementFacade; import org.apache.qpid.server.logging.log4j.LoggingFacadeException; import javax.management.JMException; @@ -55,7 +55,8 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM private static final TabularType LOGGER_LEVEL_TABULAR_TYE; private static final CompositeType LOGGER_LEVEL_COMPOSITE_TYPE; - private final LoggingFacade _configurator; + private final LoggingManagementFacade _loggingManagementFacade; + private final String[] _allAvailableLogLevels; static { @@ -77,12 +78,13 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM throw new ExceptionInInitializerError(e); } } - - public LoggingManagementMBean(LoggingFacade configurator, ManagedObjectRegistry registry) throws JMException + + public LoggingManagementMBean(LoggingManagementFacade loggingManagementFacade, ManagedObjectRegistry registry) throws JMException { super(LoggingManagement.class, LoggingManagement.TYPE, registry); register(); - _configurator = configurator; + _loggingManagementFacade = loggingManagementFacade; + _allAvailableLogLevels = buildAllAvailableLoggerLevelsWithInheritedPsuedoLogLevel(_loggingManagementFacade); } @Override @@ -100,30 +102,26 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM @Override public Integer getLog4jLogWatchInterval() { - return _configurator.getLog4jLogWatchInterval(); + return _loggingManagementFacade.getLog4jLogWatchInterval(); } @Override public String[] getAvailableLoggerLevels() { - List levels = _configurator.getAvailableLoggerLevels(); - List mbeanLevels = new ArrayList(levels); - mbeanLevels.add(INHERITED_PSUEDO_LOG_LEVEL); - - return mbeanLevels.toArray(new String[mbeanLevels.size()]); + return _allAvailableLogLevels; } @Override public TabularData viewEffectiveRuntimeLoggerLevels() { - Map levels = _configurator.retrieveRuntimeLoggersLevels(); + Map levels = _loggingManagementFacade.retrieveRuntimeLoggersLevels(); return createTabularDataFromLevelsMap(levels); } @Override public String getRuntimeRootLoggerLevel() { - return _configurator.retrieveRuntimeRootLoggerLevel(); + return _loggingManagementFacade.retrieveRuntimeRootLoggerLevel(); } @Override @@ -139,7 +137,7 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM return false; } - _configurator.setRuntimeRootLoggerLevel(level); + _loggingManagementFacade.setRuntimeRootLoggerLevel(level); return true; } @@ -159,7 +157,7 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM try { - _configurator.setRuntimeLoggerLevel(logger, validatedLevel); + _loggingManagementFacade.setRuntimeLoggerLevel(logger, validatedLevel); } catch (LoggingFacadeException e) { @@ -175,7 +173,7 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM Map levels; try { - levels = _configurator.retrieveConfigFileLoggersLevels(); + levels = _loggingManagementFacade.retrieveConfigFileLoggersLevels(); } catch (LoggingFacadeException e) { @@ -191,7 +189,7 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM { try { - return _configurator.retrieveConfigFileRootLoggerLevel().toUpperCase(); + return _loggingManagementFacade.retrieveConfigFileRootLoggerLevel().toUpperCase(); } catch (LoggingFacadeException e) { @@ -216,7 +214,7 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM try { - _configurator.setConfigFileLoggerLevel(logger, validatedLevel); + _loggingManagementFacade.setConfigFileLoggerLevel(logger, validatedLevel); } catch (LoggingFacadeException e) { @@ -241,7 +239,7 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM try { - _configurator.setConfigFileRootLoggerLevel(level); + _loggingManagementFacade.setConfigFileRootLoggerLevel(level); return true; } catch (LoggingFacadeException e) @@ -257,7 +255,7 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM try { - _configurator.reload(); + _loggingManagementFacade.reload(); } catch (LoggingFacadeException e) { @@ -283,9 +281,8 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM private void validateLevelNotAllowingInherited(String level) { - final List availableLoggerLevels = _configurator.getAvailableLoggerLevels(); - if (!availableLoggerLevels.contains(level) - && !availableLoggerLevels.contains(String.valueOf(level).toUpperCase())) + final List availableLoggerLevels = _loggingManagementFacade.getAvailableLoggerLevels(); + if (level == null || !availableLoggerLevels.contains(level.toUpperCase())) { throw new IllegalArgumentException(level + " not known"); } @@ -305,7 +302,6 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM return loggerLevelList; } - private CompositeData createRow(String loggerName, String level) { Object[] itemData = {loggerName, level.toUpperCase()}; @@ -321,4 +317,13 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM throw new RuntimeException(ode); } } + + private String[] buildAllAvailableLoggerLevelsWithInheritedPsuedoLogLevel(LoggingManagementFacade loggingManagementFacade) + { + List levels = loggingManagementFacade.getAvailableLoggerLevels(); + List mbeanLevels = new ArrayList(levels); + mbeanLevels.add(INHERITED_PSUEDO_LOG_LEVEL); + + return mbeanLevels.toArray(new String[mbeanLevels.size()]); + } } diff --git a/qpid/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/LoggingManagementMBeanTest.java b/qpid/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/LoggingManagementMBeanTest.java index ae1be5db00..0f33e78d03 100644 --- a/qpid/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/LoggingManagementMBeanTest.java +++ b/qpid/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/LoggingManagementMBeanTest.java @@ -39,7 +39,7 @@ import junit.framework.TestCase; import org.apache.qpid.management.common.mbeans.LoggingManagement; import org.apache.qpid.server.jmx.ManagedObjectRegistry; -import org.apache.qpid.server.logging.log4j.LoggingFacade; +import org.apache.qpid.server.logging.log4j.LoggingManagementFacade; public class LoggingManagementMBeanTest extends TestCase { @@ -47,13 +47,13 @@ public class LoggingManagementMBeanTest extends TestCase private static final String TEST_LEVEL2 = "LEVEL2"; private LoggingManagementMBean _loggingMBean; - private LoggingFacade _mockLoggingFacade; + private LoggingManagementFacade _mockLoggingFacade; private ManagedObjectRegistry _mockManagedObjectRegistry; @Override protected void setUp() throws Exception { - _mockLoggingFacade = mock(LoggingFacade.class); + _mockLoggingFacade = mock(LoggingManagementFacade.class); final List listOfLevels = new ArrayList() {{ add(TEST_LEVEL1); diff --git a/qpid/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/LoggingManagementTest.java b/qpid/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/LoggingManagementTest.java index ac6730638e..0f374b67d5 100644 --- a/qpid/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/LoggingManagementTest.java +++ b/qpid/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/LoggingManagementTest.java @@ -26,7 +26,7 @@ import javax.management.openmbean.TabularData; import org.apache.qpid.management.common.mbeans.LoggingManagement; import org.apache.qpid.server.jmx.mbeans.LoggingManagementMBeanTest; -import org.apache.qpid.server.logging.log4j.LoggingFacadeTest; +import org.apache.qpid.server.logging.log4j.LoggingManagementFacadeTest; import org.apache.qpid.test.utils.JMXTestUtils; import org.apache.qpid.test.utils.QpidBrokerTestCase; import org.apache.qpid.util.FileUtils; @@ -37,7 +37,7 @@ import org.apache.qpid.util.LogMonitor; * test-profiles/log4j-test.xml. * * @see LoggingManagementMBeanTest - * @see LoggingFacadeTest + * @see LoggingManagementFacadeTest * */ public class LoggingManagementTest extends QpidBrokerTestCase diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Broker.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Broker.java index e92da34a49..afb8a0029b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Broker.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Broker.java @@ -36,7 +36,7 @@ import org.apache.qpid.server.logging.SystemOutMessageLogger; import org.apache.qpid.server.logging.actors.BrokerActor; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.GenericActor; -import org.apache.qpid.server.logging.log4j.LoggingFacade; +import org.apache.qpid.server.logging.log4j.LoggingManagementFacade; import org.apache.qpid.server.logging.messages.BrokerMessages; import org.apache.qpid.server.protocol.AmqpProtocolVersion; import org.apache.qpid.server.protocol.MultiVersionProtocolEngineFactory; @@ -458,7 +458,7 @@ public class Broker // log4j expects the watch interval in milliseconds try { - LoggingFacade.configureAndWatch(logConfigFile.getPath(), logWatchTime * 1000); + LoggingManagementFacade.configureAndWatch(logConfigFile.getPath(), logWatchTime * 1000); } catch (Exception e) { @@ -469,7 +469,7 @@ public class Broker { try { - LoggingFacade.configure(logConfigFile.getPath()); + LoggingManagementFacade.configure(logConfigFile.getPath()); } catch (Exception e) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/log4j/LoggingFacade.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/log4j/LoggingFacade.java deleted file mode 100644 index 931171b175..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/log4j/LoggingFacade.java +++ /dev/null @@ -1,579 +0,0 @@ -/* - * - * 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.qpid.server.logging.log4j; - -import org.apache.log4j.Level; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; -import org.apache.log4j.xml.DOMConfigurator; -import org.apache.log4j.xml.Log4jEntityResolver; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.xml.sax.ErrorHandler; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerConfigurationException; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; - -import java.io.File; -import java.io.FileOutputStream; -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 java.util.Random; - -/** - * A facade over log4j that allows both the control of the runtime logging behaviour (that is, the ability to - * turn {@link Logger} on, off and control their {@link Level}, and the manipulation and reload - * of the log4j configuration file. - */ -public class LoggingFacade -{ - private static Logger LOGGER; - private static transient LoggingFacade _instance; - private final String _filename; - private final int _delay; - - public static LoggingFacade configure(String filename) throws LoggingFacadeException - { - _instance = new LoggingFacade(filename); - return _instance; - } - - public static LoggingFacade configureAndWatch(String filename, int delay) throws LoggingFacadeException - { - _instance = new LoggingFacade(filename, delay); - return _instance; - } - - public static LoggingFacade getCurrentInstance() - { - return _instance; - } - - private LoggingFacade(String filename) - { - DOMConfigurator.configure(filename); - - if(LOGGER == null) - { - LOGGER = Logger.getLogger(LoggingFacade.class); - } - _filename = filename; - _delay = 0; - } - - private LoggingFacade(String filename, int delay) - { - DOMConfigurator.configureAndWatch(filename, delay); - - if(LOGGER == null) - { - LOGGER = Logger.getLogger(LoggingFacade.class); - } - - _filename = filename; - _delay = delay; - } - - public int getLog4jLogWatchInterval() - { - return _delay; - } - - public synchronized void reload() throws LoggingFacadeException - { - DOMConfigurator.configure(_filename); - } - - /** The log4j XML configuration file DTD defines three possible element - * combinations for specifying optional logger+level settings. - * Must account for the following: - * - * OR - * OR - * - * - * Noting also that the level/priority child element is optional too, - * and not the only possible child element. - */ - public synchronized Map retrieveConfigFileLoggersLevels() throws LoggingFacadeException - { - try - { - Map loggerLevelList = new HashMap(); - LOGGER.info("Getting logger levels from log4j configuration file"); - - Document doc = parseConfigFile(_filename); - List categoryOrLoggerElements = buildListOfCategoryOrLoggerElements(doc); - - for (Element categoryOrLogger : categoryOrLoggerElements) - { - - Element priorityOrLevelElement; - try - { - priorityOrLevelElement = getPriorityOrLevelElement(categoryOrLogger); - } - catch (LoggingFacadeException lfe) - { - //there is no exiting priority or level to view, move onto next category/logger - continue; - } - - String categoryName = categoryOrLogger.getAttribute("name"); - String priorityOrLevelValue = priorityOrLevelElement.getAttribute("value"); - loggerLevelList.put(categoryName, priorityOrLevelValue); - } - - return loggerLevelList; - } - catch (IOException e) - { - throw new LoggingFacadeException(e); - } - } - - /** - * The log4j XML configuration file DTD defines 2 possible element - * combinations for specifying the optional root logger level settings - * Must account for the following: - * - * OR - * - * - * Noting also that the level/priority child element is optional too, - * and not the only possible child element. - */ - public synchronized String retrieveConfigFileRootLoggerLevel() throws LoggingFacadeException - { - try - { - Document doc = parseConfigFile(_filename); - - //retrieve the optional 'root' element node - NodeList rootElements = doc.getElementsByTagName("root"); - - if (rootElements.getLength() == 0) - { - //there is no root logger definition - return "N/A"; - } - - Element rootElement = (Element) rootElements.item(0); - Element levelElement = getPriorityOrLevelElement(rootElement); - - if(levelElement != null) - { - return levelElement.getAttribute("value"); - } - else - { - return "N/A"; - } - } - catch (IOException e) - { - throw new LoggingFacadeException(e); - } - } - - public synchronized void setConfigFileLoggerLevel(String logger, String level) throws LoggingFacadeException - { - LOGGER.info("Setting level to " + level + " for logger '" + logger - + "' in log4j xml configuration file: " + _filename); - - try - { - Document doc = parseConfigFile(_filename); - - List logElements = buildListOfCategoryOrLoggerElements(doc); - - //try to locate the specified logger/category in the elements retrieved - Element logElement = null; - for (Element e : logElements) - { - if (e.getAttribute("name").equals(logger)) - { - logElement = e; - break; - } - } - - if (logElement == null) - { - throw new LoggingFacadeException("Can't find logger " + logger); - } - - Element levelElement = getPriorityOrLevelElement(logElement); - - //update the element with the new level/priority - levelElement.setAttribute("value", level); - - //output the new file - writeUpdatedConfigFile(_filename, doc); - } - catch (IOException ioe) - { - throw new LoggingFacadeException(ioe); - } - catch (TransformerConfigurationException e) - { - throw new LoggingFacadeException(e); - } - } - - public synchronized void setConfigFileRootLoggerLevel(String level) throws LoggingFacadeException - { - try - { - LOGGER.info("Setting level to " + level + " for the Root logger in " + - "log4j xml configuration file: " + _filename); - - Document doc = parseConfigFile(_filename); - - //retrieve the optional 'root' element node - NodeList rootElements = doc.getElementsByTagName("root"); - - if (rootElements.getLength() == 0) - { - throw new LoggingFacadeException("Configuration contains no root element"); - } - - Element rootElement = (Element) rootElements.item(0); - Element levelElement = getPriorityOrLevelElement(rootElement); - - //update the element with the new level/priority - levelElement.setAttribute("value", level); - - //output the new file - writeUpdatedConfigFile(_filename, doc); - } - catch (IOException e) - { - throw new LoggingFacadeException(e); - } - catch (TransformerConfigurationException e) - { - throw new LoggingFacadeException(e); - } - } - - public List getAvailableLoggerLevels() - { - return new ArrayList() - {{ - add(Level.ALL.toString()); - add(Level.TRACE.toString()); - add(Level.DEBUG.toString()); - add(Level.INFO.toString()); - add(Level.WARN.toString()); - add(Level.ERROR.toString()); - add(Level.FATAL.toString()); - add(Level.OFF.toString()); - }}; - } - - public String retrieveRuntimeRootLoggerLevel() - { - Logger rootLogger = Logger.getRootLogger(); - return rootLogger.getLevel().toString(); - } - - public void setRuntimeRootLoggerLevel(String level) - { - Level newLevel = Level.toLevel(level); - - LOGGER.info("Setting RootLogger level to " + level); - - Logger log = Logger.getRootLogger(); - log.setLevel(newLevel); - } - - public void setRuntimeLoggerLevel(String loggerName, String level) throws LoggingFacadeException - { - Level newLevel = level == null ? null : Level.toLevel(level); - - Logger targetLogger = findRuntimeLogger(loggerName); - - if(targetLogger == null) - { - throw new LoggingFacadeException("Can't find logger " + loggerName); - } - - LOGGER.info("Setting level to " + newLevel + " for logger '" + targetLogger.getName() + "'"); - - targetLogger.setLevel(newLevel); - } - - public Map retrieveRuntimeLoggersLevels() - { - LOGGER.info("Getting levels for currently active log4j loggers"); - - Map levels = new HashMap(); - @SuppressWarnings("unchecked") - Enumeration loggers = LogManager.getCurrentLoggers(); - - while (loggers.hasMoreElements()) - { - Logger logger = loggers.nextElement(); - levels.put(logger.getName(), logger.getEffectiveLevel().toString()); - } - - return levels; - } - - private void writeUpdatedConfigFile(String log4jConfigFileName, Document doc) throws IOException, TransformerConfigurationException - { - File log4jConfigFile = new File(log4jConfigFileName); - - if (!log4jConfigFile.canWrite()) - { - LOGGER.warn("Specified log4j XML configuration file is not writable: " + log4jConfigFile); - throw new IOException("Specified log4j XML configuration file is not writable"); - } - - Transformer transformer = null; - transformer = TransformerFactory.newInstance().newTransformer(); - - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "log4j.dtd"); - DOMSource source = new DOMSource(doc); - - File tmp; - Random r = new Random(); - - do - { - tmp = new File(log4jConfigFile.getAbsolutePath() + r.nextInt() + ".tmp"); - } - while(tmp.exists()); - - tmp.deleteOnExit(); - - try - { - StreamResult result = new StreamResult(new FileOutputStream(tmp)); - transformer.transform(source, result); - } - catch (TransformerException e) - { - LOGGER.warn("Could not transform the XML into new file: ", e); - throw new IOException("Could not transform the XML into new file: ", e); - } - - // Swap temp file in to replace existing configuration file. - File old = new File(log4jConfigFile.getAbsoluteFile() + ".old"); - if (old.exists()) - { - old.delete(); - } - - if(!log4jConfigFile.renameTo(old)) - { - //unable to rename the existing file to the backup name - LOGGER.error("Could not backup the existing log4j XML file"); - throw new IOException("Could not backup the existing log4j XML file"); - } - - if(!tmp.renameTo(log4jConfigFile)) - { - //failed to rename the new file to the required filename - - if(!old.renameTo(log4jConfigFile)) - { - //unable to return the backup to required filename - LOGGER.error("Could not rename the new log4j configuration file into place, and unable to restore original file"); - throw new IOException("Could not rename the new log4j configuration file into place, and unable to restore original file"); - } - - LOGGER.error("Could not rename the new log4j configuration file into place"); - throw new IOException("Could not rename the new log4j configuration file into place"); - } - } - - //method to parse the XML configuration file, validating it in the process, and returning a DOM Document of the content. - private static Document parseConfigFile(String fileName) throws IOException - { - //check file was specified, exists, and is readable - if(fileName == null) - { - 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("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("The log4j XML configuration file is not readable: " + fileName); - throw new IOException("The log4j XML configuration file is not readable"); - } - - //parse it - DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder docBuilder; - Document doc; - - ErrorHandler errHandler = new QpidLog4JSaxErrorHandler(); - try - { - docFactory.setValidating(true); - docBuilder = docFactory.newDocumentBuilder(); - docBuilder.setErrorHandler(errHandler); - docBuilder.setEntityResolver(new Log4jEntityResolver()); - doc = docBuilder.parse(fileName); - } - catch (ParserConfigurationException e) - { - LOGGER.warn("Unable to parse the log4j XML file due to possible configuration error: ", e); - throw new IOException("Unable to parse the log4j XML file due to possible configuration error: ", e); - } - catch (SAXException e) - { - LOGGER.warn("The specified log4j XML file is invalid: ", e); - throw new IOException("The specified log4j XML file is invalid: ", e); - } - 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); - } - - return doc; - } - - private Logger findRuntimeLogger(String loggerName) - { - Logger targetLogger = null; - @SuppressWarnings("unchecked") - Enumeration loggers = LogManager.getCurrentLoggers(); - while(loggers.hasMoreElements()) - { - targetLogger = loggers.nextElement(); - if (targetLogger.getName().equals(loggerName)) - { - return targetLogger; - } - } - return null; - } - - private List buildListOfCategoryOrLoggerElements(Document doc) - { - //retrieve the 'category' and 'logger' element nodes - NodeList categoryElements = doc.getElementsByTagName("category"); - NodeList loggerElements = doc.getElementsByTagName("logger"); - - //collect them into a single elements list - List logElements = new ArrayList(); - - for (int i = 0; i < categoryElements.getLength(); i++) - { - logElements.add((Element) categoryElements.item(i)); - } - for (int i = 0; i < loggerElements.getLength(); i++) - { - logElements.add((Element) loggerElements.item(i)); - } - return logElements; - } - - private Element getPriorityOrLevelElement(Element categoryOrLogger) throws LoggingFacadeException - { - //retrieve the optional 'priority' or 'level' sub-element value. - //It may not be the only child node, so request by tag name. - NodeList priorityElements = categoryOrLogger.getElementsByTagName("priority"); - NodeList levelElements = categoryOrLogger.getElementsByTagName("level"); - - Element levelElement = null; - if (priorityElements.getLength() != 0) - { - levelElement = (Element) priorityElements.item(0); - } - else if (levelElements.getLength() != 0) - { - levelElement = (Element) levelElements.item(0); - } - else - { - throw new LoggingFacadeException("Configuration " + categoryOrLogger.getNodeName() - + " element contains neither priority nor level child"); - } - return levelElement; - } - - private static class QpidLog4JSaxErrorHandler implements ErrorHandler - { - public void error(SAXParseException e) throws SAXException - { - if(LOGGER != null) - { - LOGGER.warn(constructMessage("Error parsing XML file", e)); - } - else - { - System.err.println(constructMessage("Error parsing XML file", e)); - } - } - - public void fatalError(SAXParseException e) throws SAXException - { - throw new SAXException(constructMessage("Fatal error parsing XML file", e)); - } - - public void warning(SAXParseException e) throws SAXException - { - if(LOGGER != null) - { - LOGGER.warn(constructMessage("Warning parsing XML file", e)); - } - else - { - System.err.println(constructMessage("Warning parsing XML file", e)); - } - } - - private static String constructMessage(final String msg, final SAXParseException ex) - { - return msg + ": Line " + ex.getLineNumber()+" column " +ex.getColumnNumber() + ": " + ex.getMessage(); - } - } -} - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/log4j/LoggingManagementFacade.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/log4j/LoggingManagementFacade.java new file mode 100644 index 0000000000..6a961c8fa4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/log4j/LoggingManagementFacade.java @@ -0,0 +1,579 @@ +/* + * + * 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.qpid.server.logging.log4j; + +import org.apache.log4j.Level; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.apache.log4j.xml.DOMConfigurator; +import org.apache.log4j.xml.Log4jEntityResolver; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import java.io.File; +import java.io.FileOutputStream; +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 java.util.Random; + +/** + * A facade over log4j that allows both the control of the runtime logging behaviour (that is, the ability to + * turn {@link Logger} on, off and control their {@link Level}, and the manipulation and reload + * of the log4j configuration file. + */ +public class LoggingManagementFacade +{ + private static Logger LOGGER; + private static transient LoggingManagementFacade _instance; + private final String _filename; + private final int _delay; + + public static LoggingManagementFacade configure(String filename) throws LoggingFacadeException + { + _instance = new LoggingManagementFacade(filename); + return _instance; + } + + public static LoggingManagementFacade configureAndWatch(String filename, int delay) throws LoggingFacadeException + { + _instance = new LoggingManagementFacade(filename, delay); + return _instance; + } + + public static LoggingManagementFacade getCurrentInstance() + { + return _instance; + } + + private LoggingManagementFacade(String filename) + { + DOMConfigurator.configure(filename); + + if(LOGGER == null) + { + LOGGER = Logger.getLogger(LoggingManagementFacade.class); + } + _filename = filename; + _delay = 0; + } + + private LoggingManagementFacade(String filename, int delay) + { + DOMConfigurator.configureAndWatch(filename, delay); + + if(LOGGER == null) + { + LOGGER = Logger.getLogger(LoggingManagementFacade.class); + } + + _filename = filename; + _delay = delay; + } + + public int getLog4jLogWatchInterval() + { + return _delay; + } + + public synchronized void reload() throws LoggingFacadeException + { + DOMConfigurator.configure(_filename); + } + + /** The log4j XML configuration file DTD defines three possible element + * combinations for specifying optional logger+level settings. + * Must account for the following: + * + * OR + * OR + * + * + * Noting also that the level/priority child element is optional too, + * and not the only possible child element. + */ + public synchronized Map retrieveConfigFileLoggersLevels() throws LoggingFacadeException + { + try + { + Map loggerLevelList = new HashMap(); + LOGGER.info("Getting logger levels from log4j configuration file"); + + Document doc = parseConfigFile(_filename); + List categoryOrLoggerElements = buildListOfCategoryOrLoggerElements(doc); + + for (Element categoryOrLogger : categoryOrLoggerElements) + { + + Element priorityOrLevelElement; + try + { + priorityOrLevelElement = getPriorityOrLevelElement(categoryOrLogger); + } + catch (LoggingFacadeException lfe) + { + //there is no exiting priority or level to view, move onto next category/logger + continue; + } + + String categoryName = categoryOrLogger.getAttribute("name"); + String priorityOrLevelValue = priorityOrLevelElement.getAttribute("value"); + loggerLevelList.put(categoryName, priorityOrLevelValue); + } + + return loggerLevelList; + } + catch (IOException e) + { + throw new LoggingFacadeException(e); + } + } + + /** + * The log4j XML configuration file DTD defines 2 possible element + * combinations for specifying the optional root logger level settings + * Must account for the following: + * + * OR + * + * + * Noting also that the level/priority child element is optional too, + * and not the only possible child element. + */ + public synchronized String retrieveConfigFileRootLoggerLevel() throws LoggingFacadeException + { + try + { + Document doc = parseConfigFile(_filename); + + //retrieve the optional 'root' element node + NodeList rootElements = doc.getElementsByTagName("root"); + + if (rootElements.getLength() == 0) + { + //there is no root logger definition + return "N/A"; + } + + Element rootElement = (Element) rootElements.item(0); + Element levelElement = getPriorityOrLevelElement(rootElement); + + if(levelElement != null) + { + return levelElement.getAttribute("value"); + } + else + { + return "N/A"; + } + } + catch (IOException e) + { + throw new LoggingFacadeException(e); + } + } + + public synchronized void setConfigFileLoggerLevel(String logger, String level) throws LoggingFacadeException + { + LOGGER.info("Setting level to " + level + " for logger '" + logger + + "' in log4j xml configuration file: " + _filename); + + try + { + Document doc = parseConfigFile(_filename); + + List logElements = buildListOfCategoryOrLoggerElements(doc); + + //try to locate the specified logger/category in the elements retrieved + Element logElement = null; + for (Element e : logElements) + { + if (e.getAttribute("name").equals(logger)) + { + logElement = e; + break; + } + } + + if (logElement == null) + { + throw new LoggingFacadeException("Can't find logger " + logger); + } + + Element levelElement = getPriorityOrLevelElement(logElement); + + //update the element with the new level/priority + levelElement.setAttribute("value", level); + + //output the new file + writeUpdatedConfigFile(_filename, doc); + } + catch (IOException ioe) + { + throw new LoggingFacadeException(ioe); + } + catch (TransformerConfigurationException e) + { + throw new LoggingFacadeException(e); + } + } + + public synchronized void setConfigFileRootLoggerLevel(String level) throws LoggingFacadeException + { + try + { + LOGGER.info("Setting level to " + level + " for the Root logger in " + + "log4j xml configuration file: " + _filename); + + Document doc = parseConfigFile(_filename); + + //retrieve the optional 'root' element node + NodeList rootElements = doc.getElementsByTagName("root"); + + if (rootElements.getLength() == 0) + { + throw new LoggingFacadeException("Configuration contains no root element"); + } + + Element rootElement = (Element) rootElements.item(0); + Element levelElement = getPriorityOrLevelElement(rootElement); + + //update the element with the new level/priority + levelElement.setAttribute("value", level); + + //output the new file + writeUpdatedConfigFile(_filename, doc); + } + catch (IOException e) + { + throw new LoggingFacadeException(e); + } + catch (TransformerConfigurationException e) + { + throw new LoggingFacadeException(e); + } + } + + public List getAvailableLoggerLevels() + { + return new ArrayList() + {{ + add(Level.ALL.toString()); + add(Level.TRACE.toString()); + add(Level.DEBUG.toString()); + add(Level.INFO.toString()); + add(Level.WARN.toString()); + add(Level.ERROR.toString()); + add(Level.FATAL.toString()); + add(Level.OFF.toString()); + }}; + } + + public String retrieveRuntimeRootLoggerLevel() + { + Logger rootLogger = Logger.getRootLogger(); + return rootLogger.getLevel().toString(); + } + + public void setRuntimeRootLoggerLevel(String level) + { + Level newLevel = Level.toLevel(level); + + LOGGER.info("Setting RootLogger level to " + level); + + Logger log = Logger.getRootLogger(); + log.setLevel(newLevel); + } + + public void setRuntimeLoggerLevel(String loggerName, String level) throws LoggingFacadeException + { + Level newLevel = level == null ? null : Level.toLevel(level); + + Logger targetLogger = findRuntimeLogger(loggerName); + + if(targetLogger == null) + { + throw new LoggingFacadeException("Can't find logger " + loggerName); + } + + LOGGER.info("Setting level to " + newLevel + " for logger '" + targetLogger.getName() + "'"); + + targetLogger.setLevel(newLevel); + } + + public Map retrieveRuntimeLoggersLevels() + { + LOGGER.info("Getting levels for currently active log4j loggers"); + + Map levels = new HashMap(); + @SuppressWarnings("unchecked") + Enumeration loggers = LogManager.getCurrentLoggers(); + + while (loggers.hasMoreElements()) + { + Logger logger = loggers.nextElement(); + levels.put(logger.getName(), logger.getEffectiveLevel().toString()); + } + + return levels; + } + + private void writeUpdatedConfigFile(String log4jConfigFileName, Document doc) throws IOException, TransformerConfigurationException + { + File log4jConfigFile = new File(log4jConfigFileName); + + if (!log4jConfigFile.canWrite()) + { + LOGGER.warn("Specified log4j XML configuration file is not writable: " + log4jConfigFile); + throw new IOException("Specified log4j XML configuration file is not writable"); + } + + Transformer transformer = null; + transformer = TransformerFactory.newInstance().newTransformer(); + + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "log4j.dtd"); + DOMSource source = new DOMSource(doc); + + File tmp; + Random r = new Random(); + + do + { + tmp = new File(log4jConfigFile.getAbsolutePath() + r.nextInt() + ".tmp"); + } + while(tmp.exists()); + + tmp.deleteOnExit(); + + try + { + StreamResult result = new StreamResult(new FileOutputStream(tmp)); + transformer.transform(source, result); + } + catch (TransformerException e) + { + LOGGER.warn("Could not transform the XML into new file: ", e); + throw new IOException("Could not transform the XML into new file: ", e); + } + + // Swap temp file in to replace existing configuration file. + File old = new File(log4jConfigFile.getAbsoluteFile() + ".old"); + if (old.exists()) + { + old.delete(); + } + + if(!log4jConfigFile.renameTo(old)) + { + //unable to rename the existing file to the backup name + LOGGER.error("Could not backup the existing log4j XML file"); + throw new IOException("Could not backup the existing log4j XML file"); + } + + if(!tmp.renameTo(log4jConfigFile)) + { + //failed to rename the new file to the required filename + + if(!old.renameTo(log4jConfigFile)) + { + //unable to return the backup to required filename + LOGGER.error("Could not rename the new log4j configuration file into place, and unable to restore original file"); + throw new IOException("Could not rename the new log4j configuration file into place, and unable to restore original file"); + } + + LOGGER.error("Could not rename the new log4j configuration file into place"); + throw new IOException("Could not rename the new log4j configuration file into place"); + } + } + + //method to parse the XML configuration file, validating it in the process, and returning a DOM Document of the content. + private static Document parseConfigFile(String fileName) throws IOException + { + //check file was specified, exists, and is readable + if(fileName == null) + { + 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("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("The log4j XML configuration file is not readable: " + fileName); + throw new IOException("The log4j XML configuration file is not readable"); + } + + //parse it + DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder; + Document doc; + + ErrorHandler errHandler = new QpidLog4JSaxErrorHandler(); + try + { + docFactory.setValidating(true); + docBuilder = docFactory.newDocumentBuilder(); + docBuilder.setErrorHandler(errHandler); + docBuilder.setEntityResolver(new Log4jEntityResolver()); + doc = docBuilder.parse(fileName); + } + catch (ParserConfigurationException e) + { + LOGGER.warn("Unable to parse the log4j XML file due to possible configuration error: ", e); + throw new IOException("Unable to parse the log4j XML file due to possible configuration error: ", e); + } + catch (SAXException e) + { + LOGGER.warn("The specified log4j XML file is invalid: ", e); + throw new IOException("The specified log4j XML file is invalid: ", e); + } + 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); + } + + return doc; + } + + private Logger findRuntimeLogger(String loggerName) + { + Logger targetLogger = null; + @SuppressWarnings("unchecked") + Enumeration loggers = LogManager.getCurrentLoggers(); + while(loggers.hasMoreElements()) + { + targetLogger = loggers.nextElement(); + if (targetLogger.getName().equals(loggerName)) + { + return targetLogger; + } + } + return null; + } + + private List buildListOfCategoryOrLoggerElements(Document doc) + { + //retrieve the 'category' and 'logger' element nodes + NodeList categoryElements = doc.getElementsByTagName("category"); + NodeList loggerElements = doc.getElementsByTagName("logger"); + + //collect them into a single elements list + List logElements = new ArrayList(); + + for (int i = 0; i < categoryElements.getLength(); i++) + { + logElements.add((Element) categoryElements.item(i)); + } + for (int i = 0; i < loggerElements.getLength(); i++) + { + logElements.add((Element) loggerElements.item(i)); + } + return logElements; + } + + private Element getPriorityOrLevelElement(Element categoryOrLogger) throws LoggingFacadeException + { + //retrieve the optional 'priority' or 'level' sub-element value. + //It may not be the only child node, so request by tag name. + NodeList priorityElements = categoryOrLogger.getElementsByTagName("priority"); + NodeList levelElements = categoryOrLogger.getElementsByTagName("level"); + + Element levelElement = null; + if (priorityElements.getLength() != 0) + { + levelElement = (Element) priorityElements.item(0); + } + else if (levelElements.getLength() != 0) + { + levelElement = (Element) levelElements.item(0); + } + else + { + throw new LoggingFacadeException("Configuration " + categoryOrLogger.getNodeName() + + " element contains neither priority nor level child"); + } + return levelElement; + } + + private static class QpidLog4JSaxErrorHandler implements ErrorHandler + { + public void error(SAXParseException e) throws SAXException + { + if(LOGGER != null) + { + LOGGER.warn(constructMessage("Error parsing XML file", e)); + } + else + { + System.err.println(constructMessage("Error parsing XML file", e)); + } + } + + public void fatalError(SAXParseException e) throws SAXException + { + throw new SAXException(constructMessage("Fatal error parsing XML file", e)); + } + + public void warning(SAXParseException e) throws SAXException + { + if(LOGGER != null) + { + LOGGER.warn(constructMessage("Warning parsing XML file", e)); + } + else + { + System.err.println(constructMessage("Warning parsing XML file", e)); + } + } + + private static String constructMessage(final String msg, final SAXParseException ex) + { + return msg + ": Line " + ex.getLineNumber()+" column " +ex.getColumnNumber() + ": " + ex.getMessage(); + } + } +} + diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/log4j/LoggingFacadeTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/log4j/LoggingFacadeTest.java deleted file mode 100644 index f871baffe6..0000000000 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/log4j/LoggingFacadeTest.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * 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.qpid.server.logging.log4j; - -import java.io.File; -import java.util.List; -import java.util.Map; - -import org.apache.log4j.Level; -import org.apache.qpid.util.FileUtils; - -import junit.framework.TestCase; - -public class LoggingFacadeTest extends TestCase -{ - private LoggingFacade _loggingFacade; - private String _log4jXmlFile; - - @Override - protected void setUp() throws Exception - { - super.setUp(); - _log4jXmlFile = createTestLog4jXml(); - _loggingFacade = LoggingFacade.configure(_log4jXmlFile); - } - - public void testGetAvailableLoggerLevels() throws Exception - { - List levels = _loggingFacade.getAvailableLoggerLevels(); - assertTrue(levels.contains("ALL")); - assertTrue(levels.contains("TRACE")); - assertTrue(levels.contains("DEBUG")); - assertTrue(levels.contains("INFO")); - assertTrue(levels.contains("WARN")); - assertTrue(levels.contains("ERROR")); - assertTrue(levels.contains("FATAL")); - assertTrue(levels.contains("OFF")); - assertEquals(8, levels.size()); - } - - public void testRetrieveConfigFileRootLoggerLevel() throws Exception - { - String level = _loggingFacade.retrieveConfigFileRootLoggerLevel(); - assertEquals(Level.WARN.toString(), level); - } - - public void testSetConfigFileRootLoggerLevel() throws Exception - { - String oldLevel = _loggingFacade.retrieveConfigFileRootLoggerLevel(); - assertEquals("WARN", oldLevel); - - _loggingFacade.setConfigFileRootLoggerLevel("INFO"); - - String level = _loggingFacade.retrieveConfigFileRootLoggerLevel(); - assertEquals("INFO", level); - } - - public void testRetrieveConfigFileLoggerLevels() throws Exception - { - Map levels = _loggingFacade.retrieveConfigFileLoggersLevels(); - assertEquals(3, levels.size()); - String abcLevel = levels.get("a.b.c"); - String abc1Level = levels.get("a.b.c.1"); - String abc2Level = levels.get("a.b.c.2"); - assertEquals("INFO", abcLevel); - assertEquals("DEBUG", abc1Level); - assertEquals("TRACE", abc2Level); - } - - public void testSetConfigFileLoggerLevels() throws Exception - { - final String loggerName = "a.b.c"; - - assertConfigFileLoggingLevel(loggerName, "INFO"); - - _loggingFacade.setConfigFileLoggerLevel(loggerName, "WARN"); - - Map levels = _loggingFacade.retrieveConfigFileLoggersLevels(); - String abcLevel = levels.get(loggerName); - assertEquals("WARN", abcLevel); - } - - public void testSetConfigFileLoggerLevelsWhereLoggerDoesNotExist() throws Exception - { - try - { - _loggingFacade.setConfigFileLoggerLevel("does.not.exist", "WARN"); - fail("Exception not thrown"); - } - catch (LoggingFacadeException lfe) - { - // PASS - assertEquals("Can't find logger does.not.exist", lfe.getMessage()); - } - } - - public void testRetrieveRuntimeRootLoggerLevel() throws Exception - { - String level = _loggingFacade.retrieveRuntimeRootLoggerLevel(); - assertEquals(Level.WARN.toString(), level); - } - - public void testSetRuntimeRootLoggerLevel() throws Exception - { - String oldLevel = _loggingFacade.retrieveRuntimeRootLoggerLevel(); - assertEquals("WARN", oldLevel); - - _loggingFacade.setRuntimeRootLoggerLevel("INFO"); - - String level = _loggingFacade.retrieveRuntimeRootLoggerLevel(); - assertEquals("INFO", level); - } - - public void testRetrieveRuntimeLoggersLevels() throws Exception - { - Map levels = _loggingFacade.retrieveRuntimeLoggersLevels(); - // Don't assert size as implementation itself uses logging and we'd count its loggers too - String abcLevel = levels.get("a.b.c"); - String abc1Level = levels.get("a.b.c.1"); - String abc2Level = levels.get("a.b.c.2"); - assertEquals("INFO", abcLevel); - assertEquals("DEBUG", abc1Level); - assertEquals("TRACE", abc2Level); - } - - public void testSetRuntimeLoggerLevel() throws Exception - { - final String loggerName = "a.b.c"; - - assertRuntimeLoggingLevel(loggerName, "INFO"); - - _loggingFacade.setRuntimeLoggerLevel(loggerName, "WARN"); - - assertRuntimeLoggingLevel(loggerName, "WARN"); - } - - public void testSetRuntimeLoggerToInheritFromParent() throws Exception - { - final String parentLoggerName = "a.b.c"; - final String childLoggerName = "a.b.c.1"; - - assertRuntimeLoggingLevel(parentLoggerName, "INFO"); - assertRuntimeLoggingLevel(childLoggerName, "DEBUG"); - - _loggingFacade.setRuntimeLoggerLevel(childLoggerName, null); - - assertRuntimeLoggingLevel(parentLoggerName, "INFO"); - assertRuntimeLoggingLevel(childLoggerName, "INFO"); - } - - public void testSetRuntimeLoggerLevelsWhereLoggerDoesNotExist() throws Exception - { - final String loggerName = "does.not.exist2"; - - Map oldLevels = _loggingFacade.retrieveRuntimeLoggersLevels(); - assertFalse(oldLevels.containsKey(loggerName)); - - try - { - _loggingFacade.setRuntimeLoggerLevel(loggerName, "WARN"); - fail("Exception not thrown"); - } - catch (LoggingFacadeException lfe) - { - // PASS - assertEquals("Can't find logger " + loggerName, lfe.getMessage()); - } - - Map levels = _loggingFacade.retrieveRuntimeLoggersLevels(); - assertFalse(levels.containsKey(loggerName)); - } - - public void testReloadOfChangedLog4JFileUpdatesRuntimeLogLevel() throws Exception - { - final String loggerName = "a.b.c"; - - assertRuntimeLoggingLevel(loggerName, "INFO"); - assertConfigFileLoggingLevel(loggerName, "INFO"); - - _loggingFacade.setConfigFileLoggerLevel(loggerName, "WARN"); - - assertRuntimeLoggingLevel(loggerName, "INFO"); - - _loggingFacade.reload(); - - assertRuntimeLoggingLevel(loggerName, "WARN"); - } - - - public void testReloadOfLog4JFileRevertsRuntimeChanges() throws Exception - { - final String loggerName = "a.b.c"; - - assertRuntimeLoggingLevel(loggerName, "INFO"); - assertConfigFileLoggingLevel(loggerName, "INFO"); - - _loggingFacade.setRuntimeLoggerLevel(loggerName, "WARN"); - - assertRuntimeLoggingLevel(loggerName, "WARN"); - - _loggingFacade.reload(); - - assertRuntimeLoggingLevel(loggerName, "INFO"); - } - - private void assertConfigFileLoggingLevel(final String loggerName, String expectedLevel) throws Exception - { - Map levels = _loggingFacade.retrieveConfigFileLoggersLevels(); - String actualLevel = levels.get(loggerName); - assertEquals(expectedLevel, actualLevel); - } - - private void assertRuntimeLoggingLevel(final String loggerName, String expectedLevel) throws Exception - { - Map levels = _loggingFacade.retrieveRuntimeLoggersLevels(); - String actualLevel = levels.get(loggerName); - assertEquals(expectedLevel, actualLevel); - } - - private String createTestLog4jXml() throws Exception - { - File dst = File.createTempFile("log4j." + getName(), "xml"); - File filename = new File(getClass().getResource("LoggingFacadeTest.log4j.xml").toURI()); - FileUtils.copy(filename, dst); - dst.deleteOnExit(); - return dst.getAbsolutePath(); - } -} diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/log4j/LoggingManagementFacadeTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/log4j/LoggingManagementFacadeTest.java new file mode 100644 index 0000000000..6cb9d9b2e6 --- /dev/null +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/log4j/LoggingManagementFacadeTest.java @@ -0,0 +1,245 @@ +/* + * 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.qpid.server.logging.log4j; + +import java.io.File; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Level; +import org.apache.qpid.util.FileUtils; + +import junit.framework.TestCase; + +public class LoggingManagementFacadeTest extends TestCase +{ + private LoggingManagementFacade _loggingFacade; + private String _log4jXmlFile; + + @Override + protected void setUp() throws Exception + { + super.setUp(); + _log4jXmlFile = createTestLog4jXml(); + _loggingFacade = LoggingManagementFacade.configure(_log4jXmlFile); + } + + public void testGetAvailableLoggerLevels() throws Exception + { + List levels = _loggingFacade.getAvailableLoggerLevels(); + assertTrue(levels.contains("ALL")); + assertTrue(levels.contains("TRACE")); + assertTrue(levels.contains("DEBUG")); + assertTrue(levels.contains("INFO")); + assertTrue(levels.contains("WARN")); + assertTrue(levels.contains("ERROR")); + assertTrue(levels.contains("FATAL")); + assertTrue(levels.contains("OFF")); + assertEquals(8, levels.size()); + } + + public void testRetrieveConfigFileRootLoggerLevel() throws Exception + { + String level = _loggingFacade.retrieveConfigFileRootLoggerLevel(); + assertEquals(Level.WARN.toString(), level); + } + + public void testSetConfigFileRootLoggerLevel() throws Exception + { + String oldLevel = _loggingFacade.retrieveConfigFileRootLoggerLevel(); + assertEquals("WARN", oldLevel); + + _loggingFacade.setConfigFileRootLoggerLevel("INFO"); + + String level = _loggingFacade.retrieveConfigFileRootLoggerLevel(); + assertEquals("INFO", level); + } + + public void testRetrieveConfigFileLoggerLevels() throws Exception + { + Map levels = _loggingFacade.retrieveConfigFileLoggersLevels(); + assertEquals(3, levels.size()); + String abcLevel = levels.get("a.b.c"); + String abc1Level = levels.get("a.b.c.1"); + String abc2Level = levels.get("a.b.c.2"); + assertEquals("INFO", abcLevel); + assertEquals("DEBUG", abc1Level); + assertEquals("TRACE", abc2Level); + } + + public void testSetConfigFileLoggerLevels() throws Exception + { + final String loggerName = "a.b.c"; + + assertConfigFileLoggingLevel(loggerName, "INFO"); + + _loggingFacade.setConfigFileLoggerLevel(loggerName, "WARN"); + + Map levels = _loggingFacade.retrieveConfigFileLoggersLevels(); + String abcLevel = levels.get(loggerName); + assertEquals("WARN", abcLevel); + } + + public void testSetConfigFileLoggerLevelsWhereLoggerDoesNotExist() throws Exception + { + try + { + _loggingFacade.setConfigFileLoggerLevel("does.not.exist", "WARN"); + fail("Exception not thrown"); + } + catch (LoggingFacadeException lfe) + { + // PASS + assertEquals("Can't find logger does.not.exist", lfe.getMessage()); + } + } + + public void testRetrieveRuntimeRootLoggerLevel() throws Exception + { + String level = _loggingFacade.retrieveRuntimeRootLoggerLevel(); + assertEquals(Level.WARN.toString(), level); + } + + public void testSetRuntimeRootLoggerLevel() throws Exception + { + String oldLevel = _loggingFacade.retrieveRuntimeRootLoggerLevel(); + assertEquals("WARN", oldLevel); + + _loggingFacade.setRuntimeRootLoggerLevel("INFO"); + + String level = _loggingFacade.retrieveRuntimeRootLoggerLevel(); + assertEquals("INFO", level); + } + + public void testRetrieveRuntimeLoggersLevels() throws Exception + { + Map levels = _loggingFacade.retrieveRuntimeLoggersLevels(); + // Don't assert size as implementation itself uses logging and we'd count its loggers too + String abcLevel = levels.get("a.b.c"); + String abc1Level = levels.get("a.b.c.1"); + String abc2Level = levels.get("a.b.c.2"); + assertEquals("INFO", abcLevel); + assertEquals("DEBUG", abc1Level); + assertEquals("TRACE", abc2Level); + } + + public void testSetRuntimeLoggerLevel() throws Exception + { + final String loggerName = "a.b.c"; + + assertRuntimeLoggingLevel(loggerName, "INFO"); + + _loggingFacade.setRuntimeLoggerLevel(loggerName, "WARN"); + + assertRuntimeLoggingLevel(loggerName, "WARN"); + } + + public void testSetRuntimeLoggerToInheritFromParent() throws Exception + { + final String parentLoggerName = "a.b.c"; + final String childLoggerName = "a.b.c.1"; + + assertRuntimeLoggingLevel(parentLoggerName, "INFO"); + assertRuntimeLoggingLevel(childLoggerName, "DEBUG"); + + _loggingFacade.setRuntimeLoggerLevel(childLoggerName, null); + + assertRuntimeLoggingLevel(parentLoggerName, "INFO"); + assertRuntimeLoggingLevel(childLoggerName, "INFO"); + } + + public void testSetRuntimeLoggerLevelsWhereLoggerDoesNotExist() throws Exception + { + final String loggerName = "does.not.exist2"; + + Map oldLevels = _loggingFacade.retrieveRuntimeLoggersLevels(); + assertFalse(oldLevels.containsKey(loggerName)); + + try + { + _loggingFacade.setRuntimeLoggerLevel(loggerName, "WARN"); + fail("Exception not thrown"); + } + catch (LoggingFacadeException lfe) + { + // PASS + assertEquals("Can't find logger " + loggerName, lfe.getMessage()); + } + + Map levels = _loggingFacade.retrieveRuntimeLoggersLevels(); + assertFalse(levels.containsKey(loggerName)); + } + + public void testReloadOfChangedLog4JFileUpdatesRuntimeLogLevel() throws Exception + { + final String loggerName = "a.b.c"; + + assertRuntimeLoggingLevel(loggerName, "INFO"); + assertConfigFileLoggingLevel(loggerName, "INFO"); + + _loggingFacade.setConfigFileLoggerLevel(loggerName, "WARN"); + + assertRuntimeLoggingLevel(loggerName, "INFO"); + + _loggingFacade.reload(); + + assertRuntimeLoggingLevel(loggerName, "WARN"); + } + + + public void testReloadOfLog4JFileRevertsRuntimeChanges() throws Exception + { + final String loggerName = "a.b.c"; + + assertRuntimeLoggingLevel(loggerName, "INFO"); + assertConfigFileLoggingLevel(loggerName, "INFO"); + + _loggingFacade.setRuntimeLoggerLevel(loggerName, "WARN"); + + assertRuntimeLoggingLevel(loggerName, "WARN"); + + _loggingFacade.reload(); + + assertRuntimeLoggingLevel(loggerName, "INFO"); + } + + private void assertConfigFileLoggingLevel(final String loggerName, String expectedLevel) throws Exception + { + Map levels = _loggingFacade.retrieveConfigFileLoggersLevels(); + String actualLevel = levels.get(loggerName); + assertEquals(expectedLevel, actualLevel); + } + + private void assertRuntimeLoggingLevel(final String loggerName, String expectedLevel) throws Exception + { + Map levels = _loggingFacade.retrieveRuntimeLoggersLevels(); + String actualLevel = levels.get(loggerName); + assertEquals(expectedLevel, actualLevel); + } + + private String createTestLog4jXml() throws Exception + { + File dst = File.createTempFile("log4j." + getName(), "xml"); + File filename = new File(getClass().getResource("LoggingFacadeTest.log4j.xml").toURI()); + FileUtils.copy(filename, dst); + dst.deleteOnExit(); + return dst.getAbsolutePath(); + } +} -- cgit v1.2.1