move Horde_Log to git
authorChuck Hagenbuch <chuck@horde.org>
Fri, 7 Nov 2008 02:26:43 +0000 (21:26 -0500)
committerChuck Hagenbuch <chuck@horde.org>
Fri, 7 Nov 2008 02:26:43 +0000 (21:26 -0500)
26 files changed:
framework/Log/lib/Horde/Log.php [new file with mode: 0644]
framework/Log/lib/Horde/Log/Exception.php [new file with mode: 0644]
framework/Log/lib/Horde/Log/Filter/Interface.php [new file with mode: 0644]
framework/Log/lib/Horde/Log/Filter/Level.php [new file with mode: 0644]
framework/Log/lib/Horde/Log/Filter/Message.php [new file with mode: 0644]
framework/Log/lib/Horde/Log/Formatter/Interface.php [new file with mode: 0644]
framework/Log/lib/Horde/Log/Formatter/Simple.php [new file with mode: 0644]
framework/Log/lib/Horde/Log/Formatter/Xml.php [new file with mode: 0644]
framework/Log/lib/Horde/Log/Handler/Base.php [new file with mode: 0644]
framework/Log/lib/Horde/Log/Handler/Db.php [new file with mode: 0644]
framework/Log/lib/Horde/Log/Handler/Firebug.php [new file with mode: 0644]
framework/Log/lib/Horde/Log/Handler/Null.php [new file with mode: 0644]
framework/Log/lib/Horde/Log/Handler/Stream.php [new file with mode: 0644]
framework/Log/lib/Horde/Log/Logger.php [new file with mode: 0644]
framework/Log/package.xml [new file with mode: 0644]
framework/Log/test/Horde/Log/AllTests.php [new file with mode: 0644]
framework/Log/test/Horde/Log/Filter/ChainingTest.php [new file with mode: 0644]
framework/Log/test/Horde/Log/Filter/LevelTest.php [new file with mode: 0644]
framework/Log/test/Horde/Log/Filter/MessageTest.php [new file with mode: 0644]
framework/Log/test/Horde/Log/Formatter/SimpleTest.php [new file with mode: 0644]
framework/Log/test/Horde/Log/Formatter/XmlTest.php [new file with mode: 0644]
framework/Log/test/Horde/Log/Handler/DbTest.php [new file with mode: 0644]
framework/Log/test/Horde/Log/Handler/FirebugTest.php [new file with mode: 0644]
framework/Log/test/Horde/Log/Handler/NullTest.php [new file with mode: 0644]
framework/Log/test/Horde/Log/Handler/StreamTest.php [new file with mode: 0644]
framework/Log/test/Horde/Log/LogTest.php [new file with mode: 0644]

diff --git a/framework/Log/lib/Horde/Log.php b/framework/Log/lib/Horde/Log.php
new file mode 100644 (file)
index 0000000..08d065c
--- /dev/null
@@ -0,0 +1,46 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * This package is based on Zend_Log from the Zend Framework
+ * (http://framework.zend.com).  Both that package and this
+ * one were written by Mike Naberezny and Chuck Hagenbuch.
+ *
+ * @category Horde
+ * @package  Horde_Log
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * @category Horde
+ * @package Horde_Log
+ */
+class Horde_Log {
+
+    /** Emergency: system is unusable */
+    const EMERG = 0;
+
+    /** Alert: action must be taken immediately */
+    const ALERT = 1;
+
+    /** Critical: critical conditions */
+    const CRIT = 2;
+
+    /** Error: error conditions */
+    const ERR = 3;
+
+    /** Warning: warning conditions */
+    const WARN = 4;
+
+    /** Notice: normal but significant condition */
+    const NOTICE = 5;
+
+    /** Informational: informational messages */
+    const INFO = 6;
+
+    /** Debug: debug-level messages */
+    const DEBUG = 7;
+
+}
diff --git a/framework/Log/lib/Horde/Log/Exception.php b/framework/Log/lib/Horde/Log/Exception.php
new file mode 100644 (file)
index 0000000..6f006d2
--- /dev/null
@@ -0,0 +1,30 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * This package is based on Zend_Log from the Zend Framework
+ * (http://framework.zend.com).  Both that package and this
+ * one were written by Mike Naberezny and Chuck Hagenbuch.
+ *
+ * @package  Horde_Log
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * @package  Horde_Log
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Log_Exception extends Exception
+{
+    /**
+     */
+    public function __construct($msg, $code = 0)
+    {
+        parent::__construct($msg, $code);
+    }
+
+}
diff --git a/framework/Log/lib/Horde/Log/Filter/Interface.php b/framework/Log/lib/Horde/Log/Filter/Interface.php
new file mode 100644 (file)
index 0000000..48120cb
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * This package is based on Zend_Log from the Zend Framework
+ * (http://framework.zend.com).  Both that package and this
+ * one were written by Mike Naberezny and Chuck Hagenbuch.
+ *
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage Filters
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage Filters
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+interface Horde_Log_Filter_Interface
+{
+    /**
+     * Returns TRUE to accept the message, FALSE to block it.
+     *
+     * @param  array    $event    Log event
+     * @return boolean            accepted?
+     */
+    public function accept($event);
+
+}
diff --git a/framework/Log/lib/Horde/Log/Filter/Level.php b/framework/Log/lib/Horde/Log/Filter/Level.php
new file mode 100644 (file)
index 0000000..8585b56
--- /dev/null
@@ -0,0 +1,53 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * This package is based on Zend_Log from the Zend Framework
+ * (http://framework.zend.com).  Both that package and this
+ * one were written by Mike Naberezny and Chuck Hagenbuch.
+ *
+ * @package  Horde_Log
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * @package  Horde_Log
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Log_Filter_Level implements Horde_Log_Filter_Interface
+{
+    /**
+     * @var integer
+     */
+    protected $_level;
+
+    /**
+     * Filter out any log messages greater than $level.
+     *
+     * @param  integer  $level  Maximum log level to pass through the filter
+     */
+    public function __construct($level)
+    {
+        if (! is_integer($level)) {
+            throw new Horde_Log_Exception('Level must be an integer');
+        }
+
+        $this->_level = $level;
+    }
+
+    /**
+     * Returns TRUE to accept the message, FALSE to block it.
+     *
+     * @param  array    $event    Log event
+     * @return boolean            accepted?
+     */
+    public function accept($event)
+    {
+        return $event['level'] <= $this->_level;
+    }
+
+}
diff --git a/framework/Log/lib/Horde/Log/Filter/Message.php b/framework/Log/lib/Horde/Log/Filter/Message.php
new file mode 100644 (file)
index 0000000..74b6d0b
--- /dev/null
@@ -0,0 +1,57 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * This package is based on Zend_Log from the Zend Framework
+ * (http://framework.zend.com).  Both that package and this
+ * one were written by Mike Naberezny and Chuck Hagenbuch.
+ *
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage Filters
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage Filters
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Log_Filter_Message implements Horde_Log_Filter_Interface
+{
+    /**
+     * @var string
+     */
+    protected $_regexp;
+
+    /**
+     * Filter out any log messages not matching $regexp.
+     *
+     * @param  string  $regexp     Regular expression to test the log message
+     * @throws Horde_Log_Exception  Invalid regular expression
+     */
+    public function __construct($regexp)
+    {
+        if (@preg_match($regexp, '') === false) {
+            throw new Horde_Log_Exception("Invalid regular expression '$regexp'");
+        }
+        $this->_regexp = $regexp;
+    }
+
+    /**
+     * Returns TRUE to accept the message, FALSE to block it.
+     *
+     * @param  array    $event    Log event
+     * @return boolean            accepted?
+     */
+    public function accept($event)
+    {
+        return preg_match($this->_regexp, $event['message']) > 0;
+    }
+
+}
diff --git a/framework/Log/lib/Horde/Log/Formatter/Interface.php b/framework/Log/lib/Horde/Log/Formatter/Interface.php
new file mode 100644 (file)
index 0000000..0975abc
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * This package is based on Zend_Log from the Zend Framework
+ * (http://framework.zend.com).  Both that package and this
+ * one were written by Mike Naberezny and Chuck Hagenbuch.
+ *
+ * @package  Horde_Log
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * @package  Horde_Log
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+interface Horde_Log_Formatter_Interface
+{
+    /**
+     * Formats an event to be written by the handler.
+     *
+     * @param  array    $event    Log event
+     * @return string             formatted line
+     */
+    public function format($event);
+
+}
diff --git a/framework/Log/lib/Horde/Log/Formatter/Simple.php b/framework/Log/lib/Horde/Log/Formatter/Simple.php
new file mode 100644 (file)
index 0000000..939f6a5
--- /dev/null
@@ -0,0 +1,71 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * This package is based on Zend_Log from the Zend Framework
+ * (http://framework.zend.com).  Both that package and this
+ * one were written by Mike Naberezny and Chuck Hagenbuch.
+ *
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage Formatters
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage Formatters
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Log_Formatter_Simple
+{
+    /**
+     * Format string
+     *
+     * @var string
+     */
+    protected $_format;
+
+    /**
+     * Constructor
+     */
+    public function __construct($options = null)
+    {
+        if (is_array($options) && isset($options['format'])) {
+            $format = $options['format'];
+        } else {
+            $format = $options;
+        }
+
+        if (is_null($format)) {
+            $format = '%timestamp% %levelName%: %message%' . PHP_EOL;
+        }
+
+        if (!is_string($format)) {
+            throw new Horde_Log_Exception('Format must be a string');
+        }
+
+        $this->_format = $format;
+    }
+
+    /**
+     * Formats an event to be written by the handler.
+     *
+     * @param  array    $event    Log event
+     * @return string             formatted line
+     */
+    public function format($event)
+    {
+        $output = $this->_format;
+        foreach ($event as $name => $value) {
+            $output = str_replace("%$name%", $value, $output);
+        }
+        return $output;
+    }
+
+}
diff --git a/framework/Log/lib/Horde/Log/Formatter/Xml.php b/framework/Log/lib/Horde/Log/Formatter/Xml.php
new file mode 100644 (file)
index 0000000..9b35119
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * This package is based on Zend_Log from the Zend Framework
+ * (http://framework.zend.com).  Both that package and this
+ * one were written by Mike Naberezny and Chuck Hagenbuch.
+ *
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage Formatters
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage Formatters
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Log_Formatter_Xml
+{
+    protected $_options = array('elementEntry'     => 'log',
+                                'elementTimestamp' => 'timestamp',
+                                'elementMessage'   => 'message',
+                                'elementLevel'     => 'level',
+                                'lineEnding'       => PHP_EOL);
+
+    public function __construct($options = array())
+    {
+        $this->_options = array_merge($this->_options, $options);
+    }
+
+    /**
+     * Formats an event to be written by the handler.
+     *
+     * @param  array    $event    Log event
+     * @return string             XML string
+     */
+    public function format($event)
+    {
+        $dom = new DOMDocument();
+
+        $elt = $dom->appendChild(new DOMElement($this->_options['elementEntry']));
+        $elt->appendChild(new DOMElement($this->_options['elementTimestamp'], date('c')));
+        $elt->appendChild(new DOMElement($this->_options['elementMessage'], $event['message']));
+        $elt->appendChild(new DOMElement($this->_options['elementLevel'], $event['level']));
+
+        $xml = $dom->saveXML();
+        $xml = preg_replace('/<\?xml version="1.0"( encoding="[^\"]*")?\?>\n/u', '', $xml);
+
+        return $xml . $this->_options['lineEnding'];
+    }
+
+}
diff --git a/framework/Log/lib/Horde/Log/Handler/Base.php b/framework/Log/lib/Horde/Log/Handler/Base.php
new file mode 100644 (file)
index 0000000..8279b03
--- /dev/null
@@ -0,0 +1,95 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * This package is based on Zend_Log from the Zend Framework
+ * (http://framework.zend.com).  Both that package and this
+ * one were written by Mike Naberezny and Chuck Hagenbuch.
+ *
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage Handlers
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage Handlers
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+abstract class Horde_Log_Handler_Base
+{
+    /**
+     * @var array of key/value pair options
+     */
+    protected $_options = array();
+
+    /**
+     * @var array of Horde_Log_Filter_Interface
+     */
+    protected $_filters = array();
+
+    /**
+     * Add a filter specific to this handler.
+     *
+     * @param  Horde_Log_Filter_Interface  $filter
+     * @return void
+     */
+    public function addFilter($filter)
+    {
+        if (is_integer($filter)) {
+            $filter = new Horde_Log_Filter_Level($filter);
+        }
+
+        $this->_filters[] = $filter;
+    }
+
+    /**
+     * Log a message to this handler.
+     *
+     * @param  array    $event    Log event
+     * @return void
+     */
+    public function log($event)
+    {
+        // if any local filter rejects the message, don't log it.
+        foreach ($this->_filters as $filter) {
+            if (!$filter->accept($event)) {
+                return;
+            }
+        }
+
+        $this->write($event);
+    }
+
+    /**
+     * Sets an option specific to the implementation of the log handler.
+     *
+     * @param  $optionKey      Key name for the option to be changed.  Keys are handler-specific
+     * @param  $optionValue    New value to assign to the option
+     * @return bool            True
+     */
+    public function setOption($optionKey, $optionValue)
+    {
+        if (!isset($this->_options[$optionKey])) {
+            throw new Horde_Log_Exception("Unknown option \"$optionKey\".");
+        }
+        $this->_options[$optionKey] = $optionValue;
+
+        return true;
+    }
+
+    /**
+     * Buffer a message to be stored in the storage
+     * implemented by this handler.
+     *
+     * @param  array    $event    Log event
+     */
+    abstract public function write($event);
+
+}
diff --git a/framework/Log/lib/Horde/Log/Handler/Db.php b/framework/Log/lib/Horde/Log/Handler/Db.php
new file mode 100644 (file)
index 0000000..6c54533
--- /dev/null
@@ -0,0 +1,76 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * This package is based on Zend_Log from the Zend Framework
+ * (http://framework.zend.com).  Both that package and this
+ * one were written by Mike Naberezny and Chuck Hagenbuch.
+ *
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage Handlers
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage Handlers
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Log_Handler_Db extends Horde_Log_Handler_Base
+{
+    /**
+     * Database adapter instance
+     * @var Horde_Db_Adapter
+     */
+    private $_db;
+
+    /**
+     * Name of the log table in the database
+     * @var string
+     */
+    private $_table;
+
+    /**
+     * Options to be set by setOption().  Sets the field names in the database table.
+     *
+     * @var array
+     */
+    protected $_options = array('fieldMessage'  => 'message',
+                                'fieldLevel'    => 'level');
+
+    /**
+     * Class constructor
+     *
+     * @param Horde_Db_Adapter $db  Database adapter instance
+     * @param string $table         Log table in database
+     */
+    public function __construct($db, $table)
+    {
+        $this->_db    = $db;
+        $this->_table = $table;
+    }
+
+    /**
+     * Write a message to the log.
+     *
+     * @param  array    $event    Log event
+     * @return bool               Always True
+     */
+    public function write($event)
+    {
+        $fields = array(
+            $this->_options['fieldMessage'] => $event['message'],
+            $this->_options['fieldLevel']   => $event['level'],
+        );
+
+        $this->_db->insert($this->_table, $fields);
+        return true;
+    }
+
+}
diff --git a/framework/Log/lib/Horde/Log/Handler/Firebug.php b/framework/Log/lib/Horde/Log/Handler/Firebug.php
new file mode 100644 (file)
index 0000000..f209eb8
--- /dev/null
@@ -0,0 +1,122 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage Handlers
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage Handlers
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Log_Handler_Firebug extends Horde_Log_Handler_Base
+{
+    /**
+     * Formats the log message before writing.
+     * @var Horde_Log_Formatter_Interface
+     */
+    protected $_formatter;
+
+    /**
+     * Options to be set by setOption().  Sets the field names in the database table.
+     *
+     * @var array
+     */
+    protected $_options = array('buffering' => false);
+
+    /**
+     * Array of buffered output.
+     * @var string
+     */
+    protected $_buffer = array();
+
+    /**
+     * Mapping of log priorities to Firebug methods.
+     * @var array
+     * @access private
+     */
+    protected static $_methods = array(
+        Horde_Log::EMERG   => 'error',
+        Horde_Log::ALERT   => 'error',
+        Horde_Log::CRIT    => 'error',
+        Horde_Log::ERR     => 'error',
+        Horde_Log::WARN    => 'warn',
+        Horde_Log::NOTICE  => 'info',
+        Horde_Log::INFO    => 'info',
+        Horde_Log::DEBUG   => 'debug',
+    );
+
+    /**
+     * Class Constructor
+     */
+    public function __construct()
+    {
+        $this->_formatter = new Horde_Log_Formatter_Simple();
+    }
+
+    /**
+     * Write a message to the firebug console.  This function really just writes
+     * the message to the buffer.  If buffering is enabled, the
+     * message won't be output until the buffer is flushed. If
+     * buffering is not enabled, the buffer will be flushed
+     * immediately.
+     *
+     * @param  array    $event    Log event
+     * @return bool               Always True
+     */
+    public function write($event)
+    {
+        $this->_buffer[] = $event;
+
+        if (empty($this->_options['buffering'])) {
+            $this->flush();
+        }
+
+        return true;
+    }
+
+    /**
+     */
+    public function flush()
+    {
+        if (!count($this->_buffer)) {
+            return true;
+        }
+
+        $output = array();
+        foreach ($this->_buffer as $event) {
+            $line = trim($this->_formatter->format($event));
+
+            // normalize line breaks
+            $line = str_replace("\r\n", "\n", $line);
+
+            // escape line breaks
+            $line = str_replace("\n", "\\n\\\n", $line);
+
+            // escape quotes
+            $line = str_replace('"', '\\"', $line);
+
+            // firebug call
+            $method = isset(self::$_methods[$event['level']]) ? self::$_methods[$event['level']] : 'log';
+            $output[] = 'console.' . $method . '("' . $line . '");';
+        }
+
+        echo '<script type="text/javascript">'
+            . "\nif (('console' in window) || ('firebug' in console)) {\n"
+            . implode("\n", $output) . "\n"
+            . "}\n"
+            . "</script>\n";
+
+        $this->_buffer = array();
+    }
+
+}
diff --git a/framework/Log/lib/Horde/Log/Handler/Null.php b/framework/Log/lib/Horde/Log/Handler/Null.php
new file mode 100644 (file)
index 0000000..0e0bbc5
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * This package is based on Zend_Log from the Zend Framework
+ * (http://framework.zend.com).  Both that package and this
+ * one were written by Mike Naberezny and Chuck Hagenbuch.
+ *
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage Handlers
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage Handlers
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Log_Handler_Null extends Horde_Log_Handler_Base
+{
+    /**
+     * Write a message to the log buffer
+     */
+    public function write($event)
+    {
+        return true;
+    }
+
+}
\ No newline at end of file
diff --git a/framework/Log/lib/Horde/Log/Handler/Stream.php b/framework/Log/lib/Horde/Log/Handler/Stream.php
new file mode 100644 (file)
index 0000000..bea99a8
--- /dev/null
@@ -0,0 +1,84 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * This package is based on Zend_Log from the Zend Framework
+ * (http://framework.zend.com).  Both that package and this
+ * one were written by Mike Naberezny and Chuck Hagenbuch.
+ *
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage Handlers
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage Handlers
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Log_Handler_Stream extends Horde_Log_Handler_Base
+{
+    /**
+     * Formats the log message before writing.
+     * @var Horde_Log_Formatter_Interface
+     */
+    protected $_formatter;
+
+    /**
+     * Holds the PHP stream to log to.
+     * @var null|stream
+     */
+    protected $_stream = null;
+
+    /**
+     * Class Constructor
+     *
+     * @param mixed $streamOrUrl   Stream or URL to open as a stream
+     * @param string $mode         Mode, only applicable if a URL is given
+     */
+    public function __construct($streamOrUrl, $mode = 'a+')
+    {
+        $this->_formatter = new Horde_Log_Formatter_Simple();
+
+        if (is_resource($streamOrUrl)) {
+            if (get_resource_type($streamOrUrl) != 'stream') {
+                throw new Horde_Log_Exception('Resource is not a stream');
+            }
+
+            if ($mode != 'a+') {
+                throw new Horde_Log_Exception('Mode cannot be changed on existing streams');
+            }
+
+            $this->_stream = $streamOrUrl;
+        } else {
+            if (! $this->_stream = @fopen($streamOrUrl, $mode, false)) {
+                $msg = "\"$streamOrUrl\" cannot be opened with mode \"$mode\"";
+                throw new Horde_Log_Exception($msg);
+            }
+        }
+    }
+
+    /**
+     * Write a message to the log.
+     *
+     * @param  array    $event    Log event
+     * @return bool               Always True
+     */
+    public function write($event)
+    {
+        $line = $this->_formatter->format($event);
+
+        if (! @fwrite($this->_stream, $line)) {
+            throw new Horde_Log_Exception("Unable to write to stream");
+        }
+
+        return true;
+    }
+
+}
diff --git a/framework/Log/lib/Horde/Log/Logger.php b/framework/Log/lib/Horde/Log/Logger.php
new file mode 100644 (file)
index 0000000..5a0617a
--- /dev/null
@@ -0,0 +1,191 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * This package is based on Zend_Log from the Zend Framework
+ * (http://framework.zend.com).  Both that package and this
+ * one were written by Mike Naberezny and Chuck Hagenbuch.
+ *
+ * @category Horde
+ * @package  Horde_Log
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * @category Horde
+ * @package  Horde_Log
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ *
+ * @method void LOGLEVEL() LOGLEVEL($event) Log an event at LOGLEVEL, where LOGLEVEL has been added with addLevel() or already exists
+ * @method void emerg() emerg($event) Log an event at the EMERG log level
+ * @method void alert() alert($event) Log an event at the ALERT log level
+ * @method void crit() crit($event) Log an event at the CRIT log level
+ * @method void err() err($event) Log an event at the ERR log level
+ * @method void warn() warn($event) Log an event at the WARN log level
+ * @method void notice() notice($event) Log an event at the NOTICE log level
+ * @method void info() info($event) Log an event at the INFO log level
+ * @method void debug() debug($event) Log an event at the DEBUG log level
+ */
+class Horde_Log_Logger
+{
+    /**
+     * @var array of log levels where the keys are the
+     * level priorities and the values are the level names
+     */
+    private $_levels = array();
+
+    /**
+     * @var array of Horde_Log_Handler_Abstract objects
+     */
+    private $_handlers = array();
+
+    /**
+     * @var array of Horde_Log_Filter_Interface objects
+     */
+    private $_filters = array();
+
+    /**
+     * Class constructor.  Create a new logger
+     *
+     * @param Horde_Log_Handler_Abstract|null  $handler  default handler
+     */
+    public function __construct($handler = null)
+    {
+        $r = new ReflectionClass('Horde_Log');
+        $this->_levels = array_flip($r->getConstants());
+
+        if ($handler !== null) {
+            $this->addHandler($handler);
+        }
+    }
+
+    /**
+     * Undefined method handler allows a shortcut:
+     *   $log->levelName('message')
+     *     instead of
+     *   $log->log('message', Horde_Log_LEVELNAME)
+     *
+     * @param  string  $method  log level name
+     * @param  string  $params  message to log
+     * @return void
+     */
+    public function __call($method, $params)
+    {
+        $level = strtoupper($method);
+        if (($level = array_search($level, $this->_levels)) !== false) {
+            $this->log(array_shift($params), $level);
+        } else {
+            throw new Horde_Log_Exception('Bad log level');
+        }
+    }
+
+    /**
+     * Log a message at a level
+     *
+     * @param  mixed    $event  Message to log, either an array or a string
+     * @param  integer  $level  Log level of message, required if $message is a string
+     * @return void
+     */
+    public function log($event, $level = null)
+    {
+        if (empty($this->_handlers)) {
+            throw new Horde_Log_Exception('No handlers were added');
+        }
+
+        // Create an event array from the given arguments.
+        if (is_array($event)) {
+            // If we are passed an array, it must contain 'message'
+            // and 'level' indices.
+            if (!isset($event['message'])) {
+                throw new Horde_Log_Exception('Event array did not contain a message');
+            }
+            if (!isset($event['level'])) {
+                if ($level === null) {
+                    throw new Horde_Log_Exception('Event array did not contain a log level');
+                } else {
+                    $event['level'] = $level;
+                }
+            }
+        } else {
+            // Create an event array from the message and level
+            // arguments.
+            $event = array('message' => $event, 'level' => $level);
+        }
+
+        if (!isset($this->_levels[$event['level']])) {
+            throw new Horde_Log_Exception('Bad log level');
+        }
+
+        // Fill in the level name and timestamp for filters, formatters, handlers
+        $event['levelName'] = $this->_levels[$event['level']];
+
+        if (!isset($event['timestamp'])) {
+            $event['timestamp'] = date('c');
+        }
+
+        // If any global filter rejects the event, don't log it.
+        foreach ($this->_filters as $filter) {
+            if (!$filter->accept($event)) {
+                return;
+            }
+        }
+
+        foreach ($this->_handlers as $handler) {
+            $handler->log($event);
+        }
+    }
+
+    /**
+     * Add a custom log level
+     *
+     * @param  string  $name    Name of level
+     * @param  integer  $level  Numeric level
+     * @return void
+     */
+    public function addLevel($name, $level)
+    {
+        // Log level names must be uppercase for predictability.
+        $name = strtoupper($name);
+
+        if (isset($this->_levels[$level])
+            || array_search($name, $this->_levels)) {
+            throw new Horde_Log_Exception('Existing log levels cannot be overwritten');
+        }
+
+        $this->_levels[$level] = $name;
+    }
+
+    /**
+     * Add a filter that will be applied before all log handlers.
+     * Before a message will be received by any of the handlers, it
+     * must be accepted by all filters added with this method.
+     *
+     * @param  Horde_Log_Filter_Interface  $filter
+     * @return void
+     */
+    public function addFilter($filter)
+    {
+        if (is_integer($filter)) {
+            $filter = new Horde_Log_Filter_Level($filter);
+        }
+
+        $this->_filters[] = $filter;
+    }
+
+    /**
+     * Add a handler.  A handler is responsible for taking a log
+     * message and writing it out to storage.
+     *
+     * @param  Horde_Log_Handler_Abstract $handler
+     * @return void
+     */
+    public function addHandler($handler)
+    {
+        $this->_handlers[] = $handler;
+    }
+
+}
diff --git a/framework/Log/package.xml b/framework/Log/package.xml
new file mode 100644 (file)
index 0000000..85e5aa4
--- /dev/null
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package packagerversion="1.4.9" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+http://pear.php.net/dtd/tasks-1.0.xsd
+http://pear.php.net/dtd/package-2.0
+http://pear.php.net/dtd/package-2.0.xsd">
+ <name>Log</name>
+ <channel>pear.horde.org</channel>
+ <summary>Horde Logging library</summary>
+ <description>Horde Logging package with configurable handlers, filters, and formatting.
+ </description>
+ <lead>
+  <name>Chuck Hagenbuch</name>
+  <user>chuck</user>
+  <email>chuck@horde.org</email>
+  <active>yes</active>
+ </lead>
+ <lead>
+  <name>Mike Naberezny</name>
+  <user>mnaberez</user>
+  <email>mike@maintainable.com</email>
+  <active>yes</active>
+ </lead>
+ <date>2007-10-21</date>
+ <time>23:26:00</time>
+ <version>
+  <release>0.1.0</release>
+  <api>0.1.0</api>
+ </version>
+ <stability>
+  <release>beta</release>
+  <api>beta</api>
+ </stability>
+ <license uri="http://opensource.org/licenses/bsd-license.php">BSD</license>
+ <notes>Initial Horde_Log release
+ </notes>
+ <contents>
+  <dir name="/">
+   <dir name="lib">
+    <dir name="Horde">
+     <dir name="Log">
+      <dir name="Filter">
+       <file name="Interface.php" role="php" />
+       <file name="Level.php" role="php" />
+       <file name="Message.php" role="php" />
+      </dir> <!-- /lib/Horde/Log/Filter -->
+      <dir name="Formatter">
+       <file name="Interface.php" role="php" />
+       <file name="Simple.php" role="php" />
+       <file name="Xml.php" role="php" />
+      </dir> <!-- /lib/Horde/Log/Formatter -->
+      <dir name="Handler">
+       <file name="Base.php" role="php" />
+       <file name="Db.php" role="php" />
+       <file name="Firebug.php" role="php" />
+       <file name="Null.php" role="php" />
+       <file name="Stream.php" role="php" />
+      </dir> <!-- /lib/Horde/Log/Handler -->
+      <file name="Exception.php" role="php" />
+      <file name="Logger.php" role="php" />
+     </dir> <!-- /lib/Horde/Log -->
+     <file name="Log.php" role="php" />
+    </dir> <!-- /lib/Horde -->
+   </dir> <!-- /lib -->
+  </dir>
+ </contents>
+ <dependencies>
+  <required>
+   <php>
+    <min>5.2</min>
+   </php>
+   <pearinstaller>
+    <min>1.5.0</min>
+   </pearinstaller>
+  </required>
+ </dependencies>
+ <phprelease>
+  <filelist>
+   <install name="lib/Horde/Log/Exception.php" as="Horde/Log/Exception.php" />
+   <install name="lib/Horde/Log/Filter/Interface.php" as="Horde/Log/Filter/Interface.php" />
+   <install name="lib/Horde/Log/Filter/Level.php" as="Horde/Log/Filter/Level.php" />
+   <install name="lib/Horde/Log/Filter/Message.php" as="Horde/Log/Filter/Message.php" />
+   <install name="lib/Horde/Log/Formatter/Interface.php" as="Horde/Log/Formatter/Interface.php" />
+   <install name="lib/Horde/Log/Formatter/Simple.php" as="Horde/Log/Formatter/Simple.php" />
+   <install name="lib/Horde/Log/Formatter/Xml.php" as="Horde/Log/Formatter/Xml.php" />
+   <install name="lib/Horde/Log/Handler/Base.php" as="Horde/Log/Handler/Base.php" />
+   <install name="lib/Horde/Log/Handler/Db.php" as="Horde/Log/Handler/Db.php" />
+   <install name="lib/Horde/Log/Handler/Firebug.php" as="Horde/Log/Handler/Firebug.php" />
+   <install name="lib/Horde/Log/Handler/Null.php" as="Horde/Log/Handler/Null.php" />
+   <install name="lib/Horde/Log/Handler/Stream.php" as="Horde/Log/Handler/Stream.php" />
+   <install name="lib/Horde/Log/Logger.php" as="Horde/Log/Logger.php" />
+   <install name="lib/Horde/Log.php" as="Horde/Log.php" />
+  </filelist>
+ </phprelease>
+</package>
diff --git a/framework/Log/test/Horde/Log/AllTests.php b/framework/Log/test/Horde/Log/AllTests.php
new file mode 100644 (file)
index 0000000..b19ccff
--- /dev/null
@@ -0,0 +1,70 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * This package is based on Zend_Log from the Zend Framework
+ * (http://framework.zend.com).  Both that package and this
+ * one were written by Mike Naberezny and Chuck Hagenbuch.
+ *
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage UnitTests
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+if (!defined('PHPUnit_MAIN_METHOD')) {
+    define('PHPUnit_MAIN_METHOD', 'Horde_Log_AllTests::main');
+}
+
+require_once 'PHPUnit/Framework/TestSuite.php';
+require_once 'PHPUnit/TextUI/TestRunner.php';
+
+/**
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage UnitTests
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Log_AllTests
+{
+
+    public static function main()
+    {
+        PHPUnit_TextUI_TestRunner::run(self::suite());
+    }
+
+    public static function suite()
+    {
+        set_include_path(dirname(__FILE__) . '/../../../lib' . PATH_SEPARATOR . get_include_path());
+        if (!spl_autoload_functions()) {
+            spl_autoload_register(create_function('$class', '$filename = str_replace(array(\'::\', \'_\'), \'/\', $class); include "$filename.php";'));
+        }
+
+        $suite = new PHPUnit_Framework_TestSuite('Horde_Log');
+
+        $basedir = dirname(__FILE__);
+        $baseregexp = preg_quote($basedir . DIRECTORY_SEPARATOR, '/');
+
+        foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($basedir)) as $file) {
+            if ($file->isFile() && preg_match('/Test.php$/', $file->getFilename())) {
+                $pathname = $file->getPathname();
+                require $pathname;
+
+                $class = 'Horde_Log_' . str_replace(DIRECTORY_SEPARATOR, '_',
+                                                    preg_replace("/^$baseregexp(.*)\.php/", '\\1', $pathname));
+                $suite->addTestSuite($class);
+            }
+        }
+
+        return $suite;
+    }
+
+}
+
+if (PHPUnit_MAIN_METHOD == 'Horde_Log_AllTests::main') {
+    Horde_Log_AllTests::main();
+}
diff --git a/framework/Log/test/Horde/Log/Filter/ChainingTest.php b/framework/Log/test/Horde/Log/Filter/ChainingTest.php
new file mode 100644 (file)
index 0000000..4927fde
--- /dev/null
@@ -0,0 +1,79 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * This package is based on Zend_Log from the Zend Framework
+ * (http://framework.zend.com).  Both that package and this
+ * one were written by Mike Naberezny and Chuck Hagenbuch.
+ *
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage UnitTests
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage UnitTests
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Log_Filter_ChainingTest extends PHPUnit_Framework_TestCase
+{
+    public function setUp()
+    {
+        date_default_timezone_set('America/New_York');
+
+        $this->log = fopen('php://memory', 'w');
+        $this->logger = new Horde_Log_Logger();
+        $this->logger->addHandler(new Horde_Log_Handler_Stream($this->log));
+    }
+
+    public function tearDown()
+    {
+        fclose($this->log);
+    }
+
+    public function testFilterAllHandlers()
+    {
+        // filter out anything above a WARNing for all handlers
+        $this->logger->addFilter(Horde_Log::WARN);
+
+        $this->logger->info($ignored = 'info-message-ignored');
+        $this->logger->warn($logged  = 'warn-message-logged');
+
+        rewind($this->log);
+        $logdata = stream_get_contents($this->log);
+
+        $this->assertNotContains($ignored, $logdata);
+        $this->assertContains($logged, $logdata);
+    }
+
+
+    public function testFilterOnSpecificHandler()
+    {
+        $log2 = fopen('php://memory', 'w');
+        $handler2 = new Horde_Log_Handler_Stream($log2);
+        $handler2->addFilter(Horde_Log::ERR);
+
+        $this->logger->addHandler($handler2);
+
+        $this->logger->warn($warn = 'warn-message');
+        $this->logger->err($err = 'err-message');
+
+        rewind($this->log);
+        $logdata = stream_get_contents($this->log);
+        $this->assertContains($warn, $logdata);
+        $this->assertContains($err, $logdata);
+
+        rewind($log2);
+        $logdata = stream_get_contents($log2);
+        $this->assertContains($err, $logdata);
+        $this->assertNotContains($warn, $logdata);
+    }
+
+}
diff --git a/framework/Log/test/Horde/Log/Filter/LevelTest.php b/framework/Log/test/Horde/Log/Filter/LevelTest.php
new file mode 100644 (file)
index 0000000..76bca92
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * This package is based on Zend_Log from the Zend Framework
+ * (http://framework.zend.com).  Both that package and this
+ * one were written by Mike Naberezny and Chuck Hagenbuch.
+ *
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage UnitTests
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage UnitTests
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Log_Filter_LevelTest extends PHPUnit_Framework_TestCase
+{
+
+    public function setUp()
+    {
+        // accept at or below level 2
+        $this->filter = new Horde_Log_Filter_Level(2);
+    }
+
+    public function testLevelFilterAccept()
+    {
+        $this->assertTrue($this->filter->accept(array('message' => '', 'level' => 2)));
+        $this->assertTrue($this->filter->accept(array('message' => '', 'level' => 1)));
+    }
+
+    public function testLevelFilterReject()
+    {
+        $this->assertFalse($this->filter->accept(array('message' => '', 'level' => 3)));
+    }
+
+    public function testConstructorThrowsOnInvalidLevel()
+    {
+        try {
+            new Horde_Log_Filter_Level('foo');
+            $this->fail();
+        } catch (Exception $e) {
+            $this->assertType('Horde_Log_Exception', $e);
+            $this->assertRegExp('/must be an integer/i', $e->getMessage());
+        }
+    }
+}
diff --git a/framework/Log/test/Horde/Log/Filter/MessageTest.php b/framework/Log/test/Horde/Log/Filter/MessageTest.php
new file mode 100644 (file)
index 0000000..c2aa1d2
--- /dev/null
@@ -0,0 +1,45 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * This package is based on Zend_Log from the Zend Framework
+ * (http://framework.zend.com).  Both that package and this
+ * one were written by Mike Naberezny and Chuck Hagenbuch.
+ *
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage UnitTests
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage UnitTests
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Log_Filter_MessageTest extends PHPUnit_Framework_TestCase
+{
+
+    public function testMessageFilterRecognizesInvalidRegularExpression()
+    {
+        try {
+            $filter = new Horde_Log_Filter_Message('invalid regexp');
+            $this->fail();
+        } catch (Horde_Log_Exception $e) {
+            $this->assertRegexp('/invalid reg/i', $e->getMessage());
+        }
+    }
+
+    public function testMessageFilter()
+    {
+        $filter = new Horde_Log_Filter_Message('/accept/');
+        $this->assertTrue($filter->accept(array('message' => 'foo accept bar', 'level' => 0)));
+        $this->assertFalse($filter->accept(array('message' => 'foo reject bar', 'level' => 0)));
+    }
+
+}
diff --git a/framework/Log/test/Horde/Log/Formatter/SimpleTest.php b/framework/Log/test/Horde/Log/Formatter/SimpleTest.php
new file mode 100644 (file)
index 0000000..3926cf4
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * This package is based on Zend_Log from the Zend Framework
+ * (http://framework.zend.com).  Both that package and this
+ * one were written by Mike Naberezny and Chuck Hagenbuch.
+ *
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage UnitTests
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage UnitTests
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Log_Formatter_SimpleTest extends PHPUnit_Framework_TestCase
+{
+    public function testConstructorThrowsOnBadFormatString()
+    {
+        try {
+            new Horde_Log_Formatter_Simple(1);
+            $this->fail();
+        } catch (Exception $e) {
+            $this->assertType('Horde_Log_Exception', $e);
+            $this->assertRegExp('/must be a string/i', $e->getMessage());
+        }
+    }
+
+    public function testDefaultFormat()
+    {
+        $f = new Horde_Log_Formatter_Simple();
+        $line = $f->format(array('message' => $message = 'message',
+                                 'level' => $level = Horde_Log::ALERT,
+                                 'levelName' => $levelName = 'ALERT'));
+
+        $this->assertContains($message, $line);
+        $this->assertContains($levelName, $line);
+    }
+}
diff --git a/framework/Log/test/Horde/Log/Formatter/XmlTest.php b/framework/Log/test/Horde/Log/Formatter/XmlTest.php
new file mode 100644 (file)
index 0000000..266b383
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * This package is based on Zend_Log from the Zend Framework
+ * (http://framework.zend.com).  Both that package and this
+ * one were written by Mike Naberezny and Chuck Hagenbuch.
+ *
+ * @category Horde
+ * @package  Horde_Log
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * @category Horde
+ * @package  Horde_Log
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Log_Formatter_XmlTest extends PHPUnit_Framework_TestCase
+{
+    public function setUp()
+    {
+        date_default_timezone_set('America/New_York');
+    }
+
+    public function testDefaultFormat()
+    {
+        $f = new Horde_Log_Formatter_Xml();
+        $line = $f->format(array('message' => $message = 'message', 'level' => $level = 1));
+
+        $this->assertContains($message, $line);
+        $this->assertContains((string)$level, $line);
+    }
+
+    public function testXmlDeclarationIsStripped()
+    {
+        $f = new Horde_Log_Formatter_Xml();
+        $line = $f->format(array('message' => $message = 'message', 'level' => $level = 1));
+
+        $this->assertNotContains('<\?xml version=', $line);
+    }
+
+    public function testXmlValidates()
+    {
+        $f = new Horde_Log_Formatter_Xml();
+        $line = $f->format(array('message' => $message = 'message', 'level' => $level = 1));
+
+        $sxml = @simplexml_load_string($line);
+        $this->assertType('SimpleXMLElement', $sxml, 'Formatted XML is invalid');
+    }
+}
diff --git a/framework/Log/test/Horde/Log/Handler/DbTest.php b/framework/Log/test/Horde/Log/Handler/DbTest.php
new file mode 100644 (file)
index 0000000..282a004
--- /dev/null
@@ -0,0 +1,84 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * This package is based on Zend_Log from the Zend Framework
+ * (http://framework.zend.com).  Both that package and this
+ * one were written by Mike Naberezny and Chuck Hagenbuch.
+ *
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage UnitTests
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage UnitTests
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Log_Handler_DbTest extends PHPUnit_Framework_TestCase
+{
+    public function setUp()
+    {
+        $this->tableName = 'db-table-name';
+
+        $this->db      = new Horde_Log_Handler_DbTest_MockDbAdapter();
+        $this->handler = new Horde_Log_Handler_Db($this->db, $this->tableName);
+    }
+
+    public function testWriteWithDefaults()
+    {
+        // log to the mock db adapter
+        $message = 'message-to-log';
+        $level   = 2;
+        $this->handler->write(array('message' => $message, 'level' => $level));
+
+        // insert should be called once...
+        $this->assertContains('insert', array_keys($this->db->calls));
+        $this->assertEquals(1, count($this->db->calls['insert']));
+
+        // ...with the correct table and binds for the database
+        $binds = array('message' => $message,
+                       'level' => $level);
+        $this->assertEquals(array($this->tableName, $binds),
+                            $this->db->calls['insert'][0]);
+    }
+
+    public function testWriteUsesOptionalCustomColumns()
+    {
+        $this->handler->setOption('fieldMessage', $messageField = 'new-message-field');
+        $this->handler->setOption('fieldLevel',   $levelField   = 'new-level-field');
+
+        // log to the mock db adapter
+        $message = 'message-to-log';
+        $level   = 2;
+        $this->handler->write(array('message' => $message, 'level' => $level));
+
+        // insert should be called once...
+        $this->assertContains('insert', array_keys($this->db->calls));
+        $this->assertEquals(1, count($this->db->calls['insert']));
+
+        // ...with the correct table and binds for the database
+        $binds = array($messageField => $message,
+                       $levelField   => $level);
+        $this->assertEquals(array($this->tableName, $binds),
+                            $this->db->calls['insert'][0]);
+    }
+}
+
+
+class Horde_Log_Handler_DbTest_MockDbAdapter
+{
+    public $calls = array();
+
+    public function __call($method, $params)
+    {
+        $this->calls[$method][] = $params;
+    }
+}
\ No newline at end of file
diff --git a/framework/Log/test/Horde/Log/Handler/FirebugTest.php b/framework/Log/test/Horde/Log/Handler/FirebugTest.php
new file mode 100644 (file)
index 0000000..7824ee3
--- /dev/null
@@ -0,0 +1,61 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * This package is based on Zend_Log from the Zend Framework
+ * (http://framework.zend.com).  Both that package and this
+ * one were written by Mike Naberezny and Chuck Hagenbuch.
+ *
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage UnitTests
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage UnitTests
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Log_Handler_FirebugTest extends PHPUnit_Framework_TestCase
+{
+    public function setUp()
+    {
+        date_default_timezone_set('America/New_York');
+    }
+
+    public function testSettingBadOptionThrows()
+    {
+        try {
+            $handler = new Horde_Log_Handler_Stream('php://memory');
+            $handler->setOption('foo', 42);
+            $this->fail();
+        } catch (Exception $e) {
+            $this->assertType('Horde_Log_Exception', $e);
+            $this->assertRegExp('/unknown option/i', $e->getMessage());
+        }
+    }
+
+    public function testWrite()
+    {
+        ob_start();
+
+        $handler = new Horde_Log_Handler_Firebug();
+        $handler->write(array('message' => $message = 'message-to-log',
+                              'level' => $level = Horde_Log::ALERT,
+                              'levelName' => $levelName = 'ALERT',
+                              'timestamp' => date('c')));
+
+        $contents = ob_get_clean();
+
+        $date = '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}-\d{2}:\d{2}';
+
+        $this->assertRegExp("/console.error\(\"$date $levelName: $message\"\);/", $contents);
+    }
+
+}
diff --git a/framework/Log/test/Horde/Log/Handler/NullTest.php b/framework/Log/test/Horde/Log/Handler/NullTest.php
new file mode 100644 (file)
index 0000000..2fb7818
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * This package is based on Zend_Log from the Zend Framework
+ * (http://framework.zend.com).  Both that package and this
+ * one were written by Mike Naberezny and Chuck Hagenbuch.
+ *
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage UnitTests
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage UnitTests
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Log_Handler_NullTest extends PHPUnit_Framework_TestCase
+{
+    public function testWrite()
+    {
+        $handler = new Horde_Log_Handler_Null();
+        $this->assertTrue($handler->write(array('message' => 'foo', 'level' => 42)));
+    }
+}
diff --git a/framework/Log/test/Horde/Log/Handler/StreamTest.php b/framework/Log/test/Horde/Log/Handler/StreamTest.php
new file mode 100644 (file)
index 0000000..eeb56ea
--- /dev/null
@@ -0,0 +1,125 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * This package is based on Zend_Log from the Zend Framework
+ * (http://framework.zend.com).  Both that package and this
+ * one were written by Mike Naberezny and Chuck Hagenbuch.
+ *
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage UnitTests
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage UnitTests
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Log_Handler_StreamTest extends PHPUnit_Framework_TestCase
+{
+    public function setUp()
+    {
+        date_default_timezone_set('America/New_York');
+    }
+
+    public function testConstructorThrowsWhenResourceIsNotStream()
+    {
+        $resource = xml_parser_create();
+        try {
+            new Horde_Log_Handler_Stream($resource);
+            $this->fail();
+        } catch (Exception $e) {
+            $this->assertType('Horde_Log_Exception', $e);
+            $this->assertRegExp('/not a stream/i', $e->getMessage());
+        }
+        xml_parser_free($resource);
+    }
+
+    public function testConstructorWithValidStream()
+    {
+        $stream = fopen('php://memory', 'a');
+        new Horde_Log_Handler_Stream($stream);
+    }
+
+    public function testConstructorWithValidUrl()
+    {
+        new Horde_Log_Handler_Stream('php://memory');
+    }
+
+    public function testConstructorThrowsWhenModeSpecifiedForExistingStream()
+    {
+        $stream = fopen('php://memory', 'a');
+        try {
+            new Horde_Log_Handler_Stream($stream, 'w');
+            $this->fail();
+        } catch (Exception $e) {
+            $this->assertType('Horde_Log_Exception', $e);
+            $this->assertRegExp('/existing stream/i', $e->getMessage());
+        }
+    }
+
+    public function testConstructorThrowsWhenStreamCannotBeOpened()
+    {
+        try {
+            new Horde_Log_Handler_Stream('');
+            $this->fail();
+        } catch (Exception $e) {
+            $this->assertType('Horde_Log_Exception', $e);
+            $this->assertRegExp('/cannot be opened/i', $e->getMessage());
+        }
+    }
+
+    public function testSettingBadOptionThrows()
+    {
+        try {
+            $handler = new Horde_Log_Handler_Stream('php://memory');
+            $handler->setOption('foo', 42);
+            $this->fail();
+        } catch (Exception $e) {
+            $this->assertType('Horde_Log_Exception', $e);
+            $this->assertRegExp('/unknown option/i', $e->getMessage());
+        }
+    }
+
+    public function testWrite()
+    {
+        $stream = fopen('php://memory', 'a');
+
+        $handler = new Horde_Log_Handler_Stream($stream);
+        $handler->write(array('message' => $message = 'message-to-log',
+                              'level' => $level = Horde_Log::ALERT,
+                              'levelName' => $levelName = 'ALERT',
+                              'timestamp' => date('c')));
+
+        rewind($stream);
+        $contents = stream_get_contents($stream);
+        fclose($stream);
+
+        $date = '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}-\d{2}:\d{2}';
+
+        $this->assertRegExp("/$date $levelName: $message/", $contents);
+    }
+
+    public function testWriteThrowsWhenStreamWriteFails()
+    {
+        $stream = fopen('php://memory', 'a');
+        $handler = new Horde_Log_Handler_Stream($stream);
+        fclose($stream);
+
+        try {
+            $handler->write(array('message' => 'foo', 'level' => 1));
+            $this->fail();
+        } catch (Exception $e) {
+            $this->assertType('Horde_Log_Exception', $e);
+            $this->assertRegExp('/unable to write/i', $e->getMessage());
+        }
+    }
+
+}
diff --git a/framework/Log/test/Horde/Log/LogTest.php b/framework/Log/test/Horde/Log/LogTest.php
new file mode 100644 (file)
index 0000000..26a38d9
--- /dev/null
@@ -0,0 +1,147 @@
+<?php
+/**
+ * Horde Log package
+ *
+ * This package is based on Zend_Log from the Zend Framework
+ * (http://framework.zend.com).  Both that package and this
+ * one were written by Mike Naberezny and Chuck Hagenbuch.
+ *
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage UnitTests
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * @category Horde
+ * @package  Horde_Log
+ * @subpackage UnitTests
+ * @author   Mike Naberezny <mike@maintainable.com>
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Log_LogTest extends PHPUnit_Framework_TestCase
+{
+    public function setUp()
+    {
+        date_default_timezone_set('America/New_York');
+
+        $this->log = fopen('php://memory', 'a');
+        $this->handler = new Horde_Log_Handler_Stream($this->log);
+    }
+
+    // Handlers
+
+    public function testHandlerCanBeAddedWithConstructor()
+    {
+        $logger = new Horde_Log_Logger($this->handler);
+        $logger->log($message = 'message-to-long', Horde_Log::INFO);
+
+        rewind($this->log);
+        $this->assertContains($message, stream_get_contents($this->log));
+    }
+
+    public function testaddHandler()
+    {
+        $logger = new Horde_Log_Logger();
+        $logger->addHandler($this->handler);
+        $logger->log($message = 'message-to-log', Horde_Log::INFO);
+
+        rewind($this->log);
+        $this->assertContains($message, stream_get_contents($this->log));
+    }
+
+    public function testaddHandlerAddsMultipleHandlers()
+    {
+        $logger = new Horde_Log_Logger();
+
+        // create handlers for two separate streams of temporary memory
+        $log1    = fopen('php://memory', 'a');
+        $handler1 = new Horde_Log_Handler_Stream($log1);
+        $log2    = fopen('php://memory', 'a');
+        $handler2 = new Horde_Log_Handler_Stream($log2);
+
+        // add the handlers
+        $logger->addHandler($handler1);
+        $logger->addHandler($handler2);
+
+        // log to both handlers
+        $logger->log($message = 'message-sent-to-both-logs', Horde_Log::INFO);
+
+        // verify both handlers were called by the logger
+        rewind($log1);
+        $this->assertContains($message, stream_get_contents($log1));
+        rewind($log2);
+        $this->assertContains($message, stream_get_contents($log2));
+
+        // prove the two memory streams are different
+        // and both handlers were indeed called
+        fwrite($log1, 'foo');
+        $this->assertNotEquals(ftell($log1), ftell($log2));
+    }
+
+    public function testLoggerThrowsWhenNoHandlers()
+    {
+        $logger = new Horde_Log_Logger();
+        try {
+            $logger->log('message', Horde_Log::INFO);
+            $this->fail();
+        } catch (Horde_Log_Exception $e) {
+            $this->assertRegexp('/no handler/i', $e->getMessage());
+        }
+    }
+
+    // Levels
+
+    public function testLogThrowsOnBadLogLevel()
+    {
+        $logger = new Horde_Log_Logger($this->handler);
+        try {
+            $logger->log('foo', 42);
+            $this->fail();
+        } catch (Exception $e) {
+            $this->assertType('Horde_Log_Exception', $e);
+            $this->assertRegExp('/bad log level/i', $e->getMessage());
+        }
+    }
+
+    public function testLogThrough__callThrowsOnBadLogLevel()
+    {
+        $logger = new Horde_Log_Logger($this->handler);
+        try {
+            $logger->nonexistantLevel('');
+            $this->fail();
+        } catch (Exception $e) {
+            $this->assertType('Horde_Log_Exception', $e);
+            $this->assertRegExp('/bad log level/i', $e->getMessage());
+        }
+    }
+
+    public function testAddingLevelThrowsWhenOverridingBuiltinLogLevel()
+    {
+        try {
+            $logger = new Horde_Log_Logger($this->handler);
+            $logger->addLevel('BOB', 0);
+            $this->fail();
+        } catch (Exception $e) {
+            $this->assertType('Horde_Log_Exception', $e);
+            $this->assertRegExp('/existing log level/i', $e->getMessage());
+        }
+
+    }
+
+    public function testAddLogLevel()
+    {
+        $logger = new Horde_Log_Logger($this->handler);
+        $logger->addLevel($levelName = 'EIGHT', $level = 8);
+
+        $logger->eight($message = 'eight message');
+
+        rewind($this->log);
+        $logdata = stream_get_contents($this->log);
+        $this->assertContains($levelName, $logdata);
+        $this->assertContains($message, $logdata);
+    }
+}