Author: ihabunek Date: Sun Oct 16 07:12:49 2011 New Revision: 1184770 URL: http://svn.apache.org/viewvc?rev=1184770&view=rev Log: LOG4PHP-152: A rewrite of the configurator and improved tests. Added: logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapter.php logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterINI.php logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterPHP.php logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterXML.php logging/log4php/trunk/src/test/php/LoggerConfiguratorTest.php logging/log4php/trunk/src/test/php/LoggerTestHelper.php logging/log4php/trunk/src/test/php/configurators/LoggerConfigurationAdapterINITest.php logging/log4php/trunk/src/test/php/configurators/LoggerConfigurationAdapterPHPTest.php logging/log4php/trunk/src/test/php/configurators/LoggerConfigurationAdapterXMLTest.php logging/log4php/trunk/src/test/php/configurators/config1.ini logging/log4php/trunk/src/test/php/configurators/config1.php logging/log4php/trunk/src/test/php/configurators/config1.xml logging/log4php/trunk/src/test/php/configurators/config2.ini logging/log4php/trunk/src/test/php/configurators/config2.php logging/log4php/trunk/src/test/php/configurators/config2.xml logging/log4php/trunk/src/test/php/configurators/config3.ini logging/log4php/trunk/src/test/php/configurators/config3.php logging/log4php/trunk/src/test/php/configurators/config3.xml logging/log4php/trunk/src/test/php/configurators/config4.ini logging/log4php/trunk/src/test/php/configurators/config4.php logging/log4php/trunk/src/test/php/configurators/config4.xml Removed: logging/log4php/trunk/src/main/php/configurators/LoggerConfiguratorBasic.php logging/log4php/trunk/src/main/php/configurators/LoggerConfiguratorIni.php logging/log4php/trunk/src/main/php/configurators/LoggerConfiguratorPhp.php logging/log4php/trunk/src/main/php/configurators/LoggerConfiguratorXml.php logging/log4php/trunk/src/test/php/configurators/LoggerConfiguratorBasicTest.php logging/log4php/trunk/src/test/php/configurators/LoggerConfiguratorIniTest.php logging/log4php/trunk/src/test/php/configurators/LoggerConfiguratorPhpTest.php logging/log4php/trunk/src/test/php/configurators/LoggerConfiguratorXmlTest.php logging/log4php/trunk/src/test/php/configurators/test1.php logging/log4php/trunk/src/test/php/configurators/test1.properties logging/log4php/trunk/src/test/php/configurators/test1.xml logging/log4php/trunk/src/test/php/configurators/test2.properties logging/log4php/trunk/src/test/php/configurators/test3.properties logging/log4php/trunk/src/test/php/configurators/test4.properties logging/log4php/trunk/src/test/php/configurators/test5.properties logging/log4php/trunk/src/test/php/configurators/test6.properties Modified: logging/log4php/trunk/src/changes/changes.xml logging/log4php/trunk/src/main/php/Logger.php logging/log4php/trunk/src/main/php/LoggerAppenderPool.php logging/log4php/trunk/src/main/php/LoggerConfigurator.php logging/log4php/trunk/src/main/php/appenders/LoggerAppenderConsole.php logging/log4php/trunk/src/main/php/helpers/LoggerNamedPatternConverter.php logging/log4php/trunk/src/main/php/layouts/LoggerLayoutPattern.php logging/log4php/trunk/src/test/php/LoggerTest.php logging/log4php/trunk/src/test/php/LoggerThrowableInformationTest.php logging/log4php/trunk/src/test/php/appenders/LoggerAppenderConsoleTest.php logging/log4php/trunk/src/test/php/appenders/LoggerAppenderEchoTest.php logging/log4php/trunk/src/test/php/appenders/LoggerAppenderFileTest.php logging/log4php/trunk/src/test/php/appenders/LoggerAppenderPhpTest.php logging/log4php/trunk/src/test/php/bootstrap.php logging/log4php/trunk/src/test/php/filters/LoggerFilterDenyAllTest.php logging/log4php/trunk/src/test/php/filters/LoggerFilterLevelMatchTest.php logging/log4php/trunk/src/test/php/filters/LoggerFilterStringMatchTest.php logging/log4php/trunk/src/test/php/renderers/LoggerRendererMapTest.php logging/log4php/trunk/src/test/php/renderers/test4.properties Modified: logging/log4php/trunk/src/changes/changes.xml URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/changes/changes.xml?rev=1184770&r1=1184769&r2=1184770&view=diff ============================================================================== --- logging/log4php/trunk/src/changes/changes.xml (original) +++ logging/log4php/trunk/src/changes/changes.xml Sun Oct 16 07:12:49 2011 @@ -21,6 +21,7 @@ + A rewrite of the configurator. The syslog appender does not correctly parse options Remove deprecated appender LoggerAppenderAdodb LoggerUserFieldPatternConverter class missing in log4php archive Modified: logging/log4php/trunk/src/main/php/Logger.php URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/Logger.php?rev=1184770&r1=1184769&r2=1184770&view=diff ============================================================================== --- logging/log4php/trunk/src/main/php/Logger.php (original) +++ logging/log4php/trunk/src/main/php/Logger.php Sun Oct 16 07:12:49 2011 @@ -54,10 +54,10 @@ class Logger { 'LoggerNDC' => '/LoggerNDC.php', 'LoggerReflectionUtils' => '/LoggerReflectionUtils.php', 'LoggerConfigurator' => '/LoggerConfigurator.php', - 'LoggerConfiguratorBasic' => '/configurators/LoggerConfiguratorBasic.php', - 'LoggerConfiguratorIni' => '/configurators/LoggerConfiguratorIni.php', - 'LoggerConfiguratorPhp' => '/configurators/LoggerConfiguratorPhp.php', - 'LoggerConfiguratorXml' => '/configurators/LoggerConfiguratorXml.php', + 'LoggerConfigurationAdapter' => '/configurators/LoggerConfigurationAdapter.php', + 'LoggerConfigurationAdapterINI' => '/configurators/LoggerConfigurationAdapterINI.php', + 'LoggerConfigurationAdapterXML' => '/configurators/LoggerConfigurationAdapterXML.php', + 'LoggerConfigurationAdapterPHP' => '/configurators/LoggerConfigurationAdapterPHP.php', 'LoggerRoot' => '/LoggerRoot.php', 'LoggerAppender' => '/LoggerAppender.php', 'LoggerAppenderPool' => '/LoggerAppenderPool.php', @@ -154,16 +154,10 @@ class Logger { private static $hierarchy; /** - * Name of the configurator class used to configure log4php. - * Populated by {@link configure()} and used in {@link initialize()}. + * Holds the configurator. + * @var LoggerConfigurator */ - private static $configurationClass = 'LoggerConfiguratorBasic'; - - /** - * Path to the configuration file which may be used by the configurator. - * Populated by {@link configure()} and used in {@link initialize()}. - */ - private static $configurationFile; + private static $configurator; /** Inidicates if log4php has been initialized */ private static $initialized = false; @@ -344,26 +338,27 @@ class Logger { /* Factory methods */ /** - * Get a Logger by name (Delegate to {@link Logger}) + * Returns a Logger by name. + * + * If it does not exist, it will be created. * * @param string $name logger name - * @param LoggerFactory $factory a {@link LoggerFactory} instance or null * @return Logger */ public static function getLogger($name) { if(!self::isInitialized()) { - self::initialize(); + self::configure(); } return self::getHierarchy()->getLogger($name); } /** - * Get the Root Logger (Delegate to {@link Logger}) + * Returns the Root Logger. * @return LoggerRoot */ public static function getRootLogger() { if(!self::isInitialized()) { - self::initialize(); + self::configure(); } return self::getHierarchy()->getRootLogger(); } @@ -485,14 +480,11 @@ class Logger { /** * Destroy configurations for logger definitions - * @return boolean */ public static function resetConfiguration() { - $result = self::getHierarchy()->resetConfiguration(); + self::getHierarchy()->resetConfiguration(); + self::getHierarchy()->clear(); // TODO: clear or not? self::$initialized = false; - self::$configurationClass = 'LoggerConfiguratorBasic'; - self::$configurationFile = null; - return $result; } /** @@ -550,58 +542,20 @@ class Logger { } /** - * Configures log4php by defining a configuration file and/or class. + * Configures log4php. * * This method needs to be called before the first logging event has - * occured. If this method is not called before then, the standard - * configuration takes place (@see LoggerConfiguratorBasic). - * - * If only the configuration file is given, the configurator class will - * be determined by the config file extension. - * - * If a custom configurator class is provided, the configuration file - * should either be null or contain the path to file used by the custom - * configurator. Make sure the configurator class is already loaded, or - * that it can be included by PHP when necessary. - * - * @param string $configurationFile path to the configuration file - * @param string $configurationClass name of the custom configurator class - */ - public static function configure($configurationFile = null, $configurationClass = null ) { - if($configurationClass === null && $configurationFile === null) { - self::$configurationClass = 'LoggerConfiguratorBasic'; - return; - } - - if($configurationClass !== null) { - self::$configurationFile = $configurationFile; - self::$configurationClass = $configurationClass; - return; - } - - if (strtolower(substr( $configurationFile, -4 )) == '.xml') { - self::$configurationFile = $configurationFile; - self::$configurationClass = 'LoggerConfiguratorXml'; - } else { - self::$configurationFile = $configurationFile; - self::$configurationClass = 'LoggerConfiguratorIni'; - } - } - - /** - * Returns the current {@link Logger::$configurationClass configurator class}. - * @return string the configurator class name - */ - public static function getConfigurationClass() { - return self::$configurationClass; - } - - /** - * Returns the current {@link Logger::$configurationFile configuration file}. - * @return string the configuration file + * occured. If this method is not called before then the default + * configuration will be used. + * + * @param string|array $configuration Either a path to the configuration + * file, or a configuration array. */ - public static function getConfigurationFile() { - return self::$configurationFile; + public static function configure($configuration = null) { + self::resetConfiguration(); + $configurator = new LoggerConfigurator(); + $configurator->configure(self::getHierarchy(), $configuration); + self::$initialized = true; } /** @@ -612,16 +566,4 @@ class Logger { return self::$initialized; } - /** - * Initializes the log4php framework using the provided {@link - * Logger::$configurationClass configuration class} and {@link - * Logger::$configurationFile configuration file}. - * @return boolean - */ - public static function initialize() { - self::$initialized = true; - $instance = LoggerReflectionUtils::createObject(self::$configurationClass); - $result = $instance->configure(self::getHierarchy(), self::$configurationFile); - return $result; - } } Modified: logging/log4php/trunk/src/main/php/LoggerAppenderPool.php URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/LoggerAppenderPool.php?rev=1184770&r1=1184769&r2=1184770&view=diff ============================================================================== --- logging/log4php/trunk/src/main/php/LoggerAppenderPool.php (original) +++ logging/log4php/trunk/src/main/php/LoggerAppenderPool.php Sun Oct 16 07:12:49 2011 @@ -19,42 +19,81 @@ */ /** - * Pool implmentation for LoggerAppender instances + * Pool implmentation for LoggerAppender instances. + * + * The pool is used when configuring log4php. First all appender instances + * are created in the pool. Afterward, they are linked to loggers, each + * appender can be linked to multiple loggers. This makes sure duplicate + * appenders are not created. * * @version $Revision: 795727 $ * @package log4php */ class LoggerAppenderPool { - /* Appender Pool */ - public static $appenderPool = array(); + /** Holds appenders indexed by their name */ + public static $appenders = array(); + /** - * - * - * @param string $name - * @param string $class - * @return LoggerAppender + * Adds an appender to the pool. + * The appender must be named for this operation. + * @param LoggerAppender $appender */ - public static function getAppenderFromPool($name, $class = '') { - if(isset(self::$appenderPool[$name])) { - return self::$appenderPool[$name]; - } + public static function add(LoggerAppender $appender) + { + $name = $appender->getName(); - if(empty($class)) { - return null; + if(empty($name)) { + trigger_error('log4php: Cannot add unnamed appender to pool.', E_USER_WARNING); + return; } - $appender = LoggerReflectionUtils::createObject($class); - $appender->setName($name); - if($appender !== null) { - self::$appenderPool[$name] = $appender; - return self::$appenderPool[$name]; + if (isset(self::$appenders[$name])) { + trigger_error("log4php: Appender [$name] already exists in pool. Overwriting existing appender.", E_USER_WARNING); } - return null; + + self::$appenders[$name] = $appender; } - public static function clear() - { - self::$appenderPool = array(); + /** + * Retrieves an appender from the pool by name. + * @param string $name Name of the appender to retrieve. + * @return LoggerAppender The named appender or NULL if no such appender + * exists in the pool. + */ + public static function get($name) { + return isset(self::$appenders[$name]) ? self::$appenders[$name] : null; + } + + /** + * Removes an appender from the pool by name. + * @param string $name Name of the appender to remove. + */ + public static function delete($name) { + unset(self::$appenders[$name]); + } + + /** + * Returns all appenders from the pool. + * @return array Array of LoggerAppender objects. + */ + public static function getAppenders() { + return self::$appenders; + } + + /** + * Checks whether an appender exists in the pool. + * @param string $name Name of the appender to look for. + * @return boolean TRUE if the appender with the given name exists. + */ + public static function exists($name) { + return isset(self::$appenders[$name]); + } + + /** + * Clears all appenders from the pool. + */ + public static function clear() { + self::$appenders = array(); } } \ No newline at end of file Modified: logging/log4php/trunk/src/main/php/LoggerConfigurator.php URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/LoggerConfigurator.php?rev=1184770&r1=1184769&r2=1184770&view=diff ============================================================================== --- logging/log4php/trunk/src/main/php/LoggerConfigurator.php (original) +++ logging/log4php/trunk/src/main/php/LoggerConfigurator.php Sun Oct 16 07:12:49 2011 @@ -19,35 +19,426 @@ */ /** - * Implemented by classes capable of configuring log4php using a URL. - * - * @version $Revision$ + * Configures log4php based on a provided configuration file or array. + * * @package log4php + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @version $Revision$ + * @since 2.2 */ -interface LoggerConfigurator { +class LoggerConfigurator +{ + /** XML configuration file format. */ + const FORMAT_XML = 'xml'; + + /** PHP configuration file format. */ + const FORMAT_PHP = 'php'; + + /** INI (properties) configuration file format. */ + const FORMAT_INI = 'ini'; + + /** Defines which adapter should be used for parsing which format. */ + private $adapters = array( + self::FORMAT_XML => 'LoggerConfigurationAdapterXML', + self::FORMAT_INI => 'LoggerConfigurationAdapterINI', + self::FORMAT_PHP => 'LoggerConfigurationAdapterPHP', + ); + + /** Default configuration; used if no configuration file is provided. */ + private static $defaultConfiguration = array( + 'threshold' => 'ALL', + 'rootLogger' => array( + 'level' => 'DEBUG', + 'appenders' => array('default'), + ), + 'appenders' => array( + 'default' => array( + 'class' => 'LoggerAppenderEcho', + 'layout' => array( + 'class' => 'LoggerLayoutTTCC', + ), + ), + ), + ); + + /** Holds the appenders before they are linked to loggers. */ + private $appenders = array(); /** - * Special level value signifying inherited behaviour. The current - * value of this string constant is inherited. - * {@link CONFIGURATOR_NULL} is a synonym. + * Configures log4php based on the given configuration. The input can + * either be a path to the config file, or a PHP array holding the + * configuration. + * + * If no configuration is given, or if the given configuration cannot be + * parsed for whatever reason, a warning will be issued, and log4php + * will use the default configuration contained in + * {@link $defaultConfiguration}. + * + * @param LoggerHierarchy $hierarchy The hierarchy on which to perform + * the configuration. + * @param string|array $input Either path to the config file or the + * configuration as an array. If not set, default configuration + * will be used. */ - const CONFIGURATOR_INHERITED = 'inherited'; + public function configure(LoggerHierarchy $hierarchy, $input = null) { + $config = $this->parse($input); + $this->doConfigure($hierarchy, $config); + } /** - * Special level signifying inherited behaviour, same as - * {@link CONFIGURATOR_INHERITED}. - * The current value of this string constant is null. + * Parses the given configuration and returns the parsed configuration + * as a PHP array. Does not perform any configuration. + * + * If no configuration is given, or if the given configuration cannot be + * parsed for whatever reason, a warning will be issued, and the default + * configuration will be returned ({@link $defaultConfiguration}). + * + * @param string|array $input Either path to the config file or the + * configuration as an array. If not set, default configuration + * will be used. + * @return array The parsed configuration. */ - const CONFIGURATOR_NULL = 'null'; + public function parse($input) + { + // No input - use default configuration + if (!isset($input)) { + $config = self::$defaultConfiguration; + } + + // Array input - contains configuration within the array + else if (is_array($input)) { + $config = $input; + } + // String input - contains path to configuration file + else if (is_string($input)) { + try { + $config = $this->parseFile($input); + } catch (LoggerException $e) { + $this->warn("Configuration failed. " . $e->getMessage() . " Using default configuration."); + $config = self::$defaultConfiguration; + } + } + + // Anything else is an error + else { + $this->warn("Invalid configuration param given. Reverting to default configuration."); + $config = self::$defaultConfiguration; + } + + return $config; + } + + /** + * Returns the default log4php configuration. + * @return array + */ + public static function getDefaultConfiguration() { + return self::$defaultConfiguration; + } + /** - * Interpret a resource pointed by a url and configure accordingly. - * - * The configuration is done relative to the repository - * parameter. + * Loads the configuration file from the given URL, determines which + * adapter to use, converts the configuration to a PHP array and + * returns it. * - * @param string $url The URL to parse + * @param string $url Path to the config file. + * @return The configuration from the config file, as a PHP array. + * @throws LoggerException If the configuration file cannot be loaded, or + * if the parsing fails. + */ + private function parseFile($url) { + + if (!file_exists($url)) { + throw new LoggerException("File not found at [$url]."); + } + + $type = $this->getConfigType($url); + $adapterClass = $this->adapters[$type]; + + $adapter = new $adapterClass(); + return $adapter->convert($url); + } + + /** Determines configuration file type based on the file extension. */ + private function getConfigType($url) { + $info = pathinfo($url); + $ext = strtolower($info['extension']); + + switch($ext) { + case 'xml': + return self::FORMAT_XML; + + case 'ini': + case 'properties': + return self::FORMAT_INI; + + case 'php': + return self::FORMAT_PHP; + + default: + throw new LoggerException("Unsupported configuration file extension: $ext"); + } + } + + /** + * Constructs the logger hierarchy based on configuration. + * + * @param LoggerHierarchy $hierarchy + * @param array $config + */ + private function doConfigure(LoggerHierarchy $hierarchy, $config) { + if (isset($config['threshold'])) { + $threshold = LoggerLevel::toLevel($config['threshold']); + if (isset($threshold)) { + $hierarchy->setThreshold($threshold); + } else { + $this->warn("Invalid threshold {$config['threshold']} specified."); + } + } + + // Configure appenders and add them to the appender pool + if (isset($config['appenders']) && is_array($config['appenders'])) { + foreach($config['appenders'] as $name => $appenderConfig) { + $this->configureAppender($name, $appenderConfig); + } + } + + // Configure root logger + if (isset($config['rootLogger'])) { + $this->configureRootLogger($hierarchy, $config['rootLogger']); + } + + // Configure loggers + if (isset($config['loggers']) && is_array($config['loggers'])) { + foreach($config['loggers'] as $loggerName => $loggerConfig) { + $this->configureOtherLogger($hierarchy, $loggerName, $loggerConfig); + } + } + + // Configure renderers + if (isset($config['renderers']) && is_array($config['renderers'])) { + foreach($config['renderers'] as $renderer) { + $hierarchy->getRendererMap()->addRenderer($renderer['renderedClass'], $renderer['renderingClass']); + } + } + } + + /** + * Configures an appender based on given config and saves it to + * {@link $appenders} array so it can be later linked to loggers. + * @param string $name Appender name. + * @param array $config Appender configuration options. + */ + private function configureAppender($name, $config) { + + // TODO: add this check to other places where it might be useful + if (!is_array($config)) { + $type = gettype($config); + $this->warn("Invalid configuration provided for [$name] appender. Expected an array, found <$type>. Skipping appender definition."); + return; + } + + // Parse appender class + $class = $config['class']; + if (!class_exists($class)) { + $this->warn("Class [$class] does not exist. Skipping appender [$name]."); + return; + } + + // Instantiate the appender + $appender = new $class($name); + if (!($appender instanceof LoggerAppender)) { + $this->warn("[$class] is not a valid appender class. Skipping appender [$name]."); + return; + } + + // Parse the appender threshold + if (isset($config['threshold'])) { + $threshold = LoggerLevel::toLevel($config['threshold']); + if ($threshold instanceof LoggerLevel) { + $appender->setThreshold($threshold); + } else { + $default = $appender->getThreshold(); + $this->warn("Invalid threshold value [{$config['threshold']}] specified for appender [$name]. Reverting to default value [$default]."); + } + } + + // Parse the appender layout + if ($appender->requiresLayout() && isset($config['layout'])) { + $this->createAppenderLayout($appender, $config['layout']); + } + + // Parse filters + if (isset($config['filters']) && is_array($config['filters'])) { + foreach($config['filters'] as $filterConfig) { + $this->createAppenderFilter($appender, $filterConfig); + } + } + + // Set options if any + if (isset($config['params'])) { + $this->setOptions($appender, $config['params']); + } + + // Activate and save for later linking to loggers + $appender->activateOptions(); + $this->appenders[$name] = $appender; + } + + /** + * Parses layout config, creates the layout and links it to the appender. + * @param LoggerAppender $appender + * @param array $config Layout configuration. + */ + private function createAppenderLayout(LoggerAppender $appender, $config) { + $name = $appender->getName(); + $class = $config['class']; + if (!class_exists($class)) { + $this->warn("Nonexistant layout class [$class] specified for appender [$name]. Reverting to default layout."); + return; + } + + $layout = new $class(); + if (!($layout instanceof LoggerLayout)) { + $this->warn("Invalid layout class [$class] sepcified for appender [$name]. Reverting to default layout."); + return; + } + + if (isset($config['params'])) { + $this->setOptions($layout, $config['params']); + } + + $layout->activateOptions(); + $appender->setLayout($layout); + } + + /** + * Parses filter config, creates the filter and adds it to the appender's + * filter chain. + * @param LoggerAppender $appender + * @param array $config Filter configuration. + */ + private function createAppenderFilter(LoggerAppender $appender, $config) { + $name = $appender->getName(); + $class = $config['class']; + if (!class_exists($class)) { + $this->warn("Nonexistant filter class [$class] specified on appender [$name]. Skipping filter definition."); + return; + } + + $filter = new $class(); + if (!($filter instanceof LoggerFilter)) { + $this->warn("Invalid filter class [$class] sepcified on appender [$name]. Skipping filter definition."); + return; + } + + if (isset($config['params'])) { + $this->setOptions($filter, $config['params']); + } + + $filter->activateOptions(); + $appender->addFilter($filter); + } + + /** + * Configures the root logger + * @see configureLogger() + */ + private function configureRootLogger(LoggerHierarchy $hierarchy, $config) { + $logger = $hierarchy->getRootLogger(); + $this->configureLogger($logger, $config); + } + + /** + * Configures a logger which is not root. + * @see configureLogger() + */ + private function configureOtherLogger(LoggerHierarchy $hierarchy, $name, $config) { + // Get logger from hierarchy (this creates it if it doesn't already exist) + $logger = $hierarchy->getLogger($name); + $this->configureLogger($logger, $config); + } + + /** + * Configures a logger. + * + * @param Logger $logger The logger to configure + * @param array $config Logger configuration options. + */ + private function configureLogger(Logger $logger, $config) { + $loggerName = $logger->getName(); + + // Set logger level + if (isset($config['level'])) { + $level = LoggerLevel::toLevel($config['level']); + if (isset($level)) { + $logger->setLevel($level); + } else { + $default = $logger->getLevel(); + $this->warn("Invalid logger level [{$config['level']}] specified for logger [$loggerName]."); + } + } + + // Link appenders to logger + if (isset($config['appenders'])) { + foreach($config['appenders'] as $appenderName) { + if (isset($this->appenders[$appenderName])) { + $logger->addAppender($this->appenders[$appenderName]); + } else { + $this->warn("Nonexistnant appender [$appenderName] linked to logger [$loggerName]."); + } + } + } + + // Set logger additivity + if (isset($config['additivity'])) { + $additivity = LoggerOptionConverter::toBoolean($config['additivity'], null); + if (is_bool($additivity)) { + $logger->setAdditivity($additivity); + } else { + $this->warn("Invalid additivity value [{$config['additivity']}] specified for logger [$loggerName]."); + } + } + } + + /** + * Helper method which applies given options to an object which has setters + * for these options (such as appenders, layouts, etc.). + * + * For example, if options are: + * + * array( + * 'file' => '/tmp/myfile.log', + * 'append' => true + * ) + * + * + * This method will call: + * + * $object->setFile('/tmp/myfile.log') + * $object->setAppend(true) + * + * + * If required setters do not exist, it will produce a warning. + * + * @param mixed $object The object to configure. + * @param unknown_type $options */ - public function configure(LoggerHierarchy $hierarchy, $url = null); + private function setOptions($object, $options) { + foreach($options as $name => $value) { + $setter = "set$name"; + if (method_exists($object, $setter)) { + $object->$setter($value); + } else { + $class = get_class($object); + $this->warn("Nonexistant option [$name] specified on [$class]. Skipping."); + } + } + } -} + /** Helper method to simplify error reporting. */ + private function warn($message) { + trigger_error("log4php: $message", E_USER_WARNING); + } +} \ No newline at end of file Modified: logging/log4php/trunk/src/main/php/appenders/LoggerAppenderConsole.php URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/appenders/LoggerAppenderConsole.php?rev=1184770&r1=1184769&r2=1184770&view=diff ============================================================================== --- logging/log4php/trunk/src/main/php/appenders/LoggerAppenderConsole.php (original) +++ logging/log4php/trunk/src/main/php/appenders/LoggerAppenderConsole.php Sun Oct 16 07:12:49 2011 @@ -71,6 +71,10 @@ class LoggerAppenderConsole extends Logg } } + public function getTarget() { + return $this->target; + } + public function activateOptions() { $this->fp = fopen($this->target, 'w'); if(is_resource($this->fp) && $this->layout !== null) { Added: logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapter.php URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapter.php?rev=1184770&view=auto ============================================================================== --- logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapter.php (added) +++ logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapter.php Sun Oct 16 07:12:49 2011 @@ -0,0 +1,40 @@ + \ No newline at end of file Added: logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterINI.php URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterINI.php?rev=1184770&view=auto ============================================================================== --- logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterINI.php (added) +++ logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterINI.php Sun Oct 16 07:12:49 2011 @@ -0,0 +1,306 @@ +load($path); + + // Parse threshold + if (isset($properties[self::THRESHOLD_PREFIX])) { + $this->config['threshold'] = $properties[self::THRESHOLD_PREFIX]; + } + + // Parse root logger + if (isset($properties[self::ROOT_LOGGER_PREFIX])) { + $this->parseLogger($properties[self::ROOT_LOGGER_PREFIX], self::ROOT_LOGGER_NAME); + } + + $appenders = array(); + + foreach($properties as $key => $value) { + // Parse loggers + if ($this->beginsWith($key, self::LOGGER_PREFIX)) { + $name = substr($key, strlen(self::LOGGER_PREFIX)); + $this->parseLogger($value, $name); + } + + // Parse additivity + if ($this->beginsWith($key, self::ADDITIVITY_PREFIX)) { + $name = substr($key, strlen(self::ADDITIVITY_PREFIX)); + $this->config['loggers'][$name]['additivity'] = $value; + } + + // Parse appenders + else if ($this->beginsWith($key, self::APPENDER_PREFIX)) { + $this->parseAppender($key, $value); + } + + // Parse renderers + else if ($this->beginsWith($key, self::RENDERER_PREFIX)) { + $this->parseRenderer($key, $value); + } + } + + return $this->config; + } + + + /** + * Parses a logger definition. + * + * Loggers are defined in the following manner: + *
+	 * log4php.logger. = [], [, , ...] 
+	 * 
+ * + * @param string $value The configuration value (level and appender-refs). + * @param string $name Logger name. + */ + private function parseLogger($value, $name) { + // Value is divided by commas + $parts = explode(',', $value); + if (empty($value) || empty($parts)) { + return; + } + + // The first value is the logger level + $level = array_shift($parts); + + // The remaining values are appender references + $appenders = array(); + while($appender = array_shift($parts)) { + $appender = trim($appender); + if (!empty($appender)) { + $appenders[] = trim($appender); + } + } + + // Find the target configuration + if ($name == self::ROOT_LOGGER_NAME) { + $this->config['rootLogger']['level'] = trim($level); + $this->config['rootLogger']['appenders'] = $appenders; + } else { + $this->config['loggers'][$name]['level'] = trim($level); + $this->config['loggers'][$name]['appenders'] = $appenders; + } + } + + /** + * Parses an configuration line pertaining to an appender. + * + * Parses the following patterns: + * + * Appender class: + *
+	 * log4php.appender. = 
+	 * 
+ * + * Appender parameter: + *
+	 * log4php.appender.. = 
+	 * 
+ * + * Appender threshold: + *
+	 * log4php.appender..threshold = 
+	 * 
+ * + * Appender layout: + *
+	 * log4php.appender..layout = 
+	 * 
+ * + * Layout parameter: + *
+	 * log4php.appender..layout. = 
+	 * 
+ * + * For example, a full appender config might look like: + *
+	 * log4php.appender.myAppender = LoggerAppenderConsole
+	 * log4php.appender.myAppender.threshold = info
+	 * log4php.appender.myAppender.target = stdout
+	 * log4php.appender.myAppender.layout = LoggerLayoutPattern
+	 * log4php.appender.myAppender.layout.conversionPattern = "%d %c: %m%n"
+	 * 
+ * + * After parsing all these options, the following configuration can be + * found under $this->config['appenders']['myAppender']: + *
+	 * array(
+	 * 	'class' => LoggerAppenderConsole,
+	 * 	'threshold' => info,
+	 * 	'params' => array(
+	 * 		'target' => 'stdout'
+	 * 	),
+	 * 	'layout' => array(
+	 * 		'class' => 'LoggerAppenderConsole',
+	 * 		'params' => array(
+	 * 			'conversionPattern' => '%d %c: %m%n'
+	 * 		)
+	 * 	)
+	 * )
+	 * 
+ * + * @param string $key + * @param string $value + */ + private function parseAppender($key, $value) { + + // Remove the appender prefix from key + $subKey = substr($key, strlen(self::APPENDER_PREFIX)); + + // Divide the string by dots + $parts = explode('.', $subKey); + $count = count($parts); + + // The first part is always the appender name + $name = trim($parts[0]); + + // Only one part - this line defines the appender class + if ($count == 1) { + $this->config['appenders'][$name]['class'] = $value; + return; + } + + // Two parts - either a parameter, a threshold or layout class + else if ($count == 2) { + + if ($parts[1] == 'layout') { + $this->config['appenders'][$name]['layout']['class'] = $value; + return; + } else if ($parts[1] == 'threshold') { + $this->config['appenders'][$name]['threshold'] = $value; + return; + } else { + $this->config['appenders'][$name]['params'][$parts[1]] = $value; + return; + } + } + + // Three parts - this can only be a layout parameter + else if ($count == 3) { + if ($parts[1] == 'layout') { + $this->config['appenders'][$name]['layout']['params'][$parts[2]] = $value; + return; + } + } + + trigger_error("log4php: Don't know how to parse the following line: \"$key = $value\". Skipping."); + } + + /** + * Parses a renderer definition. + * + * Renderers are defined as: + *
+	 * log4php.renderer. =  
+	 * 
+ * + * @param string $key log4php.renderer. + * @param string $value + */ + private function parseRenderer($key, $value) { + // Remove the appender prefix from key + $renderedClass = substr($key, strlen(self::APPENDER_PREFIX)); + $renderingClass = $value; + + $this->config['renderers'][] = compact('renderedClass', 'renderingClass'); + } + + /** Helper method. Returns true if $str begins with $sub. */ + private function beginsWith($str, $sub) { + return (strncmp($str, $sub, strlen($sub)) == 0); + } + + +} + +?> \ No newline at end of file Added: logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterPHP.php URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterPHP.php?rev=1184770&view=auto ============================================================================== --- logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterPHP.php (added) +++ logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterPHP.php Sun Oct 16 07:12:49 2011 @@ -0,0 +1,85 @@ + + * array( + * 'level' => 'info', + * 'appenders' => array('default') + * ), + * 'appenders' => array( + * 'default' => array( + * 'class' => 'LoggerAppenderEcho', + * 'layout' => array( + * 'class' => 'LoggerLayoutSimple' + * ) + * ) + * ) + * ) + * ?> + * + * + * @package log4php + * @subpackage configurators + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @version $Revision$ + * @since 2.2 + */ +class LoggerConfigurationAdapterPHP implements LoggerConfigurationAdapter +{ + public function convert($url) { + if (!file_exists($url)) { + throw new LoggerException("File [$url] does not exist."); + } + + // Load the config file + $data = @file_get_contents($url); + if ($data === false) { + $error = error_get_last(); + throw new LoggerException("Error loading config file: {$error['message']}"); + } + + $config = @eval('?>' . $data); + + if ($config === false) { + $error = error_get_last(); + throw new LoggerException("Error parsing configuration: " . $error['message']); + } + + if (empty($config)) { + throw new LoggerException("Invalid configuration: empty configuration array."); + } + + if (!is_array($config)) { + throw new LoggerException("Invalid configuration: not an array."); + } + + return $config; + } +} + +?> \ No newline at end of file Added: logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterXML.php URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterXML.php?rev=1184770&view=auto ============================================================================== --- logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterXML.php (added) +++ logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterXML.php Sun Oct 16 07:12:49 2011 @@ -0,0 +1,244 @@ + array(), + 'loggers' => array(), + 'renderers' => array(), + ); + + public function convert($url) + { + $xml = $this->loadXML($url); + + $this->parseConfiguration($xml); + + // Parse the node + if (isset($xml->root)) { + $this->parseRootLogger($xml->root); + } + + // Process nodes + foreach($xml->logger as $logger) { + $this->parseLogger($logger); + } + + // Process nodes + foreach($xml->appender as $appender) { + $this->parseAppender($appender); + } + + // Process nodes + foreach($xml->renderer as $rendererNode) { + $this->parseRenderer($rendererNode); + } + return $this->config; + } + + /** + * Loads and validates the XML. + * @param string $url Input XML. + */ + private function loadXML($url) { + if (!file_exists($url)) { + throw new LoggerException("File [$url] does not exist."); + } + + // Load XML + $xml = simplexml_load_file($url); + if ($xml === false) { + throw new LoggerException("Error loading confuguration file."); + } + return $xml; + } + + /** + * Parses the node. + */ + private function parseConfiguration(SimpleXMLElement $xml) { + $attributes = $xml->attributes(); + if (isset($attributes['threshold'])) { + $this->config['threshold'] = (string) $attributes['threshold']; + } + } + + /** Parses an node. */ + private function parseAppender(SimpleXMLElement $node) { + $name = $this->getAttributeValue($node, 'name'); + + $appender = array(); + $appender['class'] = $this->getAttributeValue($node, 'class'); + + if (isset($node['threshold'])) { + $appender['threshold'] = $this->getAttributeValue($node, 'threshold'); + } + + if (isset($node->layout)) { + $appender['layout']= $this->parseLayout($node->layout, $name); + } + + if (count($node->param) > 0) { + $appender['params'] = $this->parseParameters($node); + } + + foreach($node->filter as $filterNode) { + $appender['filters'][] = $this->parseFilter($filterNode); + } + + $this->config['appenders'][$name] = $appender; + } + + /** Parses a node. */ + private function parseLayout(SimpleXMLElement $node, $appenderName) { + $layout = array(); + $layout['class'] = $this->getAttributeValue($node, 'class'); + + if (count($node->param) > 0) { + $layout['params'] = $this->parseParameters($node); + } + + return $layout; + } + /** Parses any child nodes returning them in an array. */ + private function parseParameters($paramsNode) { + $params = array(); + + foreach($paramsNode->param as $paramNode) { + if (empty($paramNode['name'])) { + $this->warn("Found parameter node without a name. Skipping parameter."); + continue; + } + + $name = $this->getAttributeValue($paramNode, 'name'); + $value = $this->getAttributeValue($paramNode, 'value'); + + $params[$name] = $value; + } + + return $params; + } + + /** Parses a node. */ + private function parseRootLogger(SimpleXMLElement $node) { + $logger = array(); + + if (isset($node->level)) { + $logger['level'] = $this->getAttributeValue($node->level, 'value'); + } + + $logger['appenders'] = array(); + foreach($node->appender_ref as $appender) { + $logger['appenders'][] = $this->getAttributeValue($appender, 'ref'); + } + + $this->config['rootLogger'] = $logger; + } + + /** Parses a node. */ + private function parseLogger(SimpleXMLElement $node) { + $logger = array(); + + // Check logger name exists (mandatory because it is used as the array key) + if (empty($node['name'])) { + $this->warn("Found logger without a 'name' attribute. All loggers must be named. Skipping."); + return; + } + + $name = (string) $node['name']; + + if (isset($node->level)) { + $logger['level'] = $this->getAttributeValue($node->level, 'value'); + } + + if (isset($node['additivity'])) { + $logger['additivity'] = $this->getAttributeValue($node, 'additivity'); + } + + $logger['appenders'] = $this->parseAppenderReferences($node, $name); + + // Check for duplicate loggers + if (isset($this->config['loggers'][$name])) { + $this->warn("Duplicate logger definition [$name]. Overwriting."); + } + + $this->config['loggers'][$name] = $logger; + } + + /** + * Parses a node for appender references and returns them in an array. + */ + private function parseAppenderReferences(SimpleXMLElement $node, $name) { + $refs = array(); + foreach($node->appender_ref as $ref) { + $refs[] = $this->getAttributeValue($ref, 'ref'); + } + + return $refs; + } + + /** Parses a node. */ + private function parseFilter($filterNode) { + $filter = array(); + $filter['class'] = $this->getAttributeValue($filterNode, 'class'); + + if (count($filterNode->param) > 0) { + $filter['params'] = $this->parseParameters($filterNode); + } + + return $filter; + } + + /** Parses a node. */ + private function parseRenderer(SimpleXMLElement $node) { + $renderedClass = $this->getAttributeValue($node, 'renderedClass'); + $renderingClass = $this->getAttributeValue($node, 'renderingClass'); + + $this->config['renderers'][] = compact('renderedClass', 'renderingClass'); + } + + // ****************************************** + // ** Helper methods ** + // ****************************************** + + private function getAttributeValue(SimpleXMLElement $node, $name) { + $attrs = $node->attributes(); + return isset($attrs[$name]) ? (string) $attrs[$name] : null; + } + + private function warn($message) { + trigger_error("log4php: " . $message, E_USER_WARNING); + } +} + +?> \ No newline at end of file Modified: logging/log4php/trunk/src/main/php/helpers/LoggerNamedPatternConverter.php URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/helpers/LoggerNamedPatternConverter.php?rev=1184770&r1=1184769&r2=1184770&view=diff ============================================================================== --- logging/log4php/trunk/src/main/php/helpers/LoggerNamedPatternConverter.php (original) +++ logging/log4php/trunk/src/main/php/helpers/LoggerNamedPatternConverter.php Sun Oct 16 07:12:49 2011 @@ -57,6 +57,9 @@ class LoggerNamedPatternConverter extend if($this->precision <= 0) { return $n; } else { + + // TODO: do this with explode() + $len = strlen($n); // We substract 1 from 'len' when assigning to 'end' to avoid out of // bounds exception in return r.substring(end+1, len). This can happen if Modified: logging/log4php/trunk/src/main/php/layouts/LoggerLayoutPattern.php URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/layouts/LoggerLayoutPattern.php?rev=1184770&r1=1184769&r2=1184770&view=diff ============================================================================== --- logging/log4php/trunk/src/main/php/layouts/LoggerLayoutPattern.php (original) +++ logging/log4php/trunk/src/main/php/layouts/LoggerLayoutPattern.php Sun Oct 16 07:12:49 2011 @@ -140,7 +140,7 @@ class LoggerLayoutPattern extends Logger const DEFAULT_CONVERSION_PATTERN = '%m%n'; /** Default conversion TTCC Pattern */ - const TTCC_CONVERSION_PATTERN = '%r [%t] %p %c %x - %m%n'; + const TTCC_CONVERSION_PATTERN = '%d [%t] %p %c %x - %m%n'; /** The pattern. * @var string */ Added: logging/log4php/trunk/src/test/php/LoggerConfiguratorTest.php URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/test/php/LoggerConfiguratorTest.php?rev=1184770&view=auto ============================================================================== --- logging/log4php/trunk/src/test/php/LoggerConfiguratorTest.php (added) +++ logging/log4php/trunk/src/test/php/LoggerConfiguratorTest.php Sun Oct 16 07:12:49 2011 @@ -0,0 +1,97 @@ +assertSame($expected, $actual); + + $appenders = Logger::getRootLogger()->getAllAppenders(); + $this->assertInternalType('array', $appenders); + $this->assertEquals(count($appenders), 1); + $this->assertSame('default', $appenders[0]->getName()); + + $appender = $appenders[0]; + $this->assertInstanceOf('LoggerAppenderEcho', $appender); + + $layout = $appender->getLayout(); + $this->assertInstanceOf('LoggerLayoutTTCC', $layout); + + $root = Logger::getRootLogger(); + $appenders = $root->getAllAppenders(); + $this->assertInternalType('array', $appenders); + $this->assertEquals(count($appenders), 1); + + $actual = $root->getLevel(); + $expected = LoggerLevel::getLevelDebug(); + $this->assertEquals($expected, $actual); + } + + /** + * Test that an error is reported when config file is not found. + * @expectedException PHPUnit_Framework_Error + * @expectedExceptionMessage log4php: Configuration failed. File not found + */ + public function testNonexistantFile() { + Logger::configure('hopefully/this/path/doesnt/exist/config.xml'); + + } + + /** Test correct fallback to the default configuration. */ + public function testNonexistantFileFallback() { + @Logger::configure('hopefully/this/path/doesnt/exist/config.xml'); + $this->testDefaultConfig(); + } + + public function testAppendersWithLayout() { + Logger::configure(array( + 'rootLogger' => array( + 'appenders' => array('app1', 'app2') + ), + 'appenders' => array( + 'app1' => array( + 'class' => 'LoggerAppenderEcho', + 'layout' => array( + 'class' => 'LoggerLayoutSimple' + ) + ), + 'app2' => array( + 'class' => 'LoggerAppenderEcho', + 'layout' => array( + 'class' => 'LoggerLayoutPattern', + 'params' => array( + 'conversionPattern' => 'message: %m%n' + ) + ) + ), + ) + )); + + ob_start(); + Logger::getRootLogger()->info('info'); + $actual = ob_get_contents(); + ob_end_clean(); + + $expected = "INFO - info" . PHP_EOL . "message: info" . PHP_EOL; + $this->assertSame($expected, $actual); + } + } \ No newline at end of file Modified: logging/log4php/trunk/src/test/php/LoggerTest.php URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/test/php/LoggerTest.php?rev=1184770&r1=1184769&r2=1184770&view=diff ============================================================================== --- logging/log4php/trunk/src/test/php/LoggerTest.php (original) +++ logging/log4php/trunk/src/test/php/LoggerTest.php Sun Oct 16 07:12:49 2011 @@ -40,7 +40,6 @@ class LoggerTest extends PHPUnit_Framewo public function testLoggerExist() { $l = Logger::getLogger('test'); self::assertEquals($l->getName(), 'test'); - $l->debug('test'); self::assertTrue(Logger::exists('test')); } @@ -55,7 +54,7 @@ class LoggerTest extends PHPUnit_Framewo } public function testCanLogToAllLevels() { - Logger::configure('LoggerTest.properties'); + Logger::configure(dirname(__FILE__) . '/LoggerTest.properties'); $logger = Logger::getLogger('mylogger'); ob_start(); @@ -78,7 +77,7 @@ class LoggerTest extends PHPUnit_Framewo } public function testIsEnabledFor() { - Logger::configure('LoggerTest.properties'); + Logger::configure(dirname(__FILE__) . '/LoggerTest.properties'); $logger = Logger::getLogger('mylogger'); @@ -97,34 +96,10 @@ class LoggerTest extends PHPUnit_Framewo self::assertEquals(0, count(Logger::getCurrentLoggers())); - Logger::configure('LoggerTest.properties'); - Logger::initialize(); + Logger::configure(dirname(__FILE__) . '/LoggerTest.properties'); self::assertEquals(1, count(Logger::getCurrentLoggers())); $list = Logger::getCurrentLoggers(); self::assertEquals('mylogger', $list[0]->getName()); } - - public function testConfigure() { - Logger::resetConfiguration(); - Logger::configure(); - self::assertEquals('LoggerConfiguratorBasic', Logger::getConfigurationClass()); - self::assertEquals(null, Logger::getConfigurationFile()); - - Logger::configure(null, 'MyLoggerClass'); - self::assertEquals('MyLoggerClass', Logger::getConfigurationClass()); - self::assertEquals(null, Logger::getConfigurationFile()); - - Logger::configure('log4php.xml'); - self::assertEquals('LoggerConfiguratorXml', Logger::getConfigurationClass()); - self::assertEquals('log4php.xml', Logger::getConfigurationFile()); - - Logger::configure('log4php.xml'); - self::assertEquals('LoggerConfiguratorXml', Logger::getConfigurationClass()); - self::assertEquals('log4php.xml', Logger::getConfigurationFile()); - - Logger::configure('log4php.properties'); - self::assertEquals('LoggerConfiguratorIni', Logger::getConfigurationClass()); - self::assertEquals('log4php.properties', Logger::getConfigurationFile()); - - } + } Added: logging/log4php/trunk/src/test/php/LoggerTestHelper.php URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/test/php/LoggerTestHelper.php?rev=1184770&view=auto ============================================================================== --- logging/log4php/trunk/src/test/php/LoggerTestHelper.php (added) +++ logging/log4php/trunk/src/test/php/LoggerTestHelper.php Sun Oct 16 07:12:49 2011 @@ -0,0 +1,92 @@ + 'ALL', + 'rootLogger' => array( + 'level' => 'trace', + 'appenders' => array('default'), + ), + 'appenders' => array( + 'default' => array( + 'class' => 'LoggerAppenderEcho', + 'layout' => array( + 'class' => 'LoggerLayoutSimple', + ), + ), + ), + ); + } +} + +?> \ No newline at end of file Modified: logging/log4php/trunk/src/test/php/LoggerThrowableInformationTest.php URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/test/php/LoggerThrowableInformationTest.php?rev=1184770&r1=1184769&r2=1184770&view=diff ============================================================================== --- logging/log4php/trunk/src/test/php/LoggerThrowableInformationTest.php (original) +++ logging/log4php/trunk/src/test/php/LoggerThrowableInformationTest.php Sun Oct 16 07:12:49 2011 @@ -26,17 +26,7 @@ * @group main */ class LoggerThrowableInformationTest extends PHPUnit_Framework_TestCase { - - protected static $logger; - - public static function setUpBeforeClass() { - self::$logger = Logger::getLogger('test'); - } - - public static function tearDownAfterClass() { - self::$logger = null; - } - + public function testConstructor() { $ex = new Exception(); $tInfo = new LoggerThrowableInformation($ex); Modified: logging/log4php/trunk/src/test/php/appenders/LoggerAppenderConsoleTest.php URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/test/php/appenders/LoggerAppenderConsoleTest.php?rev=1184770&r1=1184769&r2=1184770&view=diff ============================================================================== --- logging/log4php/trunk/src/test/php/appenders/LoggerAppenderConsoleTest.php (original) +++ logging/log4php/trunk/src/test/php/appenders/LoggerAppenderConsoleTest.php Sun Oct 16 07:12:49 2011 @@ -25,55 +25,66 @@ /** * @group appenders - * - * FIXME: Currently clutters the phpunit output as output buffering seems not - * to work for fwrite(STDOUT, ...) */ class LoggerAppenderConsoleTest extends PHPUnit_Framework_TestCase { - - private $event; - public function setUp() - { - $logger = new Logger('mycategory'); - $level = LoggerLevel::getLevelWarn(); - $this->event = new LoggerLoggingEvent(__CLASS__, $logger, $level, "my message"); - } + private $config = array( + 'rootLogger' => array( + 'appenders' => array('default'), + ), + 'appenders' => array( + 'default' => array( + 'class' => 'LoggerAppenderConsole', + 'layout' => array( + 'class' => 'LoggerLayoutPattern', + 'params' => array( + // Intentionally blank so output doesn't clutter phpunit output + 'conversionPattern' => '' + ) + ), + ) + ) + ); public function testRequiresLayout() { $appender = new LoggerAppenderConsole(); self::assertTrue($appender->requiresLayout()); } - public function testSimpleStdOutLogging() { - $layout = new LoggerLayoutSimple(); + public function testAppendDefault() { + Logger::configure($this->config); + $log = Logger::getRootLogger(); + + $expected = LoggerAppenderConsole::STDOUT; + $actual = $log->getAppender('default')->getTarget(); + $this->assertSame($expected, $actual); - $appender = new LoggerAppenderConsole("mylogger"); - $appender->setTarget('STDOUT'); - $appender->setLayout($layout); - $appender->activateOptions(); - $appender->append($this->event); - $appender->close(); + $log->info("hello"); } - public function testSimpleStdErrLogging() { - $layout = new LoggerLayoutSimple(); + public function testAppendStdout() { + $this->config['appenders']['default']['params']['target'] = 'stdout'; - $appender = new LoggerAppenderConsole("mylogger"); - $appender->setTarget('STDERR'); - $appender->setLayout($layout); - $appender->activateOptions(); - $appender->append($this->event); - $appender->close(); - } - - public function testSimpleDefaultLogging() { - $layout = new LoggerLayoutSimple(); + Logger::configure($this->config); + $log = Logger::getRootLogger(); + + $expected = LoggerAppenderConsole::STDOUT; + $actual = $log->getAppender('default')->getTarget(); + $this->assertSame($expected, $actual); + + $log->info("hello"); + } + + public function testAppendStderr() { + $this->config['appenders']['default']['params']['target'] = 'stderr'; - $appender = new LoggerAppenderConsole("mylogger"); - $appender->setLayout($layout); - $appender->activateOptions(); - $appender->append($this->event); - $appender->close(); + Logger::configure($this->config); + $log = Logger::getRootLogger(); + $expected = LoggerAppenderConsole::STDERR; + + $actual = $log->getAppender('default')->getTarget(); + $this->assertSame($expected, $actual); + + $log->info("hello"); } } Modified: logging/log4php/trunk/src/test/php/appenders/LoggerAppenderEchoTest.php URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/test/php/appenders/LoggerAppenderEchoTest.php?rev=1184770&r1=1184769&r2=1184770&view=diff ============================================================================== --- logging/log4php/trunk/src/test/php/appenders/LoggerAppenderEchoTest.php (original) +++ logging/log4php/trunk/src/test/php/appenders/LoggerAppenderEchoTest.php Sun Oct 16 07:12:49 2011 @@ -28,6 +28,91 @@ */ class LoggerAppenderEchoTest extends PHPUnit_Framework_TestCase { + private $config1 = array( + 'rootLogger' => array( + 'appenders' => array('default'), + ), + 'appenders' => array( + 'default' => array( + 'class' => 'LoggerAppenderEcho', + 'layout' => array( + 'class' => 'LoggerLayoutSimple' + ), + ) + ) + ); + + private $config2 = array( + 'rootLogger' => array( + 'appenders' => array('default'), + ), + 'appenders' => array( + 'default' => array( + 'class' => 'LoggerAppenderEcho', + 'layout' => array( + 'class' => 'LoggerLayoutSimple' + ), + 'params' => array( + 'htmlLineBreaks' => true + ) + ) + ) + ); + + private $config3 = array( + 'rootLogger' => array( + 'appenders' => array('default'), + ), + 'appenders' => array( + 'default' => array( + 'class' => 'LoggerAppenderEcho', + 'layout' => array( + 'class' => 'LoggerLayoutSimple' + ), + 'params' => array( + 'htmlLineBreaks' => 'foo' + ) + ) + ) + ); + + public function testAppend() { + Logger::configure($this->config1); + $log = Logger::getRootLogger(); + + $hlb = $log->getAppender('default')->getHtmlLineBreaks(); + $this->assertSame(false, $hlb); + + ob_start(); + $log->info("This is a test"); + $log->debug("And this too"); + $actual = ob_get_clean(); + $expected = "INFO - This is a test" . PHP_EOL . "DEBUG - And this too". PHP_EOL; + + $this->assertSame($expected, $actual); + } + + public function testHtmlLineBreaks() { + Logger::configure($this->config2); + $log = Logger::getRootLogger(); + + $hlb = $log->getAppender('default')->getHtmlLineBreaks(); + $this->assertSame(true, $hlb); + + ob_start(); + $log->info("This is a test" . PHP_EOL . "With more than one line"); + $log->debug("And this too"); + $actual = ob_get_clean(); + $expected = "INFO - This is a test
" . PHP_EOL . "With more than one line
" . PHP_EOL . "DEBUG - And this too
" . PHP_EOL; + + $this->assertSame($expected, $actual); + } + +// public function testHtmlLineBreaksInvalidOption() { +// Logger::configure($this->config3); +// } + + public function testEcho() { $appender = new LoggerAppenderEcho("myname "); Modified: logging/log4php/trunk/src/test/php/appenders/LoggerAppenderFileTest.php URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/test/php/appenders/LoggerAppenderFileTest.php?rev=1184770&r1=1184769&r2=1184770&view=diff ============================================================================== --- logging/log4php/trunk/src/test/php/appenders/LoggerAppenderFileTest.php (original) +++ logging/log4php/trunk/src/test/php/appenders/LoggerAppenderFileTest.php Sun Oct 16 07:12:49 2011 @@ -7,7 +7,7 @@ * (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 + * 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, @@ -16,58 +16,105 @@ * limitations under the License. * * @category tests - * @package log4php + * @package log4php * @subpackage appenders - * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 - * @version SVN: $Id$ - * @link http://logging.apache.org/log4php + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @version SVN: $Id$ + * @link http://logging.apache.org/log4php */ /** * @group appenders */ class LoggerAppenderFileTest extends PHPUnit_Framework_TestCase { - + + private $config1 = array( + 'rootLogger' => array( + 'appenders' => array('default'), + ), + 'appenders' => array( + 'default' => array( + 'class' => 'LoggerAppenderFile', + 'layout' => array( + 'class' => 'LoggerLayoutSimple' + ), + 'params' => array() + ) + ) + ); + private $testPath; public function __construct() { - $this->testPath = dirname(__FILE__) . '/../../../../target/temp/phpunit/TEST.txt'; + $this->testPath = PHPUNIT_TEMP_DIR . '/TEST.txt'; + } + + public function setUp() { + Logger::resetConfiguration(); + if(file_exists($this->testPath)) { + unlink($this->testPath); + } + } + + public function tearDown() { + Logger::resetConfiguration(); + if(file_exists($this->testPath)) { + unlink($this->testPath); + } } - protected function setUp() { - if(file_exists($this->testPath)) { - unlink($this->testPath); - } - } - public function testRequiresLayout() { $appender = new LoggerAppenderFile(); self::assertTrue($appender->requiresLayout()); } - public function testSimpleLogging() { - $layout = new LoggerLayoutSimple(); - - $event = new LoggerLoggingEvent('LoggerAppenderFileTest', - new Logger('mycategory'), - LoggerLevel::getLevelWarn(), - "my message"); - - $appender = new LoggerAppenderFile("mylogger"); - $appender->setFile($this->testPath); - $appender->setLayout($layout); - $appender->activateOptions(); - $appender->append($event); - $appender->close(); - - $v = file_get_contents($this->testPath); - $e = "WARN - my message".PHP_EOL; - self::assertEquals($e, $v); - } - - protected function tearDown() { - if(file_exists($this->testPath)) { - unlink($this->testPath); - } - } + public function testSimpleLogging() { + $config = $this->config1; + $config['appenders']['default']['params']['file'] = $this->testPath; + + Logger::configure($config); + + $logger = Logger::getRootLogger(); + $logger->info('This is a test'); + + $expected = "INFO - This is a test" . PHP_EOL; + $actual = file_get_contents($this->testPath); + $this->assertSame($expected, $actual); + } + + public function testAppendFlagTrue() { + $config = $this->config1; + $config['appenders']['default']['params']['file'] = $this->testPath; + $config['appenders']['default']['params']['append'] = true; + + Logger::configure($config); + $logger = Logger::getRootLogger(); + $logger->info('This is a test'); + + Logger::configure($config); + $logger = Logger::getRootLogger(); + $logger->info('This is a test'); + + $expected = "INFO - This is a test" . PHP_EOL . "INFO - This is a test" . PHP_EOL; + $actual = file_get_contents($this->testPath); + $this->assertSame($expected, $actual); + } + + public function testAppendFlagFalse() { + $config = $this->config1; + $config['appenders']['default']['params']['file'] = $this->testPath; + $config['appenders']['default']['params']['append'] = false; + + Logger::configure($config); + $logger = Logger::getRootLogger(); + $logger->info('This is a test'); + + Logger::configure($config); + $logger = Logger::getRootLogger(); + $logger->info('This is a test'); + + $expected = "INFO - This is a test" . PHP_EOL; + $actual = file_get_contents($this->testPath); + $this->assertSame($expected, $actual); + } } Modified: logging/log4php/trunk/src/test/php/appenders/LoggerAppenderPhpTest.php URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/test/php/appenders/LoggerAppenderPhpTest.php?rev=1184770&r1=1184769&r2=1184770&view=diff ============================================================================== --- logging/log4php/trunk/src/test/php/appenders/LoggerAppenderPhpTest.php (original) +++ logging/log4php/trunk/src/test/php/appenders/LoggerAppenderPhpTest.php Sun Oct 16 07:12:49 2011 @@ -24,49 +24,71 @@ */ function errorHandler($errno, $errstr, $errfile, $errline) { - switch ($errno) { - case E_USER_ERROR: - PHPUnit_Framework_TestCase::assertEquals($errstr, "ERROR - testmessage".PHP_EOL); - break; - case E_USER_WARNING: - PHPUnit_Framework_TestCase::assertEquals($errstr, "WARN - testmessage".PHP_EOL); - break; - case E_USER_NOTICE: - PHPUnit_Framework_TestCase::assertEquals($errstr, "DEBUG - testmessage".PHP_EOL); - break; - default: - PHPUnit_Framework_TestCase::assertTrue(false); - } + PHPUnit_Framework_TestCase::assertEquals(LoggerAppenderPhpTest::$expectedError, $errno); + PHPUnit_Framework_TestCase::assertEquals(LoggerAppenderPhpTest::$expectedMessage, $errstr); } - /** * @group appenders */ class LoggerAppenderPhpTest extends PHPUnit_Framework_TestCase { + + public static $expectedMessage; + + public static $expectedError; + + private $config = array( + 'rootLogger' => array( + 'appenders' => array('default'), + 'level' => 'trace' + ), + 'appenders' => array( + 'default' => array( + 'class' => 'LoggerAppenderPHP', + 'layout' => array( + 'class' => 'LoggerLayoutSimple' + ), + ) + ) + ); + protected function setUp() { set_error_handler("errorHandler"); } - + public function testRequiresLayout() { $appender = new LoggerAppenderPhp(); - self::assertTrue($appender->requiresLayout()); + $this->assertTrue($appender->requiresLayout()); } public function testPhp() { - $appender = new LoggerAppenderPhp("TEST"); + Logger::configure($this->config); + $logger = Logger::getRootLogger(); + + + self::$expectedError = E_USER_ERROR; + self::$expectedMessage = "FATAL - This is a test" . PHP_EOL; + $logger->fatal("This is a test"); + + self::$expectedError = E_USER_ERROR; + self::$expectedMessage = "ERROR - This is a test" . PHP_EOL; + $logger->error("This is a test"); + + self::$expectedError = E_USER_WARNING; + self::$expectedMessage = "WARN - This is a test" . PHP_EOL; + $logger->warn("This is a test"); - $layout = new LoggerLayoutSimple(); - $appender->setLayout($layout); - $appender->activateOptions(); - $event = new LoggerLoggingEvent("LoggerAppenderPhpTest", new Logger("TEST"), LoggerLevel::getLevelError(), "testmessage"); - $appender->append($event); + self::$expectedError = E_USER_NOTICE; + self::$expectedMessage = "INFO - This is a test" . PHP_EOL; + $logger->info("This is a test"); - $event = new LoggerLoggingEvent("LoggerAppenderPhpTest", new Logger("TEST"), LoggerLevel::getLevelWarn(), "testmessage"); - $appender->append($event); + self::$expectedError = E_USER_NOTICE; + self::$expectedMessage = "DEBUG - This is a test" . PHP_EOL; + $logger->debug("This is a test"); - $event = new LoggerLoggingEvent("LoggerAppenderPhpTest", new Logger("TEST"), LoggerLevel::getLevelDebug(), "testmessage"); - $appender->append($event); + self::$expectedError = E_USER_NOTICE; + self::$expectedMessage = "TRACE - This is a test" . PHP_EOL; + $logger->trace("This is a test"); } protected function tearDown() { Modified: logging/log4php/trunk/src/test/php/bootstrap.php URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/test/php/bootstrap.php?rev=1184770&r1=1184769&r2=1184770&view=diff ============================================================================== --- logging/log4php/trunk/src/test/php/bootstrap.php (original) +++ logging/log4php/trunk/src/test/php/bootstrap.php Sun Oct 16 07:12:49 2011 @@ -26,4 +26,12 @@ error_reporting(E_ALL | E_STRICT); date_default_timezone_set('Europe/London'); +// Define a temp dir where tests may write to +$tmpDir = dirname(__FILE__) . '/../../../target/temp/phpunit'; +if (!is_dir($tmpDir)) { + mkdir($tmpDir, 0777, true); +} +define('PHPUNIT_TEMP_DIR', realpath($tmpDir)); + require dirname(__FILE__) . '/../../main/php/Logger.php'; + Added: logging/log4php/trunk/src/test/php/configurators/LoggerConfigurationAdapterINITest.php URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/test/php/configurators/LoggerConfigurationAdapterINITest.php?rev=1184770&view=auto ============================================================================== --- logging/log4php/trunk/src/test/php/configurators/LoggerConfigurationAdapterINITest.php (added) +++ logging/log4php/trunk/src/test/php/configurators/LoggerConfigurationAdapterINITest.php Sun Oct 16 07:12:49 2011 @@ -0,0 +1,135 @@ + 'debug', + 'rootLogger' => array( + 'level' => 'DEBUG', + 'appenders' => array('default'), + ), + 'appenders' => array( + 'default' => array( + 'class' => 'LoggerAppenderEcho', + 'layout' => array( + 'class' => 'LoggerLayoutTTCC', + ), + ), + 'file' => array( + 'class' => 'LoggerAppenderDailyFile', + 'layout' => array( + 'class' => 'LoggerLayoutPattern', + 'params' => array( + 'conversionPattern' => '%d{ISO8601} [%p] %c: %m (at %F line %L)%n', + ), + ), + 'params' => array( + 'datePattern' => 'Ymd', + 'file' => 'target/examples/daily_%s.log', + ), + 'threshold' => 'warn' + ), + ), + 'loggers' => array( + 'foo' => array( + 'level' => 'warn', + 'appenders' => array('default'), + ), + 'foo.bar' => array( + 'level' => 'debug', + 'appenders' => array('file'), + 'additivity' => 'true', + ), + 'foo.bar.baz' => array( + 'level' => 'trace', + 'appenders' => array('default', 'file'), + 'additivity' => 'false', + ), + ), + 'renderers' => array( + array( + 'renderedClass' => 'Fruit', + 'renderingClass' => 'FruitRenderer', + ), + array( + 'renderedClass' => 'Beer', + 'renderingClass' => 'BeerRenderer', + ), + ), + ); + + public function testConfig() { + $url = dirname(__FILE__) . '/config1.ini'; + $adapter = new LoggerConfigurationAdapterINI(); + $actual = $adapter->convert($url); + + $this->assertSame($this->expected1, $actual); + } + + /** + * Test exception is thrown when file cannot be found. + * @expectedException LoggerException + * @expectedExceptionMessage File [you/will/never/find/me.ini] does not exist. + */ + public function testNonExistantFileException() { + $adapter = new LoggerConfigurationAdapterINI(); + $adapter->convert('you/will/never/find/me.ini'); + } + + /** + * Test exception is thrown when file is not a valid ini file. + * @expectedException LoggerException + * @expectedExceptionMessage Error parsing configuration file: syntax error + */ + public function testInvalidFileException() { + $url = dirname(__FILE__) . '/config2.ini'; + $adapter = new LoggerConfigurationAdapterINI(); + $adapter->convert($url); + } + + /** + * Test a warning is triggered when configurator doesn't understand a line. + * @expectedException PHPUnit_Framework_Error + * @expectedExceptionMessage log4php: Don't know how to parse the following line: "log4php.appender.default.layout.param.bla = LoggerLayoutTTCC". Skipping. + */ + public function testInvalidLineWarning1() { + $url = dirname(__FILE__) . '/config3.ini'; + $adapter = new LoggerConfigurationAdapterINI(); + $adapter->convert($url); + } + + /** + * Test a warning is triggered when configurator doesn't understand a line. + * @expectedException PHPUnit_Framework_Error + * @expectedExceptionMessage log4php: Don't know how to parse the following line: "log4php.appender.default.not-layout.param = LoggerLayoutTTCC". Skipping. + */ + public function testInvalidLineWarning2() { + $url = dirname(__FILE__) . '/config4.ini'; + $adapter = new LoggerConfigurationAdapterINI(); + $adapter->convert($url); + } +} + +?> \ No newline at end of file Added: logging/log4php/trunk/src/test/php/configurators/LoggerConfigurationAdapterPHPTest.php URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/test/php/configurators/LoggerConfigurationAdapterPHPTest.php?rev=1184770&view=auto ============================================================================== --- logging/log4php/trunk/src/test/php/configurators/LoggerConfigurationAdapterPHPTest.php (added) +++ logging/log4php/trunk/src/test/php/configurators/LoggerConfigurationAdapterPHPTest.php Sun Oct 16 07:12:49 2011 @@ -0,0 +1,96 @@ + array( + 'level' => 'info', + 'appenders' => array('default') + ), + 'appenders' => array( + 'default' => array( + 'class' => 'LoggerAppenderEcho', + 'layout' => array( + 'class' => 'LoggerLayoutSimple' + ) + ) + ) + ); + + public function testConfig() { + $url = dirname(__FILE__) . '/config1.php'; + $adapter = new LoggerConfigurationAdapterPHP(); + $actual = $adapter->convert($url); + + $this->assertSame($this->expected1, $actual); + } + + /** + * Test exception is thrown when file cannot be found. + * @expectedException LoggerException + * @expectedExceptionMessage File [you/will/never/find/me.conf] does not exist. + */ + public function testNonExistantFileWarning() { + $adapter = new LoggerConfigurationAdapterPHP(); + $adapter->convert('you/will/never/find/me.conf'); + } + + /** + * Test exception is thrown when file is not valid. + * @expectedException LoggerException + * @expectedExceptionMessage Error parsing configuration: syntax error + */ + public function testInvalidFileWarning() { + $url = dirname(__FILE__) . '/config2.php'; + $adapter = new LoggerConfigurationAdapterPHP(); + $adapter->convert($url); + } + + /** + * Test exception is thrown when the configuration is empty. + * @expectedException LoggerException + * @expectedExceptionMessage Invalid configuration: empty configuration array. + */ + public function testEmptyConfigWarning() { + $url = dirname(__FILE__) . '/config3.php'; + $adapter = new LoggerConfigurationAdapterPHP(); + $adapter->convert($url); + } + + /** + * Test exception is thrown when the configuration does not contain an array. + * @expectedException LoggerException + * @expectedExceptionMessage Invalid configuration: not an array. + */ + public function testInvalidConfigWarning() { + $url = dirname(__FILE__) . '/config4.php'; + $adapter = new LoggerConfigurationAdapterPHP(); + $adapter->convert($url); + } + + +} + +?> \ No newline at end of file