From 04f74dc0890d0720f9cca6dee183c69194927e03 Mon Sep 17 00:00:00 2001 From: "Jonathan.Wage" Date: Thu, 15 Nov 2007 21:02:17 +0000 Subject: [PATCH] Initial entry of Doctrine_Log(ported from Zend_log) --- lib/Doctrine/Log.php | 210 +++++++++++++++++++++++ lib/Doctrine/Log/Exception.php | 34 ++++ lib/Doctrine/Log/Filter/Interface.php | 41 +++++ lib/Doctrine/Log/Filter/Message.php | 64 +++++++ lib/Doctrine/Log/Filter/Priority.php | 72 ++++++++ lib/Doctrine/Log/Filter/Suppress.php | 63 +++++++ lib/Doctrine/Log/Formatter/Interface.php | 41 +++++ lib/Doctrine/Log/Formatter/Simple.php | 72 ++++++++ lib/Doctrine/Log/Formatter/Xml.php | 84 +++++++++ lib/Doctrine/Log/Writer/Abstract.php | 103 +++++++++++ lib/Doctrine/Log/Writer/Db.php | 107 ++++++++++++ lib/Doctrine/Log/Writer/Mock.php | 64 +++++++ lib/Doctrine/Log/Writer/Null.php | 43 +++++ lib/Doctrine/Log/Writer/Stream.php | 94 ++++++++++ 14 files changed, 1092 insertions(+) create mode 100755 lib/Doctrine/Log.php create mode 100755 lib/Doctrine/Log/Exception.php create mode 100644 lib/Doctrine/Log/Filter/Interface.php create mode 100644 lib/Doctrine/Log/Filter/Message.php create mode 100644 lib/Doctrine/Log/Filter/Priority.php create mode 100644 lib/Doctrine/Log/Filter/Suppress.php create mode 100644 lib/Doctrine/Log/Formatter/Interface.php create mode 100644 lib/Doctrine/Log/Formatter/Simple.php create mode 100644 lib/Doctrine/Log/Formatter/Xml.php create mode 100644 lib/Doctrine/Log/Writer/Abstract.php create mode 100644 lib/Doctrine/Log/Writer/Db.php create mode 100644 lib/Doctrine/Log/Writer/Mock.php create mode 100644 lib/Doctrine/Log/Writer/Null.php create mode 100644 lib/Doctrine/Log/Writer/Stream.php diff --git a/lib/Doctrine/Log.php b/lib/Doctrine/Log.php new file mode 100755 index 000000000..211ee6753 --- /dev/null +++ b/lib/Doctrine/Log.php @@ -0,0 +1,210 @@ +. + */ + +/** + * @package Doctrine + * @subpackage Log + * @author Jonathan H. Wage + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision: 3155 $ + */ +class Doctrine_Log +{ + const EMERG = 0; // Emergency: system is unusable + const ALERT = 1; // Alert: action must be taken immediately + const CRIT = 2; // Critical: critical conditions + const ERR = 3; // Error: error conditions + const WARN = 4; // Warning: warning conditions + const NOTICE = 5; // Notice: normal but significant condition + const INFO = 6; // Informational: informational messages + const DEBUG = 7; // Debug: debug messages + + /** + * @var array of priorities where the keys are the + * priority numbers and the values are the priority names + */ + protected $_priorities = array(); + + /** + * @var array of Doctrine_Log_Writer_Abstract + */ + protected $_writers = array(); + + /** + * @var array of Doctrine_Log_Filter_Interface + */ + protected $_filters = array(); + + /** + * @var array of extra log event + */ + protected $_extras = array(); + + /** + * Class constructor. Create a new logger + * + * @param Doctrine_Log_Writer_Abstract|null $writer default writer + */ + public function __construct($writer = null) + { + $r = new ReflectionClass($this); + $this->_priorities = array_flip($r->getConstants()); + + if ($writer !== null) { + $this->addWriter($writer); + } + } + + /** + * Class destructor. Shutdown log writers + * + * @return void + */ + public function __destruct() + { + foreach($this->_writers as $writer) { + $writer->shutdown(); + } + } + + /** + * Undefined method handler allows a shortcut: + * $log->priorityName('message') + * instead of + * $log->log('message', Doctrine_Log::PRIORITY_NAME) + * + * @param string $method priority name + * @param string $params message to log + * @return void + * @throws Doctrine_Log_Exception + */ + public function __call($method, $params) + { + $priority = strtoupper($method); + if (($priority = array_search($priority, $this->_priorities)) !== false) { + $this->log(array_shift($params), $priority); + } else { + throw new Doctrine_Log_Exception('Bad log priority'); + } + } + + /** + * Log a message at a priority + * + * @param string $message Message to log + * @param integer $priority Priority of message + * @return void + * @throws Doctrine_Log_Exception + */ + public function log($message, $priority) + { + // sanity checks + if (empty($this->_writers)) { + throw new Doctrine_Log_Exception('No writers were added'); + } + + if (! isset($this->_priorities[$priority])) { + throw new Doctrine_Log_Exception('Bad log priority'); + } + + // pack into event required by filters and writers + $event = array_merge(array('timestamp' => date('c'), + 'message' => $message, + 'priority' => $priority, + 'priorityName' => $this->_priorities[$priority]), + $this->_extras); + + // abort if rejected by the global filters + foreach ($this->_filters as $filter) { + if (! $filter->accept($event)) { + return; + } + } + + // send to each writer + foreach ($this->_writers as $writer) { + $writer->write($event); + } + } + + /** + * Add a custom priority + * + * @param string $name Name of priority + * @param integer $priority Numeric priority + * @throws Doctrine_Log_InvalidArgumentException + */ + public function addPriority($name, $priority) + { + // Priority names must be uppercase for predictability. + $name = strtoupper($name); + + if (isset($this->_priorities[$priority]) + || array_search($name, $this->_priorities)) { + throw new Doctrine_Log_Exception('Existing priorities cannot be overwritten'); + } + + $this->_priorities[$priority] = $name; + } + + /** + * Add a filter that will be applied before all log writers. + * Before a message will be received by any of the writers, it + * must be accepted by all filters added with this method. + * + * @param Doctrine_Log_Filter_Interface $filter + * @return void + */ + public function addFilter($filter) + { + if (is_integer($filter)) { + $filter = new Doctrine_Log_Filter_Priority($filter); + } + + $this->_filters[] = $filter; + } + + /** + * Add a writer. A writer is responsible for taking a log + * message and writing it out to storage. + * + * @param Doctrine_Log_Writer_Abstract $writer + * @return void + */ + public function addWriter($writer) + { + $this->_writers[] = $writer; + } + + /** + * Set an extra item to pass to the log writers. + * + * @param $name Name of the field + * @param $value Value of the field + * @return void + */ + public function setEventItem($name, $value) { + $this->_extras = array_merge($this->_extras, array($name => $value)); + } + +} diff --git a/lib/Doctrine/Log/Exception.php b/lib/Doctrine/Log/Exception.php new file mode 100755 index 000000000..e729f4158 --- /dev/null +++ b/lib/Doctrine/Log/Exception.php @@ -0,0 +1,34 @@ +. + */ + +/** + * @category Doctrine + * @package Log + * @author Jonathan H. Wage + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision: 3155 $ + */ +class Doctrine_Log_Exception extends Doctrine_Exception +{ + +} \ No newline at end of file diff --git a/lib/Doctrine/Log/Filter/Interface.php b/lib/Doctrine/Log/Filter/Interface.php new file mode 100644 index 000000000..965820388 --- /dev/null +++ b/lib/Doctrine/Log/Filter/Interface.php @@ -0,0 +1,41 @@ +. + */ + +/** + * @package Doctrine + * @subpackage Log + * @author Konsta Vesterinen + * @author Jonathan H. Wage + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision: 3155 $ + */ +interface Doctrine_Log_Filter_Interface +{ + /** + * Returns TRUE to accept the message, FALSE to block it. + * + * @param array $event event data + * @return boolean accepted? + */ + public function accept($event); +} \ No newline at end of file diff --git a/lib/Doctrine/Log/Filter/Message.php b/lib/Doctrine/Log/Filter/Message.php new file mode 100644 index 000000000..ddf654dc7 --- /dev/null +++ b/lib/Doctrine/Log/Filter/Message.php @@ -0,0 +1,64 @@ +. + */ + +/** + * @package Doctrine + * @subpackage Log + * @author Konsta Vesterinen + * @author Jonathan H. Wage + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision: 3155 $ + */ +class Doctrine_Log_Filter_Message implements Doctrine_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 Doctrine_Log_Exception + */ + public function __construct($regexp) + { + if (@preg_match($regexp, '') === false) { + throw new Doctrine_Log_Exception("Invalid regular expression '$regexp'"); + } + $this->_regexp = $regexp; + } + + /** + * Returns TRUE to accept the message, FALSE to block it. + * + * @param array $event event data + * @return boolean accepted? + */ + public function accept($event) + { + return preg_match($this->_regexp, $event['message']) > 0; + } + +} \ No newline at end of file diff --git a/lib/Doctrine/Log/Filter/Priority.php b/lib/Doctrine/Log/Filter/Priority.php new file mode 100644 index 000000000..3e0f47f82 --- /dev/null +++ b/lib/Doctrine/Log/Filter/Priority.php @@ -0,0 +1,72 @@ +. + */ + +/** + * @package Doctrine + * @subpackage Log + * @author Konsta Vesterinen + * @author Jonathan H. Wage + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision: 3155 $ + */ +class Doctrine_Log_Filter_Priority implements Doctrine_Log_Filter_Interface +{ + /** + * @var integer + */ + protected $_priority; + + /** + * @var string + */ + protected $_operator; + + /** + * Filter logging by $priority. By default, it will accept any log + * event whose priority value is less than or equal to $priority. + * + * @param integer $priority Priority + * @param string $operator Comparison operator + * @throws Doctrine_Log_Exception + */ + public function __construct($priority, $operator = '<=') + { + if (! is_integer($priority)) { + throw new Doctrine_Log_Exception('Priority must be an integer'); + } + + $this->_priority = $priority; + $this->_operator = $operator; + } + + /** + * Returns TRUE to accept the message, FALSE to block it. + * + * @param array $event event data + * @return boolean accepted? + */ + public function accept($event) + { + return version_compare($event['priority'], $this->_priority, $this->_operator); + } +} \ No newline at end of file diff --git a/lib/Doctrine/Log/Filter/Suppress.php b/lib/Doctrine/Log/Filter/Suppress.php new file mode 100644 index 000000000..3e1961204 --- /dev/null +++ b/lib/Doctrine/Log/Filter/Suppress.php @@ -0,0 +1,63 @@ +. + */ + +/** + * @package Doctrine + * @subpackage Log + * @author Konsta Vesterinen + * @author Jonathan H. Wage + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision: 3155 $ + */ +class Doctrine_Log_Filter_Suppress implements Doctrine_Log_Filter_Interface +{ + /** + * @var boolean + */ + protected $_accept = true; + + /** + * This is a simple boolean filter. + * + * Call suppress(true) to suppress all log events. + * Call suppress(false) to accept all log events. + * + * @param boolean $suppress Should all log events be suppressed? + * @return void + */ + public function suppress($suppress) + { + $this->_accept = (! $suppress); + } + + /** + * Returns TRUE to accept the message, FALSE to block it. + * + * @param array $event event data + * @return boolean accepted? + */ + public function accept($event) + { + return $this->_accept; + } +} \ No newline at end of file diff --git a/lib/Doctrine/Log/Formatter/Interface.php b/lib/Doctrine/Log/Formatter/Interface.php new file mode 100644 index 000000000..b17a1745d --- /dev/null +++ b/lib/Doctrine/Log/Formatter/Interface.php @@ -0,0 +1,41 @@ +. + */ + +/** + * @package Doctrine + * @subpackage Log + * @author Konsta Vesterinen + * @author Jonathan H. Wage + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision: 3155 $ + */ +interface Doctrine_Log_Formatter_Interface +{ + /** + * Formats data into a single line to be written by the writer. + * + * @param array $event event data + * @return string formatted line to write to the log + */ + public function format($event); +} \ No newline at end of file diff --git a/lib/Doctrine/Log/Formatter/Simple.php b/lib/Doctrine/Log/Formatter/Simple.php new file mode 100644 index 000000000..d14d9b770 --- /dev/null +++ b/lib/Doctrine/Log/Formatter/Simple.php @@ -0,0 +1,72 @@ +. + */ + +/** + * @package Doctrine + * @subpackage Log + * @author Konsta Vesterinen + * @author Jonathan H. Wage + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision: 3155 $ + */ +class Doctrine_Log_Formatter_Simple implements Doctrine_Log_Formatter_Interface +{ + /** + * @var string + */ + protected $_format; + + /** + * Class constructor + * + * @param null|string $format Format specifier for log messages + * @throws Doctrine_Log_Exception + */ + public function __construct($format = null) + { + if ($format === null) { + $format = '%timestamp% %priorityName% (%priority%): %message%' . PHP_EOL; + } + + if (! is_string($format)) { + throw new Doctrine_Log_Exception('Format must be a string'); + } + + $this->_format = $format; + } + + /** + * Formats data into a single line to be written by the writer. + * + * @param array $event event data + * @return string formatted line to write to the log + */ + public function format($event) + { + $output = $this->_format; + foreach ($event as $name => $value) { + $output = str_replace("%$name%", $value, $output); + } + return $output; + } +} \ No newline at end of file diff --git a/lib/Doctrine/Log/Formatter/Xml.php b/lib/Doctrine/Log/Formatter/Xml.php new file mode 100644 index 000000000..69f6a1db2 --- /dev/null +++ b/lib/Doctrine/Log/Formatter/Xml.php @@ -0,0 +1,84 @@ +. + */ + +/** + * @package Doctrine + * @subpackage Log + * @author Konsta Vesterinen + * @author Jonathan H. Wage + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision: 3155 $ + */ +class Doctrine_Log_Formatter_Xml implements Doctrine_Log_Formatter_Interface +{ + /** + * @var Relates XML elements to log data field keys. + */ + protected $_rootElement; + + /** + * @var Relates XML elements to log data field keys. + */ + protected $_elementMap; + + /** + * Class constructor + * + * @param array $elementMap + */ + public function __construct($rootElement = 'logEntry', $elementMap = null) + { + $this->_rootElement = $rootElement; + $this->_elementMap = $elementMap; + } + + /** + * Formats data into a single line to be written by the writer. + * + * @param array $event event data + * @return string formatted line to write to the log + */ + public function format($event) + { + if ($this->_elementMap === null) { + $dataToInsert = $event; + } else { + $dataToInsert = array(); + foreach ($this->_elementMap as $elementName => $fieldKey) { + $dataToInsert[$elementName] = $event[$fieldKey]; + } + } + + $dom = new DOMDocument(); + $elt = $dom->appendChild(new DOMElement($this->_rootElement)); + + foreach ($dataToInsert as $key => $value) { + $elt->appendChild(new DOMElement($key, $value)); + } + + $xml = $dom->saveXML(); + $xml = preg_replace('/<\?xml version="1.0"( encoding="[^\"]*")?\?>\n/u', '', $xml); + + return $xml . PHP_EOL; + } +} \ No newline at end of file diff --git a/lib/Doctrine/Log/Writer/Abstract.php b/lib/Doctrine/Log/Writer/Abstract.php new file mode 100644 index 000000000..39322f22f --- /dev/null +++ b/lib/Doctrine/Log/Writer/Abstract.php @@ -0,0 +1,103 @@ +. + */ + +/** + * @package Doctrine + * @subpackage Log + * @author Konsta Vesterinen + * @author Jonathan H. Wage + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision: 3155 $ + */ +abstract class Doctrine_Log_Writer_Abstract +{ + /** + * @var array of Doctrine_Log_Filter_Interface + */ + protected $_filters = array(); + + /** + * Formats the log message before writing. + * @var Doctrine_Log_Formatter_Interface + */ + protected $_formatter; + + /** + * Add a filter specific to this writer. + * + * @param Doctrine_Log_Filter_Interface $filter + * @return void + */ + public function addFilter($filter) + { + if (is_integer($filter)) { + $filter = new Doctrine_Log_Filter_Priority($filter); + } + + $this->_filters[] = $filter; + } + + /** + * Log a message to this writer. + * + * @param array $event log data event + * @return void + */ + public function write($event) + { + foreach ($this->_filters as $filter) { + if (! $filter->accept($event)) { + return; + } + } + + // exception occurs on error + $this->_write($event); + } + + /** + * Set a new formatter for this writer + * + * @param Doctrine_Log_Formatter_Interface $formatter + * @return void + */ + public function setFormatter($formatter) { + $this->_formatter = $formatter; + } + + /** + * Perform shutdown activites such as closing open resources + * + * @return void + */ + public function shutdown() + {} + + /** + * Write a message to the log. + * + * @param array $event log data event + * @return void + */ + abstract protected function _write($event); +} \ No newline at end of file diff --git a/lib/Doctrine/Log/Writer/Db.php b/lib/Doctrine/Log/Writer/Db.php new file mode 100644 index 000000000..4a7fe5edd --- /dev/null +++ b/lib/Doctrine/Log/Writer/Db.php @@ -0,0 +1,107 @@ +. + */ + +/** + * @package Doctrine + * @subpackage Log + * @author Konsta Vesterinen + * @author Jonathan H. Wage + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision: 3155 $ + */ +class Doctrine_Log_Writer_Db extends Doctrine_Log_Writer_Abstract +{ + /** + * Doctrine_Table instance + * + * @var string + */ + private $_table; + + /** + * Relates database columns names to log data field keys. + * + * @var null|array + */ + private $_columnMap; + + /** + * Class constructor + * + * @param Doctrine_Db_Adapter $db Database adapter instance + * @param string $table Log table in database + * @param array $columnMap + */ + public function __construct($table, $columnMap = null) + { + if (!$table instanceof Doctrine_Table) { + $table = Doctrine::getTable($table); + } + + $this->_table = $table; + $this->_columnMap = $columnMap; + } + + /** + * Formatting is not possible on this writer + */ + public function setFormatter($formatter) + { + throw new Doctrine_Log_Exception(get_class() . ' does not support formatting'); + } + + /** + * Remove reference to database adapter + * + * @return void + */ + public function shutdown() + { + $this->_table = null; + } + + /** + * Write a message to the log. + * + * @param array $event event data + * @return void + */ + protected function _write($event) + { + if ($this->_table === null) { + throw new Doctrine_Log_Exception('Database adapter instance has been removed by shutdown'); + } + + if ($this->_columnMap === null) { + $dataToInsert = $event; + } else { + $dataToInsert = array(); + foreach ($this->_columnMap as $columnName => $fieldKey) { + $dataToInsert[$columnName] = $event[$fieldKey]; + } + } + + $record = $this->_table->create($dataToInsert); + $record->save(); + } +} \ No newline at end of file diff --git a/lib/Doctrine/Log/Writer/Mock.php b/lib/Doctrine/Log/Writer/Mock.php new file mode 100644 index 000000000..ecac04611 --- /dev/null +++ b/lib/Doctrine/Log/Writer/Mock.php @@ -0,0 +1,64 @@ +. + */ + +/** + * @package Doctrine + * @subpackage Log + * @author Konsta Vesterinen + * @author Jonathan H. Wage + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision: 3155 $ + */ +class Doctrine_Log_Writer_Mock extends Doctrine_Log_Writer_Abstract +{ + /** + * array of log events + */ + public $events = array(); + + /** + * shutdown called? + */ + public $shutdown = false; + + /** + * Write a message to the log. + * + * @param array $event event data + * @return void + */ + public function _write($event) + { + $this->events[] = $event; + } + + /** + * Record shutdown + * + * @return void + */ + public function shutdown() + { + $this->shutdown = true; + } +} \ No newline at end of file diff --git a/lib/Doctrine/Log/Writer/Null.php b/lib/Doctrine/Log/Writer/Null.php new file mode 100644 index 000000000..bcd91cab0 --- /dev/null +++ b/lib/Doctrine/Log/Writer/Null.php @@ -0,0 +1,43 @@ +. + */ + +/** + * @package Doctrine + * @subpackage Log + * @author Konsta Vesterinen + * @author Jonathan H. Wage + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision: 3155 $ + */ +class Doctrine_Log_Writer_Null extends Doctrine_Log_Writer_Abstract +{ + /** + * Write a message to the log. + * + * @param array $event event data + * @return void + */ + protected function _write($event) + { + } +} \ No newline at end of file diff --git a/lib/Doctrine/Log/Writer/Stream.php b/lib/Doctrine/Log/Writer/Stream.php new file mode 100644 index 000000000..662e1ac59 --- /dev/null +++ b/lib/Doctrine/Log/Writer/Stream.php @@ -0,0 +1,94 @@ +. + */ + +/** + * @package Doctrine + * @subpackage Log + * @author Konsta Vesterinen + * @author Jonathan H. Wage + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision: 3155 $ + */ +class Doctrine_Log_Writer_Stream extends Doctrine_Log_Writer_Abstract +{ + /** + * Holds the PHP stream to log to. + * @var null|stream + */ + protected $_stream = null; + + /** + * Class Constructor + * + * @param streamOrUrl Stream or URL to open as a stream + * @param mode Mode, only applicable if a URL is given + */ + public function __construct($streamOrUrl, $mode = 'a') + { + if (is_resource($streamOrUrl)) { + if (get_resource_type($streamOrUrl) != 'stream') { + throw new Doctrine_Log_Exception('Resource is not a stream'); + } + + if ($mode != 'a') { + throw new Doctrine_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 Doctrine_Log_Exception($msg); + } + } + + $this->_formatter = new Doctrine_Log_Formatter_Simple(); + } + + /** + * Close the stream resource. + * + * @return void + */ + public function shutdown() + { + if (is_resource($this->_stream)) { + fclose($this->_stream); + } + } + + /** + * Write a message to the log. + * + * @param array $event event data + * @return void + */ + protected function _write($event) + { + $line = $this->_formatter->format($event); + + if (false === @fwrite($this->_stream, $line)) { + throw new Doctrine_Log_Exception("Unable to write to stream"); + } + } +} \ No newline at end of file