File indexing completed on 2024-12-22 05:37:17
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Log 0017 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0018 * @license http://framework.zend.com/license/new-bsd New BSD License 0019 * @version $Id$ 0020 */ 0021 0022 /** 0023 * @category Zend 0024 * @package Zend_Log 0025 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0026 * @license http://framework.zend.com/license/new-bsd New BSD License 0027 * @version $Id$ 0028 * 0029 * Convenience methods for log [@see Zend_Log::__call()]: 0030 * 0031 * @method emerg(string $message, $extras = null) 0032 * @method alert(string $message, $extras = null) 0033 * @method crit(string $message, $extras = null) 0034 * @method err(string $message, $extras = null) 0035 * @method warn(string $message, $extras = null) 0036 * @method notice(string $message, $extras = null) 0037 * @method info(string $message, $extras = null) 0038 * @method debug(string $message, $extras = null) 0039 */ 0040 class Zend_Log 0041 { 0042 const EMERG = 0; // Emergency: system is unusable 0043 const ALERT = 1; // Alert: action must be taken immediately 0044 const CRIT = 2; // Critical: critical conditions 0045 const ERR = 3; // Error: error conditions 0046 const WARN = 4; // Warning: warning conditions 0047 const NOTICE = 5; // Notice: normal but significant condition 0048 const INFO = 6; // Informational: informational messages 0049 const DEBUG = 7; // Debug: debug messages 0050 0051 /** 0052 * @var array of priorities where the keys are the 0053 * priority numbers and the values are the priority names 0054 */ 0055 protected $_priorities = array(); 0056 0057 /** 0058 * @var array of Zend_Log_Writer_Abstract 0059 */ 0060 protected $_writers = array(); 0061 0062 /** 0063 * @var array of Zend_Log_Filter_Interface 0064 */ 0065 protected $_filters = array(); 0066 0067 /** 0068 * @var array of extra log event 0069 */ 0070 protected $_extras = array(); 0071 0072 /** 0073 * 0074 * @var string 0075 */ 0076 protected $_defaultWriterNamespace = 'Zend_Log_Writer'; 0077 0078 /** 0079 * 0080 * @var string 0081 */ 0082 protected $_defaultFilterNamespace = 'Zend_Log_Filter'; 0083 0084 /** 0085 * 0086 * @var string 0087 */ 0088 protected $_defaultFormatterNamespace = 'Zend_Log_Formatter'; 0089 0090 /** 0091 * 0092 * @var callback 0093 */ 0094 protected $_origErrorHandler = null; 0095 0096 /** 0097 * 0098 * @var boolean 0099 */ 0100 protected $_registeredErrorHandler = false; 0101 0102 /** 0103 * 0104 * @var array|boolean 0105 */ 0106 protected $_errorHandlerMap = false; 0107 0108 /** 0109 * 0110 * @var string 0111 */ 0112 protected $_timestampFormat = 'c'; 0113 0114 /** 0115 * Class constructor. Create a new logger 0116 * 0117 * @param Zend_Log_Writer_Abstract|null $writer default writer 0118 */ 0119 public function __construct(Zend_Log_Writer_Abstract $writer = null) 0120 { 0121 $r = new ReflectionClass($this); 0122 $this->_priorities = array_flip($r->getConstants()); 0123 0124 if ($writer !== null) { 0125 $this->addWriter($writer); 0126 } 0127 } 0128 0129 /** 0130 * Factory to construct the logger and one or more writers 0131 * based on the configuration array 0132 * 0133 * @param array|Zend_Config Array or instance of Zend_Config 0134 * @return Zend_Log 0135 * @throws Zend_Log_Exception 0136 */ 0137 static public function factory($config = array()) 0138 { 0139 if ($config instanceof Zend_Config) { 0140 $config = $config->toArray(); 0141 } 0142 0143 if (!is_array($config) || empty($config)) { 0144 /** @see Zend_Log_Exception */ 0145 // require_once 'Zend/Log/Exception.php'; 0146 throw new Zend_Log_Exception('Configuration must be an array or instance of Zend_Config'); 0147 } 0148 0149 if (array_key_exists('className', $config)) { 0150 $class = $config['className']; 0151 unset($config['className']); 0152 } else { 0153 $class = __CLASS__; 0154 } 0155 0156 $log = new $class; 0157 0158 if (!$log instanceof Zend_Log) { 0159 /** @see Zend_Log_Exception */ 0160 // require_once 'Zend/Log/Exception.php'; 0161 throw new Zend_Log_Exception('Passed className does not belong to a descendant of Zend_Log'); 0162 } 0163 0164 if (array_key_exists('timestampFormat', $config)) { 0165 if (null != $config['timestampFormat'] && '' != $config['timestampFormat']) { 0166 $log->setTimestampFormat($config['timestampFormat']); 0167 } 0168 unset($config['timestampFormat']); 0169 } 0170 0171 if (!is_array(current($config))) { 0172 $log->addWriter(current($config)); 0173 } else { 0174 foreach($config as $writer) { 0175 $log->addWriter($writer); 0176 } 0177 } 0178 0179 return $log; 0180 } 0181 0182 0183 /** 0184 * Construct a writer object based on a configuration array 0185 * 0186 * @param array $config config array with writer spec 0187 * @return Zend_Log_Writer_Abstract 0188 * @throws Zend_Log_Exception 0189 */ 0190 protected function _constructWriterFromConfig($config) 0191 { 0192 $writer = $this->_constructFromConfig('writer', $config, $this->_defaultWriterNamespace); 0193 0194 if (!$writer instanceof Zend_Log_Writer_Abstract) { 0195 $writerName = is_object($writer) 0196 ? get_class($writer) 0197 : 'The specified writer'; 0198 /** @see Zend_Log_Exception */ 0199 // require_once 'Zend/Log/Exception.php'; 0200 throw new Zend_Log_Exception("{$writerName} does not extend Zend_Log_Writer_Abstract!"); 0201 } 0202 0203 if (isset($config['filterName'])) { 0204 $filter = $this->_constructFilterFromConfig($config); 0205 $writer->addFilter($filter); 0206 } 0207 0208 if (isset($config['formatterName'])) { 0209 $formatter = $this->_constructFormatterFromConfig($config); 0210 $writer->setFormatter($formatter); 0211 } 0212 0213 return $writer; 0214 } 0215 0216 /** 0217 * Construct filter object from configuration array or Zend_Config object 0218 * 0219 * @param array|Zend_Config $config Zend_Config or Array 0220 * @return Zend_Log_Filter_Interface 0221 * @throws Zend_Log_Exception 0222 */ 0223 protected function _constructFilterFromConfig($config) 0224 { 0225 $filter = $this->_constructFromConfig('filter', $config, $this->_defaultFilterNamespace); 0226 0227 if (!$filter instanceof Zend_Log_Filter_Interface) { 0228 $filterName = is_object($filter) 0229 ? get_class($filter) 0230 : 'The specified filter'; 0231 /** @see Zend_Log_Exception */ 0232 // require_once 'Zend/Log/Exception.php'; 0233 throw new Zend_Log_Exception("{$filterName} does not implement Zend_Log_Filter_Interface"); 0234 } 0235 0236 return $filter; 0237 } 0238 0239 /** 0240 * Construct formatter object from configuration array or Zend_Config object 0241 * 0242 * @param array|Zend_Config $config Zend_Config or Array 0243 * @return Zend_Log_Formatter_Interface 0244 * @throws Zend_Log_Exception 0245 */ 0246 protected function _constructFormatterFromConfig($config) 0247 { 0248 $formatter = $this->_constructFromConfig('formatter', $config, $this->_defaultFormatterNamespace); 0249 0250 if (!$formatter instanceof Zend_Log_Formatter_Interface) { 0251 $formatterName = is_object($formatter) 0252 ? get_class($formatter) 0253 : 'The specified formatter'; 0254 /** @see Zend_Log_Exception */ 0255 // require_once 'Zend/Log/Exception.php'; 0256 throw new Zend_Log_Exception($formatterName . ' does not implement Zend_Log_Formatter_Interface'); 0257 } 0258 0259 return $formatter; 0260 } 0261 0262 /** 0263 * Construct a filter or writer from config 0264 * 0265 * @param string $type 'writer' of 'filter' 0266 * @param mixed $config Zend_Config or Array 0267 * @param string $namespace 0268 * @return object 0269 * @throws Zend_Log_Exception 0270 */ 0271 protected function _constructFromConfig($type, $config, $namespace) 0272 { 0273 if ($config instanceof Zend_Config) { 0274 $config = $config->toArray(); 0275 } 0276 0277 if (!is_array($config) || empty($config)) { 0278 // require_once 'Zend/Log/Exception.php'; 0279 throw new Zend_Log_Exception( 0280 'Configuration must be an array or instance of Zend_Config' 0281 ); 0282 } 0283 0284 $params = isset($config[ $type .'Params' ]) ? $config[ $type .'Params' ] : array(); 0285 $className = $this->getClassName($config, $type, $namespace); 0286 if (!class_exists($className)) { 0287 // require_once 'Zend/Loader.php'; 0288 Zend_Loader::loadClass($className); 0289 } 0290 0291 $reflection = new ReflectionClass($className); 0292 if (!$reflection->implementsInterface('Zend_Log_FactoryInterface')) { 0293 // require_once 'Zend/Log/Exception.php'; 0294 throw new Zend_Log_Exception( 0295 $className . ' does not implement Zend_Log_FactoryInterface and can not be constructed from config.' 0296 ); 0297 } 0298 0299 return call_user_func(array($className, 'factory'), $params); 0300 } 0301 0302 /** 0303 * Get the writer or filter full classname 0304 * 0305 * @param array $config 0306 * @param string $type filter|writer 0307 * @param string $defaultNamespace 0308 * @return string full classname 0309 * @throws Zend_Log_Exception 0310 */ 0311 protected function getClassName($config, $type, $defaultNamespace) 0312 { 0313 if (!isset($config[$type . 'Name'])) { 0314 // require_once 'Zend/Log/Exception.php'; 0315 throw new Zend_Log_Exception("Specify {$type}Name in the configuration array"); 0316 } 0317 0318 $className = $config[$type . 'Name']; 0319 $namespace = $defaultNamespace; 0320 0321 if (isset($config[$type . 'Namespace'])) { 0322 $namespace = $config[$type . 'Namespace']; 0323 } 0324 0325 // PHP >= 5.3.0 namespace given? 0326 if (substr($namespace, -1) == '\\') { 0327 return $namespace . $className; 0328 } 0329 0330 // empty namespace given? 0331 if (strlen($namespace) === 0) { 0332 return $className; 0333 } 0334 0335 return $namespace . '_' . $className; 0336 } 0337 0338 /** 0339 * Packs message and priority into Event array 0340 * 0341 * @param string $message Message to log 0342 * @param integer $priority Priority of message 0343 * @return array Event array 0344 */ 0345 protected function _packEvent($message, $priority) 0346 { 0347 return array_merge(array( 0348 'timestamp' => date($this->_timestampFormat), 0349 'message' => $message, 0350 'priority' => $priority, 0351 'priorityName' => $this->_priorities[$priority] 0352 ), 0353 $this->_extras 0354 ); 0355 } 0356 0357 /** 0358 * Class destructor. Shutdown log writers 0359 * 0360 * @return void 0361 */ 0362 public function __destruct() 0363 { 0364 /** @var Zend_Log_Writer_Abstract $writer */ 0365 foreach($this->_writers as $writer) { 0366 $writer->shutdown(); 0367 } 0368 } 0369 0370 /** 0371 * Undefined method handler allows a shortcut: 0372 * $log->priorityName('message') 0373 * instead of 0374 * $log->log('message', Zend_Log::PRIORITY_NAME) 0375 * 0376 * @param string $method priority name 0377 * @param string $params message to log 0378 * @return void 0379 * @throws Zend_Log_Exception 0380 */ 0381 public function __call($method, $params) 0382 { 0383 $priority = strtoupper($method); 0384 if (($priority = array_search($priority, $this->_priorities)) !== false) { 0385 switch (count($params)) { 0386 case 0: 0387 /** @see Zend_Log_Exception */ 0388 // require_once 'Zend/Log/Exception.php'; 0389 throw new Zend_Log_Exception('Missing log message'); 0390 case 1: 0391 $message = array_shift($params); 0392 $extras = null; 0393 break; 0394 default: 0395 $message = array_shift($params); 0396 $extras = array_shift($params); 0397 break; 0398 } 0399 $this->log($message, $priority, $extras); 0400 } else { 0401 /** @see Zend_Log_Exception */ 0402 // require_once 'Zend/Log/Exception.php'; 0403 throw new Zend_Log_Exception('Bad log priority'); 0404 } 0405 } 0406 0407 /** 0408 * Log a message at a priority 0409 * 0410 * @param string $message Message to log 0411 * @param integer $priority Priority of message 0412 * @param mixed $extras Extra information to log in event 0413 * @return void 0414 * @throws Zend_Log_Exception 0415 */ 0416 public function log($message, $priority, $extras = null) 0417 { 0418 // sanity checks 0419 if (empty($this->_writers)) { 0420 /** @see Zend_Log_Exception */ 0421 // require_once 'Zend/Log/Exception.php'; 0422 throw new Zend_Log_Exception('No writers were added'); 0423 } 0424 0425 if (! isset($this->_priorities[$priority])) { 0426 /** @see Zend_Log_Exception */ 0427 // require_once 'Zend/Log/Exception.php'; 0428 throw new Zend_Log_Exception('Bad log priority'); 0429 } 0430 0431 // pack into event required by filters and writers 0432 $event = $this->_packEvent($message, $priority); 0433 0434 // Check to see if any extra information was passed 0435 if (!empty($extras)) { 0436 $info = array(); 0437 if (is_array($extras)) { 0438 foreach ($extras as $key => $value) { 0439 if (is_string($key)) { 0440 $event[$key] = $value; 0441 } else { 0442 $info[] = $value; 0443 } 0444 } 0445 } else { 0446 $info = $extras; 0447 } 0448 if (!empty($info)) { 0449 $event['info'] = $info; 0450 } 0451 } 0452 0453 // abort if rejected by the global filters 0454 /** @var Zend_Log_Filter_Interface $filter */ 0455 foreach ($this->_filters as $filter) { 0456 if (! $filter->accept($event)) { 0457 return; 0458 } 0459 } 0460 0461 // send to each writer 0462 /** @var Zend_Log_Writer_Abstract $writer */ 0463 foreach ($this->_writers as $writer) { 0464 $writer->write($event); 0465 } 0466 } 0467 0468 /** 0469 * Add a custom priority 0470 * 0471 * @param string $name Name of priority 0472 * @param integer $priority Numeric priority 0473 * @return $this 0474 * @throws Zend_Log_Exception 0475 */ 0476 public function addPriority($name, $priority) 0477 { 0478 // Priority names must be uppercase for predictability. 0479 $name = strtoupper($name); 0480 0481 if (isset($this->_priorities[$priority]) 0482 || false !== array_search($name, $this->_priorities)) { 0483 /** @see Zend_Log_Exception */ 0484 // require_once 'Zend/Log/Exception.php'; 0485 throw new Zend_Log_Exception('Existing priorities cannot be overwritten'); 0486 } 0487 0488 $this->_priorities[$priority] = $name; 0489 return $this; 0490 } 0491 0492 /** 0493 * Add a filter that will be applied before all log writers. 0494 * Before a message will be received by any of the writers, it 0495 * must be accepted by all filters added with this method. 0496 * 0497 * @param int|Zend_Config|array|Zend_Log_Filter_Interface $filter 0498 * @return $this 0499 * @throws Zend_Log_Exception 0500 */ 0501 public function addFilter($filter) 0502 { 0503 if (is_int($filter)) { 0504 /** @see Zend_Log_Filter_Priority */ 0505 // require_once 'Zend/Log/Filter/Priority.php'; 0506 $filter = new Zend_Log_Filter_Priority($filter); 0507 0508 } elseif ($filter instanceof Zend_Config || is_array($filter)) { 0509 $filter = $this->_constructFilterFromConfig($filter); 0510 0511 } elseif(! $filter instanceof Zend_Log_Filter_Interface) { 0512 /** @see Zend_Log_Exception */ 0513 // require_once 'Zend/Log/Exception.php'; 0514 throw new Zend_Log_Exception('Invalid filter provided'); 0515 } 0516 0517 $this->_filters[] = $filter; 0518 return $this; 0519 } 0520 0521 /** 0522 * Add a writer. A writer is responsible for taking a log 0523 * message and writing it out to storage. 0524 * 0525 * @param mixed $writer Zend_Log_Writer_Abstract or Config array 0526 * @return Zend_Log 0527 * @throws Zend_Log_Exception 0528 */ 0529 public function addWriter($writer) 0530 { 0531 if (is_array($writer) || $writer instanceof Zend_Config) { 0532 $writer = $this->_constructWriterFromConfig($writer); 0533 } 0534 0535 if (!$writer instanceof Zend_Log_Writer_Abstract) { 0536 /** @see Zend_Log_Exception */ 0537 // require_once 'Zend/Log/Exception.php'; 0538 throw new Zend_Log_Exception( 0539 'Writer must be an instance of Zend_Log_Writer_Abstract' 0540 . ' or you should pass a configuration array' 0541 ); 0542 } 0543 0544 $this->_writers[] = $writer; 0545 return $this; 0546 } 0547 0548 /** 0549 * Set an extra item to pass to the log writers. 0550 * 0551 * @param string $name Name of the field 0552 * @param string $value Value of the field 0553 * @return Zend_Log 0554 */ 0555 public function setEventItem($name, $value) 0556 { 0557 $this->_extras = array_merge($this->_extras, array($name => $value)); 0558 return $this; 0559 } 0560 0561 /** 0562 * Register Logging system as an error handler to log php errors 0563 * Note: it still calls the original error handler if set_error_handler is able to return it. 0564 * 0565 * Errors will be mapped as: 0566 * E_NOTICE, E_USER_NOTICE => NOTICE 0567 * E_WARNING, E_CORE_WARNING, E_USER_WARNING => WARN 0568 * E_ERROR, E_USER_ERROR, E_CORE_ERROR, E_RECOVERABLE_ERROR => ERR 0569 * E_DEPRECATED, E_STRICT, E_USER_DEPRECATED => DEBUG 0570 * (unknown/other) => INFO 0571 * 0572 * @link http://www.php.net/manual/en/function.set-error-handler.php Custom error handler 0573 * 0574 * @return Zend_Log 0575 */ 0576 public function registerErrorHandler() 0577 { 0578 // Only register once. Avoids loop issues if it gets registered twice. 0579 if ($this->_registeredErrorHandler) { 0580 return $this; 0581 } 0582 0583 $this->_origErrorHandler = set_error_handler(array($this, 'errorHandler')); 0584 0585 // Contruct a default map of phpErrors to Zend_Log priorities. 0586 // Some of the errors are uncatchable, but are included for completeness 0587 $this->_errorHandlerMap = array( 0588 E_NOTICE => Zend_Log::NOTICE, 0589 E_USER_NOTICE => Zend_Log::NOTICE, 0590 E_WARNING => Zend_Log::WARN, 0591 E_CORE_WARNING => Zend_Log::WARN, 0592 E_USER_WARNING => Zend_Log::WARN, 0593 E_ERROR => Zend_Log::ERR, 0594 E_USER_ERROR => Zend_Log::ERR, 0595 E_CORE_ERROR => Zend_Log::ERR, 0596 E_RECOVERABLE_ERROR => Zend_Log::ERR, 0597 E_STRICT => Zend_Log::DEBUG, 0598 ); 0599 // PHP 5.3.0+ 0600 if (defined('E_DEPRECATED')) { 0601 $this->_errorHandlerMap['E_DEPRECATED'] = Zend_Log::DEBUG; 0602 } 0603 if (defined('E_USER_DEPRECATED')) { 0604 $this->_errorHandlerMap['E_USER_DEPRECATED'] = Zend_Log::DEBUG; 0605 } 0606 0607 $this->_registeredErrorHandler = true; 0608 return $this; 0609 } 0610 0611 /** 0612 * Error Handler will convert error into log message, and then call the original error handler 0613 * 0614 * @link http://www.php.net/manual/en/function.set-error-handler.php Custom error handler 0615 * @param int $errno 0616 * @param string $errstr 0617 * @param string $errfile 0618 * @param int $errline 0619 * @param array $errcontext 0620 * @return boolean 0621 */ 0622 public function errorHandler($errno, $errstr, $errfile, $errline, $errcontext) 0623 { 0624 $errorLevel = error_reporting(); 0625 0626 if ($errorLevel & $errno) { 0627 if (isset($this->_errorHandlerMap[$errno])) { 0628 $priority = $this->_errorHandlerMap[$errno]; 0629 } else { 0630 $priority = Zend_Log::INFO; 0631 } 0632 $this->log($errstr, $priority, array('errno'=>$errno, 'file'=>$errfile, 'line'=>$errline, 'context'=>$errcontext)); 0633 } 0634 0635 if ($this->_origErrorHandler !== null) { 0636 return call_user_func($this->_origErrorHandler, $errno, $errstr, $errfile, $errline, $errcontext); 0637 } 0638 return false; 0639 } 0640 0641 /** 0642 * Set timestamp format for log entries. 0643 * 0644 * @param string $format 0645 * @return Zend_Log 0646 */ 0647 public function setTimestampFormat($format) 0648 { 0649 $this->_timestampFormat = $format; 0650 return $this; 0651 } 0652 0653 /** 0654 * Get timestamp format used for log entries. 0655 * 0656 * @return string 0657 */ 0658 public function getTimestampFormat() 0659 { 0660 return $this->_timestampFormat; 0661 } 0662 }