You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by ih...@apache.org on 2013/11/28 17:03:55 UTC
[25/43] LOG4PHP-121: Reorganized classes into namespaces
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Helpers/FormattingInfo.php
----------------------------------------------------------------------
diff --git a/src/Helpers/FormattingInfo.php b/src/Helpers/FormattingInfo.php
new file mode 100644
index 0000000..9f2bb3b
--- /dev/null
+++ b/src/Helpers/FormattingInfo.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * 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.
+ */
+
+namespace Apache\Log4php\Helpers;
+
+/**
+ * This class encapsulates the information obtained when parsing
+ * formatting modifiers in conversion modifiers.
+ * @since 0.3
+ */
+class FormattingInfo {
+
+ /**
+ * Minimal output length. If output is shorter than this value, it will be
+ * padded with spaces.
+ */
+ public $min = 0;
+
+ /**
+ * Maximum output length. If output is longer than this value, it will be
+ * trimmed.
+ */
+ public $max = PHP_INT_MAX;
+
+ /**
+ * Whether to pad the string from the left. If set to false, the string
+ * will be padded from the right.
+ */
+ public $padLeft = true;
+
+ /**
+ * Whether to trim the string from the left. If set to false, the string
+ * will be trimmed from the right.
+ */
+ public $trimLeft = false;
+}
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Helpers/OptionConverter.php
----------------------------------------------------------------------
diff --git a/src/Helpers/OptionConverter.php b/src/Helpers/OptionConverter.php
new file mode 100644
index 0000000..c496f02
--- /dev/null
+++ b/src/Helpers/OptionConverter.php
@@ -0,0 +1,225 @@
+<?php
+/**
+ * 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.
+ */
+
+namespace Apache\Log4php\Helpers;
+
+use Apache\Log4php\Level;
+use Apache\Log4php\LoggerException;
+
+/**
+ * A convenience class to convert property values to specific types.
+ * @since 0.5
+ */
+class OptionConverter {
+
+ /** String values which are converted to boolean TRUE. */
+ private static $trueValues = array('1', 'true', 'yes', 'on');
+
+ /**
+ * String values which are converted to boolean FALSE.
+ *
+ * Note that an empty string must convert to false, because
+ * parse_ini_file() which is used for parsing configuration
+ * converts the value _false_ to an empty string.
+ */
+ private static $falseValues = array('0', 'false', 'no', 'off', '');
+
+ /**
+ * Read a predefined var.
+ *
+ * It returns a value referenced by <var>$key</var> using this search criteria:
+ * - if <var>$key</var> is a constant then return it. Else
+ * - if <var>$key</var> is set in <var>$_ENV</var> then return it. Else
+ * - return <var>$def</var>.
+ *
+ * @param string $key The key to search for.
+ * @param string $def The default value to return.
+ * @return string the string value of the system property, or the default
+ * value if there is no property with that key.
+ */
+ public static function getSystemProperty($key, $def) {
+ if(defined($key)) {
+ return (string)constant($key);
+ } else if(isset($_SERVER[$key])) {
+ return (string)$_SERVER[$key];
+ } else if(isset($_ENV[$key])) {
+ return (string)$_ENV[$key];
+ } else {
+ return $def;
+ }
+ }
+
+ /** Converts $value to boolean, or throws an exception if not possible. */
+ public static function toBooleanEx($value) {
+ if (isset($value)) {
+ if (is_bool($value)) {
+ return $value;
+ }
+ $value = strtolower(trim($value));
+ if (in_array($value, self::$trueValues)) {
+ return true;
+ }
+ if (in_array($value, self::$falseValues)) {
+ return false;
+ }
+ }
+
+ throw new LoggerException("Given value [" . var_export($value, true) . "] cannot be converted to boolean.");
+ }
+
+ /**
+ * Converts $value to integer, or throws an exception if not possible.
+ * Floats cannot be converted to integer.
+ */
+ public static function toIntegerEx($value) {
+ if (is_integer($value)) {
+ return $value;
+ }
+ if (is_numeric($value) && ($value == (integer) $value)) {
+ return (integer) $value;
+ }
+
+ throw new LoggerException("Given value [" . var_export($value, true) . "] cannot be converted to integer.");
+ }
+
+ /**
+ * Converts $value to integer, or throws an exception if not possible.
+ * Floats cannot be converted to integer.
+ */
+ public static function toPositiveIntegerEx($value) {
+ if (is_integer($value) && $value > 0) {
+ return $value;
+ }
+ if (is_numeric($value) && ($value == (integer) $value) && $value > 0) {
+ return (integer) $value;
+ }
+
+ throw new LoggerException("Given value [" . var_export($value, true) . "] cannot be converted to a positive integer.");
+ }
+
+ /** Converts the value to a level. Throws an exception if not possible. */
+ public static function toLevelEx($value) {
+ if ($value instanceof Level) {
+ return $value;
+ }
+ $level = Level::toLevel($value);
+ if ($level === null) {
+ throw new LoggerException("Given value [" . var_export($value, true) . "] cannot be converted to a logger level.");
+ }
+ return $level;
+ }
+
+ /**
+ * Converts a value to a valid file size (integer).
+ *
+ * Supports 'KB', 'MB' and 'GB' suffixes, where KB = 1024 B etc.
+ *
+ * The final value will be rounded to the nearest integer.
+ *
+ * Examples:
+ * - '100' => 100
+ * - '100.12' => 100
+ * - '100KB' => 102400
+ * - '1.5MB' => 1572864
+ *
+ * @param mixed $value File size (optionally with suffix).
+ * @return integer Parsed file size.
+ */
+ public static function toFileSizeEx($value) {
+
+ if (empty($value)) {
+ throw new LoggerException("Empty value cannot be converted to a file size.");
+ }
+
+ if (is_numeric($value)) {
+ return (integer) $value;
+ }
+
+ if (!is_string($value)) {
+ throw new LoggerException("Given value [" . var_export($value, true) . "] cannot be converted to a file size.");
+ }
+
+ $str = strtoupper(trim($value));
+ $count = preg_match('/^([0-9.]+)(KB|MB|GB)?$/', $str, $matches);
+
+ if ($count > 0) {
+ $size = $matches[1];
+ $unit = $matches[2];
+
+ switch($unit) {
+ case 'KB': $size *= pow(1024, 1); break;
+ case 'MB': $size *= pow(1024, 2); break;
+ case 'GB': $size *= pow(1024, 3); break;
+ }
+
+ return (integer) $size;
+ }
+
+ throw new LoggerException("Given value [$value] cannot be converted to a file size.");
+ }
+
+ /**
+ * Converts a value to string, or throws an exception if not possible.
+ *
+ * Objects can be converted to string if they implement the magic
+ * __toString() method.
+ *
+ */
+ public static function toStringEx($value) {
+ if (is_string($value)) {
+ return $value;
+ }
+ if (is_numeric($value)) {
+ return (string) $value;
+ }
+ if (is_object($value) && method_exists($value, '__toString')) {
+ return (string) $value;
+ }
+
+ throw new LoggerException("Given value [" . var_export($value, true) . "] cannot be converted to string.");
+ }
+
+ /**
+ * Performs value substitution for string options.
+ *
+ * An option can contain PHP constants delimited by '${' and '}'.
+ *
+ * E.g. for input string "some ${FOO} value", the method will attempt
+ * to substitute ${FOO} with the value of constant FOO if it exists.
+ *
+ * Therefore, if FOO is a constant, and it has value "bar", the resulting
+ * string will be "some bar value".
+ *
+ * If the constant is not defined, it will be replaced by an empty string,
+ * and the resulting string will be "some value".
+ *
+ * @param string $string String on which to perform substitution.
+ * @return string
+ */
+ public static function substConstants($string) {
+ preg_match_all('/\${([^}]+)}/', $string, $matches);
+
+ foreach($matches[1] as $key => $match) {
+ $match = trim($match);
+ $search = $matches[0][$key];
+ $replacement = defined($match) ? constant($match) : '';
+ $string = str_replace($search, $replacement, $string);
+ }
+ return $string;
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Helpers/PatternParser.php
----------------------------------------------------------------------
diff --git a/src/Helpers/PatternParser.php b/src/Helpers/PatternParser.php
new file mode 100644
index 0000000..7e98a55
--- /dev/null
+++ b/src/Helpers/PatternParser.php
@@ -0,0 +1,245 @@
+<?php
+/**
+ * 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.
+ */
+
+namespace Apache\Log4php\Helpers;
+
+use Apache\Log4php\LoggerException;
+use Apache\Log4php\Pattern\AbstractConverter;
+use Apache\Log4php\Pattern\LiteralConverter;
+
+/**
+ * Most of the work of the {@link LoggerPatternLayout} class
+ * is delegated to the {@link PatternParser} class.
+ *
+ * <p>It is this class that parses conversion patterns and creates
+ * a chained list of {@link AbstractConverter} converters.</p>
+ *
+ * @since 0.3
+ */
+class PatternParser {
+
+ /** Escape character for conversion words in the conversion pattern. */
+ const ESCAPE_CHAR = '%';
+
+ /** Maps conversion words to relevant converters. */
+ private $converterMap;
+
+ /** Conversion pattern used in layout. */
+ private $pattern;
+
+ /** Regex pattern used for parsing the conversion pattern. */
+ private $regex;
+
+ /**
+ * First converter in the chain.
+ * @var AbstractConverter
+ */
+ private $head;
+
+ /** Last converter in the chain. */
+ private $tail;
+
+ public function __construct($pattern, $converterMap) {
+ $this->pattern = $pattern;
+ $this->converterMap = $converterMap;
+
+ // Construct the regex pattern
+ $this->regex =
+ '/' . // Starting regex pattern delimiter
+ self::ESCAPE_CHAR . // Character which marks the start of the conversion pattern
+ '(?P<modifiers>[0-9.-]*)' . // Format modifiers (optional)
+ '(?P<word>[a-zA-Z]+)' . // The conversion word
+ '(?P<option>{[^}]*})?' . // Conversion option in braces (optional)
+ '/'; // Ending regex pattern delimiter
+ }
+
+ /**
+ * Parses the conversion pattern string, converts it to a chain of pattern
+ * converters and returns the first converter in the chain.
+ *
+ * @return AbstractConverter
+ */
+ public function parse() {
+
+ // Skip parsing if the pattern is empty
+ if (empty($this->pattern)) {
+ $this->addLiteral('');
+ return $this->head;
+ }
+
+ // Find all conversion words in the conversion pattern
+ $count = preg_match_all($this->regex, $this->pattern, $matches, PREG_OFFSET_CAPTURE);
+ if ($count === false) {
+ $error = error_get_last();
+ throw new LoggerException("Failed parsing layotut pattern: {$error['message']}");
+ }
+
+ $prevEnd = 0;
+
+ foreach($matches[0] as $key => $item) {
+
+ // Locate where the conversion command starts and ends
+ $length = strlen($item[0]);
+ $start = $item[1];
+ $end = $item[1] + $length;
+
+ // Find any literal expressions between matched commands
+ if ($start > $prevEnd) {
+ $literal = substr($this->pattern, $prevEnd, $start - $prevEnd);
+ $this->addLiteral($literal);
+ }
+
+ // Extract the data from the matched command
+ $word = !empty($matches['word'][$key]) ? $matches['word'][$key][0] : null;
+ $modifiers = !empty($matches['modifiers'][$key]) ? $matches['modifiers'][$key][0] : null;
+ $option = !empty($matches['option'][$key]) ? $matches['option'][$key][0] : null;
+
+ // Create a converter and add it to the chain
+ $this->addConverter($word, $modifiers, $option);
+
+ $prevEnd = $end;
+ }
+
+ // Add any trailing literals
+ if ($end < strlen($this->pattern)) {
+ $literal = substr($this->pattern, $end);
+ $this->addLiteral($literal);
+ }
+
+ return $this->head;
+ }
+
+ /**
+ * Adds a literal converter to the converter chain.
+ * @param string $string The string for the literal converter.
+ */
+ private function addLiteral($string) {
+ $converter = new LiteralConverter($string);
+ $this->addToChain($converter);
+ }
+
+ /**
+ * Adds a non-literal converter to the converter chain.
+ *
+ * @param string $word The conversion word, used to determine which
+ * converter will be used.
+ * @param string $modifiers Formatting modifiers.
+ * @param string $option Option to pass to the converter.
+ */
+ private function addConverter($word, $modifiers, $option) {
+ $formattingInfo = $this->parseModifiers($modifiers);
+ $option = trim($option, "{} ");
+
+ if (isset($this->converterMap[$word])) {
+ $converter = $this->getConverter($word, $formattingInfo, $option);
+ $this->addToChain($converter);
+ } else {
+ trigger_error("log4php: Invalid keyword '%$word' in converison pattern. Ignoring keyword.", E_USER_WARNING);
+ }
+ }
+
+ /**
+ * Determines which converter to use based on the conversion word. Creates
+ * an instance of the converter using the provided formatting info and
+ * option and returns it.
+ *
+ * @param string $word The conversion word.
+ * @param FormattingInfo $info Formatting info.
+ * @param string $option Converter option.
+ *
+ * @throws LoggerException
+ *
+ * @return AbstractConverter
+ */
+ private function getConverter($word, $info, $option) {
+ if (!isset($this->converterMap[$word])) {
+ throw new LoggerException("Invalid keyword '%$word' in converison pattern. Ignoring keyword.");
+ }
+
+ $class = $this->converterMap[$word];
+ if (class_exists($class)) {
+ $converter = new $class($info, $option);
+ } else {
+ $nsClass = "Apache\\Log4php\\Pattern\\$class";
+ if (class_exists($nsClass)) {
+ $converter = new $nsClass($info, $option);
+ }
+ }
+
+ if (!isset($converter)) {
+ throw new LoggerException("Class '$class' does not exist.");
+ }
+
+ if(!($converter instanceof AbstractConverter)) {
+ throw new LoggerException("Class '$class' is not an instance of AbstractConverter.");
+ }
+
+ return $converter;
+ }
+
+ /** Adds a converter to the chain and updates $head and $tail pointers. */
+ private function addToChain(AbstractConverter $converter) {
+ if (!isset($this->head)) {
+ $this->head = $converter;
+ $this->tail = $this->head;
+ } else {
+ $this->tail->next = $converter;
+ $this->tail = $this->tail->next;
+ }
+ }
+
+ /**
+ * Parses the formatting modifiers and produces the corresponding
+ * FormattingInfo object.
+ *
+ * @param string $modifier
+ * @return FormattingInfo
+ * @throws LoggerException
+ */
+ private function parseModifiers($modifiers) {
+ $info = new FormattingInfo();
+
+ // If no modifiers are given, return default values
+ if (empty($modifiers)) {
+ return $info;
+ }
+
+ // Validate
+ $pattern = '/^(-?[0-9]+)?\.?-?[0-9]+$/';
+ if (!preg_match($pattern, $modifiers)) {
+ trigger_error("log4php: Invalid modifier in conversion pattern: [$modifiers]. Ignoring modifier.", E_USER_WARNING);
+ return $info;
+ }
+
+ $parts = explode('.', $modifiers);
+
+ if (!empty($parts[0])) {
+ $minPart = (integer) $parts[0];
+ $info->min = abs($minPart);
+ $info->padLeft = ($minPart > 0);
+ }
+
+ if (!empty($parts[1])) {
+ $maxPart = (integer) $parts[1];
+ $info->max = abs($maxPart);
+ $info->trimLeft = ($maxPart < 0);
+ }
+
+ return $info;
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Helpers/Utils.php
----------------------------------------------------------------------
diff --git a/src/Helpers/Utils.php b/src/Helpers/Utils.php
new file mode 100644
index 0000000..52be24d
--- /dev/null
+++ b/src/Helpers/Utils.php
@@ -0,0 +1,120 @@
+<?php
+/**
+ * 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.
+ */
+
+namespace Apache\Log4php\Helpers;
+
+/**
+ * Contains various helper methods.
+ * @since 2.3
+ */
+class Utils {
+
+ /**
+ * Splits a fully qualified class name into fragments delimited by the
+ * namespace separator (\).
+ *
+ * For backward compatibility, a dot (.) can be used as a delimiter as
+ * well.
+ *
+ * @param string $name
+ *
+ * @return array Class name split into fragments.
+ */
+ public static function tokenizeClassName($name) {
+ $name = str_replace('.', '\\', $name);
+ $name = trim($name, ' \\');
+ $fragments = explode('\\', $name);
+
+ foreach($fragments as $key => $fragment) {
+ if (trim($fragment) === '') {
+ unset($fragments[$key]);
+ }
+ }
+
+ return $fragments;
+ }
+
+ /**
+ * Attempts to shorten the given class name to the desired length.
+ *
+ * This is done by separating the class name into fragments (delimited
+ * by \ or .) and trimming individual fragments, starting with the left,
+ * until desired length has been reached.
+ *
+ * The final fragment (i.e. class name) will never be shortened so the
+ * result may still be longer than given length.
+ *
+ * @param string $name The (qualified) class name.
+ * @param integer $length The length to shorten to. If null or 0 is given,
+ * the name will be returned without shortening.
+ */
+ public static function shortenClassName($name, $length) {
+ if ($length === null || $length < 0) {
+ return $name;
+ }
+
+ $name = str_replace('.', '\\', $name);
+ $name = trim($name, ' \\');
+
+ // Check if any shortening is required
+ $currentLength = strlen($name);
+ if ($currentLength <= $length) {
+ return $name;
+ }
+
+ // Split name into fragments
+ $fragments = explode('\\', $name);
+
+ // If zero length is specified, return only last fragment
+ if ($length == 0) {
+ return array_pop($fragments);
+ }
+
+ // If the name splits to only one fragment, then it cannot be shortened
+ $count = count($fragments);
+ if ($count == 1) {
+ return $name;
+ }
+
+ foreach($fragments as $key => &$fragment) {
+
+ // Never shorten last fragment
+ if ($key == $count - 1) {
+ break;
+ }
+
+ // Check for empty fragments (shouldn't happen but it's possible)
+ $fragLen = strlen($fragment);
+ if ($fragLen <= 1) {
+ continue;
+ }
+
+ // Shorten fragment to one character and check if total length satisfactory
+ $fragment = substr($fragment, 0, 1);
+ $currentLength = $currentLength - $fragLen + 1;
+
+ if ($currentLength <= $length) {
+ break;
+ }
+ }
+ unset($fragment);
+
+ return implode('\\', $fragments);
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Hierarchy.php
----------------------------------------------------------------------
diff --git a/src/Hierarchy.php b/src/Hierarchy.php
new file mode 100644
index 0000000..7b28a6b
--- /dev/null
+++ b/src/Hierarchy.php
@@ -0,0 +1,256 @@
+<?php
+/**
+ * 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.
+ */
+
+namespace Apache\Log4php;
+
+use Apache\Log4php\Renderers\RendererMap;
+
+/**
+ * This class is specialized in retrieving loggers by name and also maintaining
+ * the logger hierarchy. The logger hierarchy is dealing with the several Log-Levels
+ * Logger can have. From log4j website:
+ *
+ * "A logger is said to be an ancestor of another logger if its name followed
+ * by a dot is a prefix of the descendant logger name. A logger is said to be
+ * a parent of a child logger if there are no ancestors between itself and the
+ * descendant logger."
+ *
+ * Child Loggers do inherit their Log-Levels from their Ancestors. They can
+ * increase their Log-Level compared to their Ancestors, but they cannot decrease it.
+ *
+ * <p>The casual user does not have to deal with this class directly.</p>
+ *
+ * <p>The structure of the logger hierarchy is maintained by the
+ * getLogger method. The hierarchy is such that children link
+ * to their parent but parents do not have any pointers to their
+ * children. Moreover, loggers can be instantiated in any order, in
+ * particular descendant before ancestor.</p>
+ *
+ * <p>In case a descendant is created before a particular ancestor,
+ * then it creates a provision node for the ancestor and adds itself
+ * to the provision node. Other descendants of the same ancestor add
+ * themselves to the previously created provision node.</p>
+ */
+class Hierarchy {
+
+ /** Array holding all Logger instances. */
+ protected $loggers = array();
+
+ /**
+ * The root logger.
+ * @var RootLogger
+ */
+ protected $root;
+
+ /**
+ * The logger renderer map.
+ * @var RendererMap
+ */
+ protected $rendererMap;
+
+ /**
+ * Main level threshold. Events with lower level will not be logged by any
+ * logger, regardless of it's configuration.
+ * @var Level
+ */
+ protected $threshold;
+
+ /**
+ * Creates a new logger hierarchy.
+ * @param RootLogger $root The root logger.
+ */
+ public function __construct(RootLogger $root) {
+ $this->root = $root;
+ $this->setThreshold(Level::getLevelAll());
+ $this->rendererMap = new RendererMap();
+ }
+
+ /**
+ * Clears all loggers.
+ */
+ public function clear() {
+ $this->loggers = array();
+ }
+
+ /**
+ * Check if the named logger exists in the hierarchy.
+ * @param string $name
+ * @return boolean
+ */
+ public function exists($name) {
+ return isset($this->loggers[$name]);
+ }
+
+ /**
+ * Returns all the currently defined loggers in this hierarchy as an array.
+ * @return array
+ */
+ public function getCurrentLoggers() {
+ return array_values($this->loggers);
+ }
+
+ /**
+ * Returns a named logger instance logger. If it doesn't exist, one is created.
+ *
+ * @param string $name Logger name
+ * @return Logger Logger instance.
+ */
+ public function getLogger($name) {
+ if(!isset($this->loggers[$name])) {
+ $logger = new Logger($name);
+
+ $nodes = explode('.', $name);
+ $firstNode = array_shift($nodes);
+
+ // if name is not a first node but another first node is their
+ if($firstNode != $name and isset($this->loggers[$firstNode])) {
+ $logger->setParent($this->loggers[$firstNode]);
+ } else {
+ // if there is no father, set root logger as father
+ $logger->setParent($this->root);
+ }
+
+ // if there are more nodes than one
+ if(count($nodes) > 0) {
+ // find parent node
+ foreach($nodes as $node) {
+ $parentNode = "$firstNode.$node";
+ if(isset($this->loggers[$parentNode]) and $parentNode != $name) {
+ $logger->setParent($this->loggers[$parentNode]);
+ }
+ $firstNode .= ".$node";
+ }
+ }
+
+ $this->loggers[$name] = $logger;
+ }
+
+ return $this->loggers[$name];
+ }
+
+ /**
+ * Returns the logger renderer map.
+ * @return RendererMap
+ */
+ public function getRendererMap() {
+ return $this->rendererMap;
+ }
+
+ /**
+ * Returns the root logger.
+ * @return RootLogger
+ */
+ public function getRootLogger() {
+ return $this->root;
+ }
+
+ /**
+ * Returns the main threshold level.
+ * @return Level
+ */
+ public function getThreshold() {
+ return $this->threshold;
+ }
+
+ /**
+ * Returns true if the hierarchy is disabled for given log level and false
+ * otherwise.
+ * @return boolean
+ */
+ public function isDisabled(Level $level) {
+ return ($this->threshold->toInt() > $level->toInt());
+ }
+
+ /**
+ * Reset all values contained in this hierarchy instance to their
+ * default.
+ *
+ * This removes all appenders from all loggers, sets
+ * the level of all non-root loggers to <i>null</i>,
+ * sets their additivity flag to <i>true</i> and sets the level
+ * of the root logger to {@link LOGGER_LEVEL_DEBUG}.
+ *
+ * <p>Existing loggers are not removed. They are just reset.
+ *
+ * <p>This method should be used sparingly and with care as it will
+ * block all logging until it is completed.</p>
+ */
+ public function resetConfiguration() {
+ $root = $this->getRootLogger();
+
+ $root->setLevel(Level::getLevelDebug());
+ $this->setThreshold(Level::getLevelAll());
+ $this->shutDown();
+
+ foreach($this->loggers as $logger) {
+ $logger->setLevel(null);
+ $logger->setAdditivity(true);
+ $logger->removeAllAppenders();
+ }
+
+ $this->rendererMap->reset();
+ AppenderPool::clear();
+ }
+
+ /**
+ * Sets the main threshold level.
+ * @param Level $l
+ */
+ public function setThreshold(Level $threshold) {
+ $this->threshold = $threshold;
+ }
+
+ /**
+ * Shutting down a hierarchy will <i>safely</i> close and remove
+ * all appenders in all loggers including the root logger.
+ *
+ * The shutdown method is careful to close nested
+ * appenders before closing regular appenders. This is allows
+ * configurations where a regular appender is attached to a logger
+ * and again to a nested appender.
+ *
+ * @todo Check if the last paragraph is correct.
+ */
+ public function shutdown() {
+ $this->root->removeAllAppenders();
+
+ foreach($this->loggers as $logger) {
+ $logger->removeAllAppenders();
+ }
+ }
+
+ /**
+ * Prints the current Logger hierarchy tree. Useful for debugging.
+ */
+ public function printHierarchy() {
+ $this->printHierarchyInner($this->getRootLogger(), 0);
+ }
+
+ private function printHierarchyInner(Logger $current, $level) {
+ for ($i = 0; $i < $level; $i++) {
+ echo ($i == $level - 1) ? "|--" : "| ";
+ }
+ echo $current->getName() . "\n";
+
+ foreach($this->loggers as $logger) {
+ if ($logger->getParent() == $current) {
+ $this->printHierarchyInner($logger, $level + 1);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Layouts/AbstractLayout.php
----------------------------------------------------------------------
diff --git a/src/Layouts/AbstractLayout.php b/src/Layouts/AbstractLayout.php
new file mode 100644
index 0000000..b6a2d14
--- /dev/null
+++ b/src/Layouts/AbstractLayout.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * 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.
+ */
+
+namespace Apache\Log4php\Layouts;
+
+use Apache\Log4php\Configurable;
+use Apache\Log4php\LoggingEvent;
+
+/**
+ * Extend this abstract class to create your own log layout format.
+ */
+abstract class AbstractLayout extends Configurable {
+ /**
+ * Activates options for this layout.
+ * Override this method if you have options to be activated.
+ */
+ public function activateOptions() {
+ return true;
+ }
+
+ /**
+ * Override this method to create your own layout format.
+ *
+ * @param LoggingEvent
+ * @return string
+ */
+ public function format(LoggingEvent $event) {
+ return $event->getRenderedMessage();
+ }
+
+ /**
+ * Returns the content type output by this layout.
+ * @return string
+ */
+ public function getContentType() {
+ return "text/plain";
+ }
+
+ /**
+ * Returns the footer for the layout format.
+ * @return string
+ */
+ public function getFooter() {
+ return null;
+ }
+
+ /**
+ * Returns the header for the layout format.
+ * @return string
+ */
+ public function getHeader() {
+ return null;
+ }
+
+ /** Triggers a warning for this layout with the given message. */
+ protected function warn($message) {
+ trigger_error("log4php: [" . get_class($this) . "]: $message", E_USER_WARNING);
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Layouts/HtmlLayout.php
----------------------------------------------------------------------
diff --git a/src/Layouts/HtmlLayout.php b/src/Layouts/HtmlLayout.php
new file mode 100644
index 0000000..af74e61
--- /dev/null
+++ b/src/Layouts/HtmlLayout.php
@@ -0,0 +1,197 @@
+<?php
+/**
+ * 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.
+ */
+
+namespace Apache\Log4php\Layouts;
+
+use Apache\Log4php\LoggingEvent;
+use Apache\Log4php\Level;
+
+/**
+ * This layout outputs events in a HTML table.
+ *
+ * Configurable parameters for this layout are:
+ *
+ * - title
+ * - locationInfo
+ */
+class HtmlLayout extends AbstractLayout {
+ /**
+ * The <b>LocationInfo</b> option takes a boolean value. By
+ * default, it is set to false which means there will be no location
+ * information output by this layout. If the the option is set to
+ * true, then the file name and line number of the statement
+ * at the origin of the log statement will be output.
+ *
+ * <p>If you are embedding this layout within a {@link MailAppender}
+ * or a {@link MailEventAppender} then make sure to set the
+ * <b>LocationInfo</b> option of that appender as well.
+ * @var boolean
+ */
+ protected $locationInfo = false;
+
+ /**
+ * The <b>Title</b> option takes a String value. This option sets the
+ * document title of the generated HTML document.
+ * Defaults to 'Log4php Log Messages'.
+ * @var string
+ */
+ protected $title = "Log4php Log Messages";
+
+ /**
+ * The <b>LocationInfo</b> option takes a boolean value. By
+ * default, it is set to false which means there will be no location
+ * information output by this layout. If the the option is set to
+ * true, then the file name and line number of the statement
+ * at the origin of the log statement will be output.
+ *
+ * <p>If you are embedding this layout within a {@link MailAppender}
+ * or a {@link MailEventAppender} then make sure to set the
+ * <b>LocationInfo</b> option of that appender as well.
+ */
+ public function setLocationInfo($flag) {
+ $this->setBoolean('locationInfo', $flag);
+ }
+
+ /**
+ * Returns the current value of the <b>LocationInfo</b> option.
+ */
+ public function getLocationInfo() {
+ return $this->locationInfo;
+ }
+
+ /**
+ * The <b>Title</b> option takes a String value. This option sets the
+ * document title of the generated HTML document.
+ * Defaults to 'Log4php Log Messages'.
+ */
+ public function setTitle($title) {
+ $this->setString('title', $title);
+ }
+
+ /**
+ * @return string Returns the current value of the <b>Title</b> option.
+ */
+ public function getTitle() {
+ return $this->title;
+ }
+
+ /**
+ * @return string Returns the content type output by this layout, i.e "text/html".
+ */
+ public function getContentType() {
+ return "text/html";
+ }
+
+ /**
+ * @param LoggingEvent $event
+ * @return string
+ */
+ public function format(LoggingEvent $event) {
+ $sbuf = PHP_EOL . "<tr>" . PHP_EOL;
+
+ $sbuf .= "<td>";
+ $sbuf .= round(1000 * $event->getRelativeTime());
+ $sbuf .= "</td>" . PHP_EOL;
+
+ $sbuf .= "<td title=\"" . $event->getThreadName() . " thread\">";
+ $sbuf .= $event->getThreadName();
+ $sbuf .= "</td>" . PHP_EOL;
+
+ $sbuf .= "<td title=\"Level\">";
+
+ $level = $event->getLevel();
+
+ if ($level->equals(Level::getLevelDebug())) {
+ $sbuf .= "<font color=\"#339933\">$level</font>";
+ } else if ($level->equals(Level::getLevelWarn())) {
+ $sbuf .= "<font color=\"#993300\"><strong>$level</strong></font>";
+ } else {
+ $sbuf .= $level;
+ }
+ $sbuf .= "</td>" . PHP_EOL;
+
+ $sbuf .= "<td title=\"" . htmlentities($event->getLoggerName(), ENT_QUOTES) . " category\">";
+ $sbuf .= htmlentities($event->getLoggerName(), ENT_QUOTES);
+ $sbuf .= "</td>" . PHP_EOL;
+
+ if ($this->locationInfo) {
+ $locInfo = $event->getLocationInformation();
+ $sbuf .= "<td>";
+ $sbuf .= htmlentities($locInfo->getFileName(), ENT_QUOTES). ':' . $locInfo->getLineNumber();
+ $sbuf .= "</td>" . PHP_EOL;
+ }
+
+ $sbuf .= "<td title=\"Message\">";
+ $sbuf .= htmlentities($event->getRenderedMessage(), ENT_QUOTES);
+ $sbuf .= "</td>" . PHP_EOL;
+
+ $sbuf .= "</tr>" . PHP_EOL;
+
+ if ($event->getNDC() != null) {
+ $sbuf .= "<tr><td bgcolor=\"#EEEEEE\" style=\"font-size : xx-small;\" colspan=\"6\" title=\"Nested Diagnostic Context\">";
+ $sbuf .= "NDC: " . htmlentities($event->getNDC(), ENT_QUOTES);
+ $sbuf .= "</td></tr>" . PHP_EOL;
+ }
+ return $sbuf;
+ }
+
+ /**
+ * @return string Returns appropriate HTML headers.
+ */
+ public function getHeader() {
+ $sbuf = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">" . PHP_EOL;
+ $sbuf .= "<html>" . PHP_EOL;
+ $sbuf .= "<head>" . PHP_EOL;
+ $sbuf .= "<title>" . $this->title . "</title>" . PHP_EOL;
+ $sbuf .= "<style type=\"text/css\">" . PHP_EOL;
+ $sbuf .= "<!--" . PHP_EOL;
+ $sbuf .= "body, table {font-family: arial,sans-serif; font-size: x-small;}" . PHP_EOL;
+ $sbuf .= "th {background: #336699; color: #FFFFFF; text-align: left;}" . PHP_EOL;
+ $sbuf .= "-->" . PHP_EOL;
+ $sbuf .= "</style>" . PHP_EOL;
+ $sbuf .= "</head>" . PHP_EOL;
+ $sbuf .= "<body bgcolor=\"#FFFFFF\" topmargin=\"6\" leftmargin=\"6\">" . PHP_EOL;
+ $sbuf .= "<hr size=\"1\" noshade>" . PHP_EOL;
+ $sbuf .= "Log session start time " . strftime('%c', time()) . "<br>" . PHP_EOL;
+ $sbuf .= "<br>" . PHP_EOL;
+ $sbuf .= "<table cellspacing=\"0\" cellpadding=\"4\" border=\"1\" bordercolor=\"#224466\" width=\"100%\">" . PHP_EOL;
+ $sbuf .= "<tr>" . PHP_EOL;
+ $sbuf .= "<th>Time</th>" . PHP_EOL;
+ $sbuf .= "<th>Thread</th>" . PHP_EOL;
+ $sbuf .= "<th>Level</th>" . PHP_EOL;
+ $sbuf .= "<th>Category</th>" . PHP_EOL;
+ if ($this->locationInfo) {
+ $sbuf .= "<th>File:Line</th>" . PHP_EOL;
+ }
+ $sbuf .= "<th>Message</th>" . PHP_EOL;
+ $sbuf .= "</tr>" . PHP_EOL;
+
+ return $sbuf;
+ }
+
+ /**
+ * @return string Returns the appropriate HTML footers.
+ */
+ public function getFooter() {
+ $sbuf = "</table>" . PHP_EOL;
+ $sbuf .= "<br>" . PHP_EOL;
+ $sbuf .= "</body></html>";
+
+ return $sbuf;
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Layouts/PatternLayout.php
----------------------------------------------------------------------
diff --git a/src/Layouts/PatternLayout.php b/src/Layouts/PatternLayout.php
new file mode 100644
index 0000000..c34cbe2
--- /dev/null
+++ b/src/Layouts/PatternLayout.php
@@ -0,0 +1,171 @@
+<?php
+/**
+ * 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.
+ */
+
+namespace Apache\Log4php\Layouts;
+
+use Apache\Log4php\Helpers\PatternParser;
+use Apache\Log4php\LoggerException;
+use Apache\Log4php\LoggingEvent;
+
+/**
+ * A flexible layout configurable with a pattern string.
+ *
+ * Configurable parameters:
+ *
+ * * converionPattern - A string which controls the formatting of logging
+ * events. See docs for full specification.
+ */
+class PatternLayout extends AbstractLayout {
+
+ /** Default conversion pattern */
+ const DEFAULT_CONVERSION_PATTERN = '%date %-5level %logger %message%newline';
+
+ /** Default conversion TTCC Pattern */
+ const TTCC_CONVERSION_PATTERN = '%d [%t] %p %c %x - %m%n';
+
+ /** The conversion pattern. */
+ protected $pattern = self::DEFAULT_CONVERSION_PATTERN;
+
+ /** Maps conversion keywords to the relevant converter (default implementation). */
+ protected static $defaultConverterMap = array(
+ 'c' => 'LoggerConverter',
+ 'lo' => 'LoggerConverter',
+ 'logger' => 'LoggerConverter',
+
+ 'C' => 'ClassConverter',
+ 'class' => 'ClassConverter',
+
+ 'cookie' => 'CookieConverter',
+
+ 'd' => 'DateConverter',
+ 'date' => 'DateConverter',
+
+ 'e' => 'EnvironmentConverter',
+ 'env' => 'EnvironmentConverter',
+
+ 'ex' => 'ThrowableConverter',
+ 'exception' => 'ThrowableConverter',
+ 'throwable' => 'ThrowableConverter',
+
+ 'F' => 'FileConverter',
+ 'file' => 'FileConverter',
+
+ 'l' => 'LocationConverter',
+ 'location' => 'LocationConverter',
+
+ 'L' => 'LineConverter',
+ 'line' => 'LineConverter',
+
+ 'm' => 'MessageConverter',
+ 'msg' => 'MessageConverter',
+ 'message' => 'MessageConverter',
+
+ 'M' => 'MethodConverter',
+ 'method' => 'MethodConverter',
+
+ 'n' => 'NewLineConverter',
+ 'newline' => 'NewLineConverter',
+
+ 'p' => 'LevelConverter',
+ 'le' => 'LevelConverter',
+ 'level' => 'LevelConverter',
+
+ 'r' => 'RelativeConverter',
+ 'relative' => 'RelativeConverter',
+
+ 'req' => 'RequestConverter',
+ 'request' => 'RequestConverter',
+
+ 's' => 'ServerConverter',
+ 'server' => 'ServerConverter',
+
+ 'ses' => 'SessionConverter',
+ 'session' => 'SessionConverter',
+
+ 'sid' => 'SessionIdConverter',
+ 'sessionid' => 'SessionIdConverter',
+
+ 't' => 'ProcessConverter',
+ 'pid' => 'ProcessConverter',
+ 'process' => 'ProcessConverter',
+
+ 'x' => 'NdcConverter',
+ 'ndc' => 'NdcConverter',
+
+ 'X' => 'MdcConverter',
+ 'mdc' => 'MdcConverter',
+ );
+
+ /** Maps conversion keywords to the relevant converter. */
+ protected $converterMap = array();
+
+ /**
+ * Head of a chain of Converters.
+ * @var AbstractConverter
+ */
+ private $head;
+
+ /** Returns the default converter map. */
+ public static function getDefaultConverterMap() {
+ return self::$defaultConverterMap;
+ }
+
+ /** Constructor. Initializes the converter map. */
+ public function __construct() {
+ $this->converterMap = self::$defaultConverterMap;
+ }
+
+ /**
+ * Sets the conversionPattern option. This is the string which
+ * controls formatting and consists of a mix of literal content and
+ * conversion specifiers.
+ * @param array $conversionPattern
+ */
+ public function setConversionPattern($conversionPattern) {
+ $this->pattern = $conversionPattern;
+ }
+
+ /**
+ * Processes the conversion pattern and creates a corresponding chain of
+ * pattern converters which will be used to format logging events.
+ */
+ public function activateOptions() {
+ if (!isset($this->pattern)) {
+ throw new LoggerException("Mandatory parameter 'conversionPattern' is not set.");
+ }
+
+ $parser = new PatternParser($this->pattern, $this->converterMap);
+ $this->head = $parser->parse();
+ }
+
+ /**
+ * Produces a formatted string as specified by the conversion pattern.
+ *
+ * @param LoggingEvent $event
+ * @return string
+ */
+ public function format(LoggingEvent $event) {
+ $sbuf = '';
+ $converter = $this->head;
+ while ($converter !== null) {
+ $converter->format($sbuf, $event);
+ $converter = $converter->next;
+ }
+ return $sbuf;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Layouts/SerializedLayout.php
----------------------------------------------------------------------
diff --git a/src/Layouts/SerializedLayout.php b/src/Layouts/SerializedLayout.php
new file mode 100644
index 0000000..5273c3b
--- /dev/null
+++ b/src/Layouts/SerializedLayout.php
@@ -0,0 +1,53 @@
+<?php
+/**
+ * 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.
+ */
+
+namespace Apache\Log4php\Layouts;
+
+use Apache\Log4php\LoggingEvent;
+
+/**
+ * Layout which formats the events using PHP's serialize() function.
+ *
+ * Available options:
+ * - locationInfo - If set to true, the event's location information will also
+ * be serialized (slow, defaults to false).
+ * @since 2.2
+ */
+class SerializedLayout extends AbstractLayout {
+
+ /** Whether to include the event's location information (slow). */
+ protected $locationInfo = false;
+
+ /** Sets the location information flag. */
+ public function setLocationInfo($value) {
+ $this->setBoolean('locationInfo', $value);
+ }
+
+ /** Returns the location information flag. */
+ public function getLocationInfo() {
+ return $this->locationInfo;
+ }
+
+ public function format(LoggingEvent $event) {
+ // If required, initialize the location data
+ if($this->locationInfo) {
+ $event->getLocationInformation();
+ }
+ return serialize($event) . PHP_EOL;
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Layouts/SimpleLayout.php
----------------------------------------------------------------------
diff --git a/src/Layouts/SimpleLayout.php b/src/Layouts/SimpleLayout.php
new file mode 100644
index 0000000..16645f3
--- /dev/null
+++ b/src/Layouts/SimpleLayout.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ * 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.
+ */
+
+namespace Apache\Log4php\Layouts;
+
+use Apache\Log4php\LoggingEvent;
+
+/**
+ * A simple layout.
+ *
+ * Returns the log statement in a format consisting of the
+ * <b>level</b>, followed by " - " and then the <b>message</b>.
+ */
+class SimpleLayout extends AbstractLayout {
+ /**
+ * Returns the log statement in a format consisting of the
+ * <b>level</b>, followed by " - " and then the
+ * <b>message</b>. For example,
+ * <samp> INFO - "A message" </samp>
+ *
+ * @param LoggingEvent $event
+ * @return string
+ */
+ public function format(LoggingEvent $event) {
+ $level = $event->getLevel();
+ $message = $event->getRenderedMessage();
+ return "$level - $message" . PHP_EOL;
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Layouts/XmlLayout.php
----------------------------------------------------------------------
diff --git a/src/Layouts/XmlLayout.php b/src/Layouts/XmlLayout.php
new file mode 100644
index 0000000..0ada386
--- /dev/null
+++ b/src/Layouts/XmlLayout.php
@@ -0,0 +1,192 @@
+<?php
+/**
+ * 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.
+ */
+
+namespace Apache\Log4php\Layouts;
+
+use Apache\Log4php\LoggingEvent;
+
+/**
+ * The output of the LoggerXmlLayout consists of a series of log4php:event elements.
+ *
+ * Configurable parameters:
+ * - {@link $locationInfo} - If set to true then the file name and line number
+ * of the origin of the log statement will be included in output.
+ * - {@link $log4jNamespace} - If set to true then log4j namespace will be used
+ * instead of log4php namespace. This can be usefull when using log viewers
+ * which can only parse the log4j namespace such as Apache Chainsaw.
+ *
+ * <p>It does not output a complete well-formed XML file.
+ * The output is designed to be included as an external entity in a separate file to form
+ * a correct XML file.</p>
+ *
+ */
+class XmlLayout extends AbstractLayout {
+ const LOG4J_NS_PREFIX ='log4j';
+ const LOG4J_NS = 'http://jakarta.apache.org/log4j/';
+
+ const LOG4PHP_NS_PREFIX = 'log4php';
+ const LOG4PHP_NS = 'http://logging.apache.org/log4php/';
+
+ const CDATA_START = '<![CDATA[';
+ const CDATA_END = ']]>';
+ const CDATA_PSEUDO_END = ']]>';
+ const CDATA_EMBEDDED_END = ']]>]]><![CDATA[';
+
+ /**
+ * If set to true then the file name and line number of the origin of the
+ * log statement will be output.
+ * @var boolean
+ */
+ protected $locationInfo = true;
+
+ /**
+ * If set to true, log4j namespace will be used instead of the log4php
+ * namespace.
+ * @var boolean
+ */
+ protected $log4jNamespace = false;
+
+ /** The namespace in use. */
+ protected $namespace = self::LOG4PHP_NS;
+
+ /** The namespace prefix in use */
+ protected $namespacePrefix = self::LOG4PHP_NS_PREFIX;
+
+ public function activateOptions() {
+ if ($this->getLog4jNamespace()) {
+ $this->namespace = self::LOG4J_NS;
+ $this->namespacePrefix = self::LOG4J_NS_PREFIX;
+ } else {
+ $this->namespace = self::LOG4PHP_NS;
+ $this->namespacePrefix = self::LOG4PHP_NS_PREFIX;
+ }
+ }
+
+ /**
+ * @return string
+ */
+ public function getHeader() {
+ return "<{$this->namespacePrefix}:eventSet ".
+ "xmlns:{$this->namespacePrefix}=\"{$this->namespace}\" ".
+ "version=\"0.3\" ".
+ "includesLocationInfo=\"".($this->getLocationInfo() ? "true" : "false")."\"".
+ ">" . PHP_EOL;
+ }
+
+ /**
+ * Formats a {@link LoggingEvent} in conformance with the log4php.dtd.
+ *
+ * @param LoggingEvent $event
+ * @return string
+ */
+ public function format(LoggingEvent $event) {
+ $ns = $this->namespacePrefix;
+
+ $loggerName = $event->getLoggerName();
+ $timeStamp = number_format((float)($event->getTimeStamp() * 1000), 0, '', '');
+ $thread = $event->getThreadName();
+ $level = $event->getLevel()->toString();
+
+ $buf = "<$ns:event logger=\"{$loggerName}\" level=\"{$level}\" thread=\"{$thread}\" timestamp=\"{$timeStamp}\">".PHP_EOL;
+ $buf .= "<$ns:message>";
+ $buf .= $this->encodeCDATA($event->getRenderedMessage());
+ $buf .= "</$ns:message>".PHP_EOL;
+
+ $ndc = $event->getNDC();
+ if(!empty($ndc)) {
+ $buf .= "<$ns:NDC><![CDATA[";
+ $buf .= $this->encodeCDATA($ndc);
+ $buf .= "]]></$ns:NDC>".PHP_EOL;
+ }
+
+ $mdcMap = $event->getMDCMap();
+ if (!empty($mdcMap)) {
+ $buf .= "<$ns:properties>".PHP_EOL;
+ foreach ($mdcMap as $name=>$value) {
+ $buf .= "<$ns:data name=\"$name\" value=\"$value\" />".PHP_EOL;
+ }
+ $buf .= "</$ns:properties>".PHP_EOL;
+ }
+
+ if ($this->getLocationInfo()) {
+ $locationInfo = $event->getLocationInformation();
+ $buf .= "<$ns:locationInfo ".
+ "class=\"" . $locationInfo->getClassName() . "\" ".
+ "file=\"" . htmlentities($locationInfo->getFileName(), ENT_QUOTES) . "\" ".
+ "line=\"" . $locationInfo->getLineNumber() . "\" ".
+ "method=\"" . $locationInfo->getMethodName() . "\" ";
+ $buf .= "/>".PHP_EOL;
+ }
+
+ $buf .= "</$ns:event>".PHP_EOL;
+
+ return $buf;
+ }
+
+ /**
+ * @return string
+ */
+ public function getFooter() {
+ return "</{$this->namespacePrefix}:eventSet>" . PHP_EOL;
+ }
+
+
+ /**
+ * Whether or not file name and line number will be included in the output.
+ * @return boolean
+ */
+ public function getLocationInfo() {
+ return $this->locationInfo;
+ }
+
+ /**
+ * The {@link $locationInfo} option takes a boolean value. By default,
+ * it is set to false which means there will be no location
+ * information output by this layout. If the the option is set to
+ * true, then the file name and line number of the statement at the
+ * origin of the log statement will be output.
+ */
+ public function setLocationInfo($flag) {
+ $this->setBoolean('locationInfo', $flag);
+ }
+
+ /**
+ * @return boolean
+ */
+ public function getLog4jNamespace() {
+ return $this->log4jNamespace;
+ }
+
+ /**
+ * @param boolean
+ */
+ public function setLog4jNamespace($flag) {
+ $this->setBoolean('log4jNamespace', $flag);
+ }
+
+ /**
+ * Encases a string in CDATA tags, and escapes any existing CDATA end
+ * tags already present in the string.
+ * @param string $string
+ */
+ private function encodeCDATA($string) {
+ $string = str_replace(self::CDATA_END, self::CDATA_EMBEDDED_END, $string);
+ return self::CDATA_START . $string . self::CDATA_END;
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Level.php
----------------------------------------------------------------------
diff --git a/src/Level.php b/src/Level.php
new file mode 100644
index 0000000..f17f0fc
--- /dev/null
+++ b/src/Level.php
@@ -0,0 +1,253 @@
+<?php
+/**
+ * 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.
+ */
+
+namespace Apache\Log4php;
+
+/**
+ * Defines the minimum set of levels recognized by the system, that is
+ * <i>OFF</i>, <i>FATAL</i>, <i>ERROR</i>,
+ * <i>WARN</i>, <i>INFO</i>, <i>DEBUG</i> and
+ * <i>ALL</i>.
+ *
+ * <p>The <i>Level</i> class may be subclassed to define a larger
+ * level set.</p>
+ * @since 0.5
+ */
+class Level {
+
+ const OFF = 2147483647;
+ const FATAL = 50000;
+ const ERROR = 40000;
+ const WARN = 30000;
+ const INFO = 20000;
+ const DEBUG = 10000;
+ const TRACE = 5000;
+ const ALL = -2147483647;
+
+ /** Integer level value. */
+ private $level;
+
+ /** Contains a list of instantiated levels. */
+ private static $levelMap;
+
+ /** String representation of the level. */
+ private $levelStr;
+
+ /**
+ * Equivalent syslog level.
+ * @var integer
+ */
+ private $syslogEquivalent;
+
+ /**
+ * Constructor
+ *
+ * @param integer $level
+ * @param string $levelStr
+ * @param integer $syslogEquivalent
+ */
+ private function __construct($level, $levelStr, $syslogEquivalent) {
+ $this->level = $level;
+ $this->levelStr = $levelStr;
+ $this->syslogEquivalent = $syslogEquivalent;
+ }
+
+ /**
+ * Compares two logger levels.
+ *
+ * @param Level $other
+ * @return boolean
+ */
+ public function equals($other) {
+ if($other instanceof Level) {
+ if($this->level == $other->level) {
+ return true;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Returns an Off Level
+ * @return Level
+ */
+ public static function getLevelOff() {
+ if(!isset(self::$levelMap[Level::OFF])) {
+ self::$levelMap[Level::OFF] = new Level(Level::OFF, 'OFF', LOG_ALERT);
+ }
+ return self::$levelMap[Level::OFF];
+ }
+
+ /**
+ * Returns a Fatal Level
+ * @return Level
+ */
+ public static function getLevelFatal() {
+ if(!isset(self::$levelMap[Level::FATAL])) {
+ self::$levelMap[Level::FATAL] = new Level(Level::FATAL, 'FATAL', LOG_ALERT);
+ }
+ return self::$levelMap[Level::FATAL];
+ }
+
+ /**
+ * Returns an Error Level
+ * @return Level
+ */
+ public static function getLevelError() {
+ if(!isset(self::$levelMap[Level::ERROR])) {
+ self::$levelMap[Level::ERROR] = new Level(Level::ERROR, 'ERROR', LOG_ERR);
+ }
+ return self::$levelMap[Level::ERROR];
+ }
+
+ /**
+ * Returns a Warn Level
+ * @return Level
+ */
+ public static function getLevelWarn() {
+ if(!isset(self::$levelMap[Level::WARN])) {
+ self::$levelMap[Level::WARN] = new Level(Level::WARN, 'WARN', LOG_WARNING);
+ }
+ return self::$levelMap[Level::WARN];
+ }
+
+ /**
+ * Returns an Info Level
+ * @return Level
+ */
+ public static function getLevelInfo() {
+ if(!isset(self::$levelMap[Level::INFO])) {
+ self::$levelMap[Level::INFO] = new Level(Level::INFO, 'INFO', LOG_INFO);
+ }
+ return self::$levelMap[Level::INFO];
+ }
+
+ /**
+ * Returns a Debug Level
+ * @return Level
+ */
+ public static function getLevelDebug() {
+ if(!isset(self::$levelMap[Level::DEBUG])) {
+ self::$levelMap[Level::DEBUG] = new Level(Level::DEBUG, 'DEBUG', LOG_DEBUG);
+ }
+ return self::$levelMap[Level::DEBUG];
+ }
+
+ /**
+ * Returns a Trace Level
+ * @return Level
+ */
+ public static function getLevelTrace() {
+ if(!isset(self::$levelMap[Level::TRACE])) {
+ self::$levelMap[Level::TRACE] = new Level(Level::TRACE, 'TRACE', LOG_DEBUG);
+ }
+ return self::$levelMap[Level::TRACE];
+ }
+
+ /**
+ * Returns an All Level
+ * @return Level
+ */
+ public static function getLevelAll() {
+ if(!isset(self::$levelMap[Level::ALL])) {
+ self::$levelMap[Level::ALL] = new Level(Level::ALL, 'ALL', LOG_DEBUG);
+ }
+ return self::$levelMap[Level::ALL];
+ }
+
+ /**
+ * Return the syslog equivalent of this level as an integer.
+ * @return integer
+ */
+ public function getSyslogEquivalent() {
+ return $this->syslogEquivalent;
+ }
+
+ /**
+ * Returns <i>true</i> if this level has a higher or equal
+ * level than the level passed as argument, <i>false</i>
+ * otherwise.
+ *
+ * @param Level $other
+ * @return boolean
+ */
+ public function isGreaterOrEqual($other) {
+ return $this->level >= $other->level;
+ }
+
+ /**
+ * Returns the string representation of this level.
+ * @return string
+ */
+ public function toString() {
+ return $this->levelStr;
+ }
+
+ /**
+ * Returns the string representation of this level.
+ * @return string
+ */
+ public function __toString() {
+ return $this->toString();
+ }
+
+ /**
+ * Returns the integer representation of this level.
+ * @return integer
+ */
+ public function toInt() {
+ return $this->level;
+ }
+
+ /**
+ * Convert the input argument to a level. If the conversion fails, then
+ * this method returns the provided default level.
+ *
+ * @param mixed $arg The value to convert to level.
+ * @param Level $default Value to return if conversion is not possible.
+ * @return Level
+ */
+ public static function toLevel($arg, $defaultLevel = null) {
+ if(is_int($arg)) {
+ switch($arg) {
+ case self::ALL: return self::getLevelAll();
+ case self::TRACE: return self::getLevelTrace();
+ case self::DEBUG: return self::getLevelDebug();
+ case self::INFO: return self::getLevelInfo();
+ case self::WARN: return self::getLevelWarn();
+ case self::ERROR: return self::getLevelError();
+ case self::FATAL: return self::getLevelFatal();
+ case self::OFF: return self::getLevelOff();
+ default: return $defaultLevel;
+ }
+ } else {
+ switch(strtoupper($arg)) {
+ case 'ALL': return self::getLevelAll();
+ case 'TRACE': return self::getLevelTrace();
+ case 'DEBUG': return self::getLevelDebug();
+ case 'INFO': return self::getLevelInfo();
+ case 'WARN': return self::getLevelWarn();
+ case 'ERROR': return self::getLevelError();
+ case 'FATAL': return self::getLevelFatal();
+ case 'OFF': return self::getLevelOff();
+ default: return $defaultLevel;
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/LocationInfo.php
----------------------------------------------------------------------
diff --git a/src/LocationInfo.php b/src/LocationInfo.php
new file mode 100644
index 0000000..4615962
--- /dev/null
+++ b/src/LocationInfo.php
@@ -0,0 +1,100 @@
+<?php
+/**
+ * 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.
+ */
+
+namespace Apache\Log4php;
+
+/**
+ * The internal representation of caller location information.
+ * @since 0.3
+ */
+class LocationInfo {
+
+ /** The value to return when the location information is not available. */
+ const LOCATION_INFO_NA = 'NA';
+
+ /**
+ * Caller line number.
+ * @var integer
+ */
+ protected $lineNumber;
+
+ /**
+ * Caller file name.
+ * @var string
+ */
+ protected $fileName;
+
+ /**
+ * Caller class name.
+ * @var string
+ */
+ protected $className;
+
+ /**
+ * Caller method name.
+ * @var string
+ */
+ protected $methodName;
+
+ /**
+ * All the information combined.
+ * @var string
+ */
+ protected $fullInfo;
+
+ /**
+ * Instantiate location information based on a {@link PHP_MANUAL#debug_backtrace}.
+ *
+ * @param array $trace
+ * @param mixed $caller
+ */
+ public function __construct($trace, $fqcn = null) {
+ $this->lineNumber = isset($trace['line']) ? $trace['line'] : null;
+ $this->fileName = isset($trace['file']) ? $trace['file'] : null;
+ $this->className = isset($trace['class']) ? $trace['class'] : null;
+ $this->methodName = isset($trace['function']) ? $trace['function'] : null;
+ $this->fullInfo = $this->getClassName() . '.' . $this->getMethodName() .
+ '(' . $this->getFileName() . ':' . $this->getLineNumber() . ')';
+ }
+
+ /** Returns the caller class name. */
+ public function getClassName() {
+ return ($this->className === null) ? self::LOCATION_INFO_NA : $this->className;
+ }
+
+ /** Returns the caller file name. */
+ public function getFileName() {
+ return ($this->fileName === null) ? self::LOCATION_INFO_NA : $this->fileName;
+ }
+
+ /** Returns the caller line number. */
+ public function getLineNumber() {
+ return ($this->lineNumber === null) ? self::LOCATION_INFO_NA : $this->lineNumber;
+ }
+
+ /** Returns the caller method name. */
+ public function getMethodName() {
+ return ($this->methodName === null) ? self::LOCATION_INFO_NA : $this->methodName;
+ }
+
+ /** Returns the full information of the caller. */
+ public function getFullInfo() {
+ return ($this->fullInfo === null) ? self::LOCATION_INFO_NA : $this->fullInfo;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Logger.php
----------------------------------------------------------------------
diff --git a/src/Logger.php b/src/Logger.php
new file mode 100644
index 0000000..27eca1c
--- /dev/null
+++ b/src/Logger.php
@@ -0,0 +1,592 @@
+<?php
+/**
+ * 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.
+ */
+
+namespace Apache\Log4php;
+
+/**
+ * This is the central class in the log4php package. All logging operations
+ * are done through this class.
+ *
+ * The main logging methods are:
+ * <ul>
+ * <li>{@link trace()}</li>
+ * <li>{@link debug()}</li>
+ * <li>{@link info()}</li>
+ * <li>{@link warn()}</li>
+ * <li>{@link error()}</li>
+ * <li>{@link fatal()}</li>
+ * </ul>
+ *
+ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
+ * @link http://logging.apache.org/log4php
+ */
+class Logger {
+
+ /**
+ * Logger additivity. If set to true then child loggers will inherit
+ * the appenders of their ancestors by default.
+ * @var boolean
+ */
+ private $additive = true;
+
+ /**
+ * The Logger's fully qualified class name.
+ * TODO: Determine if this is useful.
+ */
+ private $fqcn = 'Logger';
+
+ /** The assigned Logger level. */
+ private $level;
+
+ /** The name of this Logger instance. */
+ private $name;
+
+ /** The parent logger. Set to null if this is the root logger. */
+ private $parent;
+
+ /** A collection of appenders linked to this logger. */
+ private $appenders = array();
+
+ /**
+ * Constructor.
+ * @param string $name Name of the logger.
+ */
+ public function __construct($name) {
+ $this->name = $name;
+ }
+
+ /**
+ * Returns the logger name.
+ * @return string
+ */
+ public function getName() {
+ return $this->name;
+ }
+
+ /**
+ * Returns the parent Logger. Can be null if this is the root logger.
+ * @return Logger
+ */
+ public function getParent() {
+ return $this->parent;
+ }
+
+ // ******************************************
+ // *** Logging methods ***
+ // ******************************************
+
+ /**
+ * Log a message object with the TRACE level.
+ *
+ * @param mixed $message message
+ * @param Exception $throwable Optional throwable information to include
+ * in the logging event.
+ */
+ public function trace($message, $throwable = null) {
+ $this->log(Level::getLevelTrace(), $message, $throwable);
+ }
+
+ /**
+ * Log a message object with the DEBUG level.
+ *
+ * @param mixed $message message
+ * @param Exception $throwable Optional throwable information to include
+ * in the logging event.
+ */
+ public function debug($message, $throwable = null) {
+ $this->log(Level::getLevelDebug(), $message, $throwable);
+ }
+
+ /**
+ * Log a message object with the INFO Level.
+ *
+ * @param mixed $message message
+ * @param Exception $throwable Optional throwable information to include
+ * in the logging event.
+ */
+ public function info($message, $throwable = null) {
+ $this->log(Level::getLevelInfo(), $message, $throwable);
+ }
+
+ /**
+ * Log a message with the WARN level.
+ *
+ * @param mixed $message message
+ * @param Exception $throwable Optional throwable information to include
+ * in the logging event.
+ */
+ public function warn($message, $throwable = null) {
+ $this->log(Level::getLevelWarn(), $message, $throwable);
+ }
+
+ /**
+ * Log a message object with the ERROR level.
+ *
+ * @param mixed $message message
+ * @param Exception $throwable Optional throwable information to include
+ * in the logging event.
+ */
+ public function error($message, $throwable = null) {
+ $this->log(Level::getLevelError(), $message, $throwable);
+ }
+
+ /**
+ * Log a message object with the FATAL level.
+ *
+ * @param mixed $message message
+ * @param Exception $throwable Optional throwable information to include
+ * in the logging event.
+ */
+ public function fatal($message, $throwable = null) {
+ $this->log(Level::getLevelFatal(), $message, $throwable);
+ }
+
+ /**
+ * Log a message using the provided logging level.
+ *
+ * @param Level $level The logging level.
+ * @param mixed $message Message to log.
+ * @param Exception $throwable Optional throwable information to include
+ * in the logging event.
+ */
+ public function log(Level $level, $message, $throwable = null) {
+ if($this->isEnabledFor($level)) {
+ $event = new LoggingEvent($this->fqcn, $this, $level, $message, null, $throwable);
+ $this->callAppenders($event);
+ }
+
+ // Forward the event upstream if additivity is turned on
+ if(isset($this->parent) && $this->getAdditivity()) {
+
+ // Use the event if already created
+ if (isset($event)) {
+ $this->parent->logEvent($event);
+ } else {
+ $this->parent->log($level, $message, $throwable);
+ }
+ }
+ }
+
+ /**
+ * Logs an already prepared logging event object.
+ * @param LoggingEvent $event
+ */
+ public function logEvent(LoggingEvent $event) {
+ if($this->isEnabledFor($event->getLevel())) {
+ $this->callAppenders($event);
+ }
+
+ // Forward the event upstream if additivity is turned on
+ if(isset($this->parent) && $this->getAdditivity()) {
+ $this->parent->logEvent($event);
+ }
+ }
+
+ /**
+ * If assertion parameter evaluates as false, then logs the message
+ * using the ERROR level.
+ *
+ * @param bool $assertion
+ * @param string $msg message to log
+ */
+ public function assertLog($assertion = true, $msg = '') {
+ if($assertion == false) {
+ $this->error($msg);
+ }
+ }
+
+ /**
+ * This method creates a new logging event and logs the event without
+ * further checks.
+ *
+ * It should not be called directly. Use {@link trace()}, {@link debug()},
+ * {@link info()}, {@link warn()}, {@link error()} and {@link fatal()}
+ * wrappers.
+ *
+ * @param string $fqcn Fully qualified class name of the Logger
+ * @param Exception $throwable Optional throwable information to include
+ * in the logging event.
+ * @param Level $level log level
+ * @param mixed $message message to log
+ */
+ public function forcedLog($fqcn, $throwable, Level $level, $message) {
+ $event = new LoggingEvent($fqcn, $this, $level, $message, null, $throwable);
+ $this->callAppenders($event);
+
+ // Forward the event upstream if additivity is turned on
+ if(isset($this->parent) && $this->getAdditivity()) {
+ $this->parent->logEvent($event);
+ }
+ }
+
+ /**
+ * Forwards the given logging event to all linked appenders.
+ * @param LoggingEvent $event
+ */
+ public function callAppenders($event) {
+ foreach($this->appenders as $appender) {
+ $appender->doAppend($event);
+ }
+ }
+
+ // ******************************************
+ // *** Checker methods ***
+ // ******************************************
+
+ /**
+ * Check whether this Logger is enabled for a given Level passed as parameter.
+ *
+ * @param Level level
+ * @return boolean
+ */
+ public function isEnabledFor(Level $level) {
+ return $level->isGreaterOrEqual($this->getEffectiveLevel());
+ }
+
+ /**
+ * Check whether this Logger is enabled for the TRACE Level.
+ * @return boolean
+ */
+ public function isTraceEnabled() {
+ return $this->isEnabledFor(Level::getLevelTrace());
+ }
+
+ /**
+ * Check whether this Logger is enabled for the DEBUG Level.
+ * @return boolean
+ */
+ public function isDebugEnabled() {
+ return $this->isEnabledFor(Level::getLevelDebug());
+ }
+
+ /**
+ * Check whether this Logger is enabled for the INFO Level.
+ * @return boolean
+ */
+ public function isInfoEnabled() {
+ return $this->isEnabledFor(Level::getLevelInfo());
+ }
+
+ /**
+ * Check whether this Logger is enabled for the WARN Level.
+ * @return boolean
+ */
+ public function isWarnEnabled() {
+ return $this->isEnabledFor(Level::getLevelWarn());
+ }
+
+ /**
+ * Check whether this Logger is enabled for the ERROR Level.
+ * @return boolean
+ */
+ public function isErrorEnabled() {
+ return $this->isEnabledFor(Level::getLevelError());
+ }
+
+ /**
+ * Check whether this Logger is enabled for the FATAL Level.
+ * @return boolean
+ */
+ public function isFatalEnabled() {
+ return $this->isEnabledFor(Level::getLevelFatal());
+ }
+
+ // ******************************************
+ // *** Configuration methods ***
+ // ******************************************
+
+ /**
+ * Adds a new appender to the Logger.
+ * @param Appender $appender The appender to add.
+ */
+ public function addAppender($appender) {
+ $appenderName = $appender->getName();
+ $this->appenders[$appenderName] = $appender;
+ }
+
+ /** Removes all appenders from the Logger. */
+ public function removeAllAppenders() {
+ foreach($this->appenders as $name => $appender) {
+ $this->removeAppender($name);
+ }
+ }
+
+ /**
+ * Remove the appender passed as parameter form the Logger.
+ * @param mixed $appender an appender name or a {@link Appender} instance.
+ */
+ public function removeAppender($appender) {
+ if($appender instanceof Appender) {
+ $appender->close();
+ unset($this->appenders[$appender->getName()]);
+ } else if (is_string($appender) and isset($this->appenders[$appender])) {
+ $this->appenders[$appender]->close();
+ unset($this->appenders[$appender]);
+ }
+ }
+
+ /**
+ * Returns the appenders linked to this logger as an array.
+ * @return array collection of appender names
+ */
+ public function getAllAppenders() {
+ return $this->appenders;
+ }
+
+ /**
+ * Returns a linked appender by name.
+ * @return Appender
+ */
+ public function getAppender($name) {
+ return $this->appenders[$name];
+ }
+
+ /**
+ * Sets the additivity flag.
+ * @param boolean $additive
+ */
+ public function setAdditivity($additive) {
+ $this->additive = (bool)$additive;
+ }
+
+ /**
+ * Returns the additivity flag.
+ * @return boolean
+ */
+ public function getAdditivity() {
+ return $this->additive;
+ }
+
+ /**
+ * Starting from this Logger, search the Logger hierarchy for a non-null level and return it.
+ * @see Level
+ * @return Level or null
+ */
+ public function getEffectiveLevel() {
+ for($logger = $this; $logger !== null; $logger = $logger->getParent()) {
+ if($logger->getLevel() !== null) {
+ return $logger->getLevel();
+ }
+ }
+ }
+
+ /**
+ * Get the assigned Logger level.
+ * @return Level The assigned level or null if none is assigned.
+ */
+ public function getLevel() {
+ return $this->level;
+ }
+
+ /**
+ * Set the Logger level.
+ *
+ * Use Level::getLevelXXX() methods to get a Level object, e.g.
+ * <code>$logger->setLevel(Level::getLevelInfo());</code>
+ *
+ * @param Level $level The level to set, or NULL to clear the logger level.
+ */
+ public function setLevel(Level $level = null) {
+ $this->level = $level;
+ }
+
+ /**
+ * Checks whether an appender is attached to this logger instance.
+ *
+ * @param Appender $appender
+ * @return boolean
+ */
+ public function isAttached(Appender $appender) {
+ return isset($this->appenders[$appender->getName()]);
+ }
+
+ /**
+ * Sets the parent logger.
+ * @param Logger $logger
+ */
+ public function setParent(Logger $logger) {
+ $this->parent = $logger;
+ }
+
+ // ******************************************
+ // *** Static methods and properties ***
+ // ******************************************
+
+ /** The logger hierarchy used by log4php. */
+ private static $hierarchy;
+
+ /** Inidicates if log4php has been initialized */
+ private static $initialized = false;
+
+ /**
+ * Returns the hierarchy used by this Logger.
+ *
+ * Caution: do not use this hierarchy unless you have called initialize().
+ * To get Loggers, use the Logger::getLogger and Logger::getRootLogger
+ * methods instead of operating on on the hierarchy directly.
+ *
+ * @return Hierarchy
+ */
+ public static function getHierarchy() {
+ if(!isset(self::$hierarchy)) {
+ self::$hierarchy = new Hierarchy(new RootLogger());
+ }
+ return self::$hierarchy;
+ }
+
+ /**
+ * Returns a Logger by name. If it does not exist, it will be created.
+ *
+ * @param string $name The logger name
+ * @return Logger
+ */
+ public static function getLogger($name) {
+ if(!self::isInitialized()) {
+ self::configure();
+ }
+ return self::getHierarchy()->getLogger($name);
+ }
+
+ /**
+ * Returns the Root Logger.
+ * @return RootLogger
+ */
+ public static function getRootLogger() {
+ if(!self::isInitialized()) {
+ self::configure();
+ }
+ return self::getHierarchy()->getRootLogger();
+ }
+
+ /**
+ * Clears all Logger definitions from the logger hierarchy.
+ * @return boolean
+ */
+ public static function clear() {
+ return self::getHierarchy()->clear();
+ }
+
+ /**
+ * Destroy configurations for logger definitions
+ */
+ public static function resetConfiguration() {
+ self::getHierarchy()->resetConfiguration();
+ self::getHierarchy()->clear(); // TODO: clear or not?
+ self::$initialized = false;
+ }
+
+ /**
+ * Safely close all appenders.
+ * @deprecated This is no longer necessary due the appenders shutdown via
+ * destructors.
+ */
+ public static function shutdown() {
+ return self::getHierarchy()->shutdown();
+ }
+
+ /**
+ * check if a given logger exists.
+ *
+ * @param string $name logger name
+ * @return boolean
+ */
+ public static function exists($name) {
+ return self::getHierarchy()->exists($name);
+ }
+
+ /**
+ * Returns an array this whole Logger instances.
+ * @see Logger
+ * @return array
+ */
+ public static function getCurrentLoggers() {
+ return self::getHierarchy()->getCurrentLoggers();
+ }
+
+ /**
+ * Configures log4php.
+ *
+ * This method needs to be called before the first logging event has
+ * 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.
+ *
+ * @param string|Configurator $configurator A custom
+ * configurator class: either a class name (string), or an object which
+ * implements the Configurator interface. If left empty, the default
+ * configurator implementation will be used.
+ */
+ public static function configure($configuration = null, $configurator = null) {
+ self::resetConfiguration();
+ $configurator = self::getConfigurator($configurator);
+ $configurator->configure(self::getHierarchy(), $configuration);
+ self::$initialized = true;
+ }
+
+ /**
+ * Creates a logger configurator instance based on the provided
+ * configurator class. If no class is given, returns an instance of
+ * the default configurator.
+ *
+ * @param string|Configurator $configurator The configurator class
+ * or Configurator instance.
+ */
+ private static function getConfigurator($configurator = null) {
+ if ($configurator === null) {
+ return new Configuration\DefaultConfigurator();
+ }
+
+ if (is_object($configurator)) {
+ if ($configurator instanceof Configurator) {
+ return $configurator;
+ } else {
+ trigger_error("log4php: Given configurator object [$configurator] does not implement the Configurator interface. Reverting to default configurator.", E_USER_WARNING);
+ return new Configuration\DefaultConfigurator();
+ }
+ }
+
+ if (is_string($configurator)) {
+ if (!class_exists($configurator)) {
+ trigger_error("log4php: Specified configurator class [$configurator] does not exist. Reverting to default configurator.", E_USER_WARNING);
+ return new Configuration\DefaultConfigurator();
+ }
+
+ $instance = new $configurator();
+
+ if (!($instance instanceof Configurator)) {
+ trigger_error("log4php: Specified configurator class [$configurator] does not implement the Configurator interface. Reverting to default configurator.", E_USER_WARNING);
+ return new Configuration\DefaultConfigurator();
+ }
+
+ return $instance;
+ }
+
+ trigger_error("log4php: Invalid configurator specified. Expected either a string or a Configurator instance. Reverting to default configurator.", E_USER_WARNING);
+ return new Configuration\DefaultConfigurator();
+ }
+
+ /**
+ * Returns true if the log4php framework has been initialized.
+ * @return boolean
+ */
+ private static function isInitialized() {
+ return self::$initialized;
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/LoggerException.php
----------------------------------------------------------------------
diff --git a/src/LoggerException.php b/src/LoggerException.php
new file mode 100644
index 0000000..103c532
--- /dev/null
+++ b/src/LoggerException.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * 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.
+ */
+
+namespace Apache\Log4php;
+
+/**
+ * LoggerException class
+ */
+class LoggerException extends \Exception {
+}