|
1 <?php |
|
2 /** |
|
3 * Zend Framework |
|
4 * |
|
5 * LICENSE |
|
6 * |
|
7 * This source file is subject to the new BSD license that is bundled |
|
8 * with this package in the file LICENSE.txt. |
|
9 * It is also available through the world-wide-web at this URL: |
|
10 * http://framework.zend.com/license/new-bsd |
|
11 * If you did not receive a copy of the license and are unable to |
|
12 * obtain it through the world-wide-web, please send an email |
|
13 * to license@zend.com so we can send you a copy immediately. |
|
14 * |
|
15 * @category Zend |
|
16 * @package Zend_Log |
|
17 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
18 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
19 * @version $Id: Log.php 22976 2010-09-19 11:57:26Z intiilapa $ |
|
20 */ |
|
21 |
|
22 /** |
|
23 * @category Zend |
|
24 * @package Zend_Log |
|
25 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
26 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
27 * @version $Id: Log.php 22976 2010-09-19 11:57:26Z intiilapa $ |
|
28 */ |
|
29 class Zend_Log |
|
30 { |
|
31 const EMERG = 0; // Emergency: system is unusable |
|
32 const ALERT = 1; // Alert: action must be taken immediately |
|
33 const CRIT = 2; // Critical: critical conditions |
|
34 const ERR = 3; // Error: error conditions |
|
35 const WARN = 4; // Warning: warning conditions |
|
36 const NOTICE = 5; // Notice: normal but significant condition |
|
37 const INFO = 6; // Informational: informational messages |
|
38 const DEBUG = 7; // Debug: debug messages |
|
39 |
|
40 /** |
|
41 * @var array of priorities where the keys are the |
|
42 * priority numbers and the values are the priority names |
|
43 */ |
|
44 protected $_priorities = array(); |
|
45 |
|
46 /** |
|
47 * @var array of Zend_Log_Writer_Abstract |
|
48 */ |
|
49 protected $_writers = array(); |
|
50 |
|
51 /** |
|
52 * @var array of Zend_Log_Filter_Interface |
|
53 */ |
|
54 protected $_filters = array(); |
|
55 |
|
56 /** |
|
57 * @var array of extra log event |
|
58 */ |
|
59 protected $_extras = array(); |
|
60 |
|
61 /** |
|
62 * |
|
63 * @var string |
|
64 */ |
|
65 protected $_defaultWriterNamespace = 'Zend_Log_Writer'; |
|
66 |
|
67 /** |
|
68 * |
|
69 * @var string |
|
70 */ |
|
71 protected $_defaultFilterNamespace = 'Zend_Log_Filter'; |
|
72 |
|
73 /** |
|
74 * |
|
75 * @var callback |
|
76 */ |
|
77 protected $_origErrorHandler = null; |
|
78 |
|
79 /** |
|
80 * |
|
81 * @var boolean |
|
82 */ |
|
83 protected $_registeredErrorHandler = false; |
|
84 |
|
85 /** |
|
86 * |
|
87 * @var array |
|
88 */ |
|
89 protected $_errorHandlerMap = false; |
|
90 |
|
91 /** |
|
92 * |
|
93 * @var string |
|
94 */ |
|
95 protected $_timestampFormat = 'c'; |
|
96 |
|
97 /** |
|
98 * Class constructor. Create a new logger |
|
99 * |
|
100 * @param Zend_Log_Writer_Abstract|null $writer default writer |
|
101 */ |
|
102 public function __construct(Zend_Log_Writer_Abstract $writer = null) |
|
103 { |
|
104 $r = new ReflectionClass($this); |
|
105 $this->_priorities = array_flip($r->getConstants()); |
|
106 |
|
107 if ($writer !== null) { |
|
108 $this->addWriter($writer); |
|
109 } |
|
110 } |
|
111 |
|
112 /** |
|
113 * Factory to construct the logger and one or more writers |
|
114 * based on the configuration array |
|
115 * |
|
116 * @param array|Zend_Config Array or instance of Zend_Config |
|
117 * @return Zend_Log |
|
118 */ |
|
119 static public function factory($config = array()) |
|
120 { |
|
121 if ($config instanceof Zend_Config) { |
|
122 $config = $config->toArray(); |
|
123 } |
|
124 |
|
125 if (!is_array($config) || empty($config)) { |
|
126 /** @see Zend_Log_Exception */ |
|
127 require_once 'Zend/Log/Exception.php'; |
|
128 throw new Zend_Log_Exception('Configuration must be an array or instance of Zend_Config'); |
|
129 } |
|
130 |
|
131 $log = new self; |
|
132 |
|
133 if (!is_array(current($config))) { |
|
134 $log->addWriter(current($config)); |
|
135 } else { |
|
136 foreach($config as $writer) { |
|
137 $log->addWriter($writer); |
|
138 } |
|
139 } |
|
140 |
|
141 return $log; |
|
142 } |
|
143 |
|
144 |
|
145 /** |
|
146 * Construct a writer object based on a configuration array |
|
147 * |
|
148 * @param array $spec config array with writer spec |
|
149 * @return Zend_Log_Writer_Abstract |
|
150 */ |
|
151 protected function _constructWriterFromConfig($config) |
|
152 { |
|
153 $writer = $this->_constructFromConfig('writer', $config, $this->_defaultWriterNamespace); |
|
154 |
|
155 if (!$writer instanceof Zend_Log_Writer_Abstract) { |
|
156 $writerName = is_object($writer) |
|
157 ? get_class($writer) |
|
158 : 'The specified writer'; |
|
159 /** @see Zend_Log_Exception */ |
|
160 require_once 'Zend/Log/Exception.php'; |
|
161 throw new Zend_Log_Exception("{$writerName} does not extend Zend_Log_Writer_Abstract!"); |
|
162 } |
|
163 |
|
164 if (isset($config['filterName'])) { |
|
165 $filter = $this->_constructFilterFromConfig($config); |
|
166 $writer->addFilter($filter); |
|
167 } |
|
168 |
|
169 return $writer; |
|
170 } |
|
171 |
|
172 /** |
|
173 * Construct filter object from configuration array or Zend_Config object |
|
174 * |
|
175 * @param array|Zend_Config $config Zend_Config or Array |
|
176 * @return Zend_Log_Filter_Interface |
|
177 */ |
|
178 protected function _constructFilterFromConfig($config) |
|
179 { |
|
180 $filter = $this->_constructFromConfig('filter', $config, $this->_defaultFilterNamespace); |
|
181 |
|
182 if (!$filter instanceof Zend_Log_Filter_Interface) { |
|
183 $filterName = is_object($filter) |
|
184 ? get_class($filter) |
|
185 : 'The specified filter'; |
|
186 /** @see Zend_Log_Exception */ |
|
187 require_once 'Zend/Log/Exception.php'; |
|
188 throw new Zend_Log_Exception("{$filterName} does not implement Zend_Log_Filter_Interface"); |
|
189 } |
|
190 |
|
191 return $filter; |
|
192 } |
|
193 |
|
194 /** |
|
195 * Construct a filter or writer from config |
|
196 * |
|
197 * @param string $type 'writer' of 'filter' |
|
198 * @param mixed $config Zend_Config or Array |
|
199 * @param string $namespace |
|
200 * @return object |
|
201 */ |
|
202 protected function _constructFromConfig($type, $config, $namespace) |
|
203 { |
|
204 if ($config instanceof Zend_Config) { |
|
205 $config = $config->toArray(); |
|
206 } |
|
207 |
|
208 if (!is_array($config) || empty($config)) { |
|
209 require_once 'Zend/Log/Exception.php'; |
|
210 throw new Zend_Log_Exception( |
|
211 'Configuration must be an array or instance of Zend_Config' |
|
212 ); |
|
213 } |
|
214 |
|
215 $params = isset($config[ $type .'Params' ]) ? $config[ $type .'Params' ] : array(); |
|
216 $className = $this->getClassName($config, $type, $namespace); |
|
217 if (!class_exists($className)) { |
|
218 require_once 'Zend/Loader.php'; |
|
219 Zend_Loader::loadClass($className); |
|
220 } |
|
221 |
|
222 $reflection = new ReflectionClass($className); |
|
223 if (!$reflection->implementsInterface('Zend_Log_FactoryInterface')) { |
|
224 require_once 'Zend/Log/Exception.php'; |
|
225 throw new Zend_Log_Exception( |
|
226 'Driver does not implement Zend_Log_FactoryInterface and can not be constructed from config.' |
|
227 ); |
|
228 } |
|
229 |
|
230 return call_user_func(array($className, 'factory'), $params); |
|
231 } |
|
232 |
|
233 /** |
|
234 * Get the writer or filter full classname |
|
235 * |
|
236 * @param array $config |
|
237 * @param string $type filter|writer |
|
238 * @param string $defaultNamespace |
|
239 * @return string full classname |
|
240 */ |
|
241 protected function getClassName($config, $type, $defaultNamespace) |
|
242 { |
|
243 if (!isset($config[ $type . 'Name' ])) { |
|
244 require_once 'Zend/Log/Exception.php'; |
|
245 throw new Zend_Log_Exception("Specify {$type}Name in the configuration array"); |
|
246 } |
|
247 $className = $config[ $type . 'Name' ]; |
|
248 |
|
249 $namespace = $defaultNamespace; |
|
250 if (isset($config[ $type . 'Namespace' ])) { |
|
251 $namespace = $config[ $type . 'Namespace' ]; |
|
252 } |
|
253 |
|
254 $fullClassName = $namespace . '_' . $className; |
|
255 return $fullClassName; |
|
256 } |
|
257 |
|
258 /** |
|
259 * Packs message and priority into Event array |
|
260 * |
|
261 * @param string $message Message to log |
|
262 * @param integer $priority Priority of message |
|
263 * @return array Event array |
|
264 **/ |
|
265 protected function _packEvent($message, $priority) |
|
266 { |
|
267 return array_merge(array( |
|
268 'timestamp' => date($this->_timestampFormat), |
|
269 'message' => $message, |
|
270 'priority' => $priority, |
|
271 'priorityName' => $this->_priorities[$priority] |
|
272 ), |
|
273 $this->_extras |
|
274 ); |
|
275 } |
|
276 |
|
277 /** |
|
278 * Class destructor. Shutdown log writers |
|
279 * |
|
280 * @return void |
|
281 */ |
|
282 public function __destruct() |
|
283 { |
|
284 foreach($this->_writers as $writer) { |
|
285 $writer->shutdown(); |
|
286 } |
|
287 } |
|
288 |
|
289 /** |
|
290 * Undefined method handler allows a shortcut: |
|
291 * $log->priorityName('message') |
|
292 * instead of |
|
293 * $log->log('message', Zend_Log::PRIORITY_NAME) |
|
294 * |
|
295 * @param string $method priority name |
|
296 * @param string $params message to log |
|
297 * @return void |
|
298 * @throws Zend_Log_Exception |
|
299 */ |
|
300 public function __call($method, $params) |
|
301 { |
|
302 $priority = strtoupper($method); |
|
303 if (($priority = array_search($priority, $this->_priorities)) !== false) { |
|
304 switch (count($params)) { |
|
305 case 0: |
|
306 /** @see Zend_Log_Exception */ |
|
307 require_once 'Zend/Log/Exception.php'; |
|
308 throw new Zend_Log_Exception('Missing log message'); |
|
309 case 1: |
|
310 $message = array_shift($params); |
|
311 $extras = null; |
|
312 break; |
|
313 default: |
|
314 $message = array_shift($params); |
|
315 $extras = array_shift($params); |
|
316 break; |
|
317 } |
|
318 $this->log($message, $priority, $extras); |
|
319 } else { |
|
320 /** @see Zend_Log_Exception */ |
|
321 require_once 'Zend/Log/Exception.php'; |
|
322 throw new Zend_Log_Exception('Bad log priority'); |
|
323 } |
|
324 } |
|
325 |
|
326 /** |
|
327 * Log a message at a priority |
|
328 * |
|
329 * @param string $message Message to log |
|
330 * @param integer $priority Priority of message |
|
331 * @param mixed $extras Extra information to log in event |
|
332 * @return void |
|
333 * @throws Zend_Log_Exception |
|
334 */ |
|
335 public function log($message, $priority, $extras = null) |
|
336 { |
|
337 // sanity checks |
|
338 if (empty($this->_writers)) { |
|
339 /** @see Zend_Log_Exception */ |
|
340 require_once 'Zend/Log/Exception.php'; |
|
341 throw new Zend_Log_Exception('No writers were added'); |
|
342 } |
|
343 |
|
344 if (! isset($this->_priorities[$priority])) { |
|
345 /** @see Zend_Log_Exception */ |
|
346 require_once 'Zend/Log/Exception.php'; |
|
347 throw new Zend_Log_Exception('Bad log priority'); |
|
348 } |
|
349 |
|
350 // pack into event required by filters and writers |
|
351 $event = $this->_packEvent($message, $priority); |
|
352 |
|
353 // Check to see if any extra information was passed |
|
354 if (!empty($extras)) { |
|
355 $info = array(); |
|
356 if (is_array($extras)) { |
|
357 foreach ($extras as $key => $value) { |
|
358 if (is_string($key)) { |
|
359 $event[$key] = $value; |
|
360 } else { |
|
361 $info[] = $value; |
|
362 } |
|
363 } |
|
364 } else { |
|
365 $info = $extras; |
|
366 } |
|
367 if (!empty($info)) { |
|
368 $event['info'] = $info; |
|
369 } |
|
370 } |
|
371 |
|
372 // abort if rejected by the global filters |
|
373 foreach ($this->_filters as $filter) { |
|
374 if (! $filter->accept($event)) { |
|
375 return; |
|
376 } |
|
377 } |
|
378 |
|
379 // send to each writer |
|
380 foreach ($this->_writers as $writer) { |
|
381 $writer->write($event); |
|
382 } |
|
383 } |
|
384 |
|
385 /** |
|
386 * Add a custom priority |
|
387 * |
|
388 * @param string $name Name of priority |
|
389 * @param integer $priority Numeric priority |
|
390 * @throws Zend_Log_InvalidArgumentException |
|
391 */ |
|
392 public function addPriority($name, $priority) |
|
393 { |
|
394 // Priority names must be uppercase for predictability. |
|
395 $name = strtoupper($name); |
|
396 |
|
397 if (isset($this->_priorities[$priority]) |
|
398 || false !== array_search($name, $this->_priorities)) { |
|
399 /** @see Zend_Log_Exception */ |
|
400 require_once 'Zend/Log/Exception.php'; |
|
401 throw new Zend_Log_Exception('Existing priorities cannot be overwritten'); |
|
402 } |
|
403 |
|
404 $this->_priorities[$priority] = $name; |
|
405 return $this; |
|
406 } |
|
407 |
|
408 /** |
|
409 * Add a filter that will be applied before all log writers. |
|
410 * Before a message will be received by any of the writers, it |
|
411 * must be accepted by all filters added with this method. |
|
412 * |
|
413 * @param int|Zend_Log_Filter_Interface $filter |
|
414 * @return void |
|
415 */ |
|
416 public function addFilter($filter) |
|
417 { |
|
418 if (is_integer($filter)) { |
|
419 /** @see Zend_Log_Filter_Priority */ |
|
420 require_once 'Zend/Log/Filter/Priority.php'; |
|
421 $filter = new Zend_Log_Filter_Priority($filter); |
|
422 |
|
423 } elseif ($filter instanceof Zend_Config || is_array($filter)) { |
|
424 $filter = $this->_constructFilterFromConfig($filter); |
|
425 |
|
426 } elseif(! $filter instanceof Zend_Log_Filter_Interface) { |
|
427 /** @see Zend_Log_Exception */ |
|
428 require_once 'Zend/Log/Exception.php'; |
|
429 throw new Zend_Log_Exception('Invalid filter provided'); |
|
430 } |
|
431 |
|
432 $this->_filters[] = $filter; |
|
433 return $this; |
|
434 } |
|
435 |
|
436 /** |
|
437 * Add a writer. A writer is responsible for taking a log |
|
438 * message and writing it out to storage. |
|
439 * |
|
440 * @param mixed $writer Zend_Log_Writer_Abstract or Config array |
|
441 * @return void |
|
442 */ |
|
443 public function addWriter($writer) |
|
444 { |
|
445 if (is_array($writer) || $writer instanceof Zend_Config) { |
|
446 $writer = $this->_constructWriterFromConfig($writer); |
|
447 } |
|
448 |
|
449 if (!$writer instanceof Zend_Log_Writer_Abstract) { |
|
450 /** @see Zend_Log_Exception */ |
|
451 require_once 'Zend/Log/Exception.php'; |
|
452 throw new Zend_Log_Exception( |
|
453 'Writer must be an instance of Zend_Log_Writer_Abstract' |
|
454 . ' or you should pass a configuration array' |
|
455 ); |
|
456 } |
|
457 |
|
458 $this->_writers[] = $writer; |
|
459 return $this; |
|
460 } |
|
461 |
|
462 /** |
|
463 * Set an extra item to pass to the log writers. |
|
464 * |
|
465 * @param $name Name of the field |
|
466 * @param $value Value of the field |
|
467 * @return void |
|
468 */ |
|
469 public function setEventItem($name, $value) |
|
470 { |
|
471 $this->_extras = array_merge($this->_extras, array($name => $value)); |
|
472 return $this; |
|
473 } |
|
474 |
|
475 /** |
|
476 * Register Logging system as an error handler to log php errors |
|
477 * Note: it still calls the original error handler if set_error_handler is able to return it. |
|
478 * |
|
479 * Errors will be mapped as: |
|
480 * E_NOTICE, E_USER_NOTICE => NOTICE |
|
481 * E_WARNING, E_CORE_WARNING, E_USER_WARNING => WARN |
|
482 * E_ERROR, E_USER_ERROR, E_CORE_ERROR, E_RECOVERABLE_ERROR => ERR |
|
483 * E_DEPRECATED, E_STRICT, E_USER_DEPRECATED => DEBUG |
|
484 * (unknown/other) => INFO |
|
485 * |
|
486 * @link http://www.php.net/manual/en/function.set-error-handler.php Custom error handler |
|
487 * |
|
488 * @return Zend_Log |
|
489 */ |
|
490 public function registerErrorHandler() |
|
491 { |
|
492 // Only register once. Avoids loop issues if it gets registered twice. |
|
493 if ($this->_registeredErrorHandler) { |
|
494 return $this; |
|
495 } |
|
496 |
|
497 $this->_origErrorHandler = set_error_handler(array($this, 'errorHandler')); |
|
498 |
|
499 // Contruct a default map of phpErrors to Zend_Log priorities. |
|
500 // Some of the errors are uncatchable, but are included for completeness |
|
501 $this->_errorHandlerMap = array( |
|
502 E_NOTICE => Zend_Log::NOTICE, |
|
503 E_USER_NOTICE => Zend_Log::NOTICE, |
|
504 E_WARNING => Zend_Log::WARN, |
|
505 E_CORE_WARNING => Zend_Log::WARN, |
|
506 E_USER_WARNING => Zend_Log::WARN, |
|
507 E_ERROR => Zend_Log::ERR, |
|
508 E_USER_ERROR => Zend_Log::ERR, |
|
509 E_CORE_ERROR => Zend_Log::ERR, |
|
510 E_RECOVERABLE_ERROR => Zend_Log::ERR, |
|
511 E_STRICT => Zend_Log::DEBUG, |
|
512 ); |
|
513 // PHP 5.3.0+ |
|
514 if (defined('E_DEPRECATED')) { |
|
515 $this->_errorHandlerMap['E_DEPRECATED'] = Zend_Log::DEBUG; |
|
516 } |
|
517 if (defined('E_USER_DEPRECATED')) { |
|
518 $this->_errorHandlerMap['E_USER_DEPRECATED'] = Zend_Log::DEBUG; |
|
519 } |
|
520 |
|
521 $this->_registeredErrorHandler = true; |
|
522 return $this; |
|
523 } |
|
524 |
|
525 /** |
|
526 * Error Handler will convert error into log message, and then call the original error handler |
|
527 * |
|
528 * @link http://www.php.net/manual/en/function.set-error-handler.php Custom error handler |
|
529 * @param int $errno |
|
530 * @param string $errstr |
|
531 * @param string $errfile |
|
532 * @param int $errline |
|
533 * @param array $errcontext |
|
534 * @return boolean |
|
535 */ |
|
536 public function errorHandler($errno, $errstr, $errfile, $errline, $errcontext) |
|
537 { |
|
538 $errorLevel = error_reporting(); |
|
539 |
|
540 if ($errorLevel && $errno) { |
|
541 if (isset($this->_errorHandlerMap[$errno])) { |
|
542 $priority = $this->_errorHandlerMap[$errno]; |
|
543 } else { |
|
544 $priority = Zend_Log::INFO; |
|
545 } |
|
546 $this->log($errstr, $priority, array('errno'=>$errno, 'file'=>$errfile, 'line'=>$errline, 'context'=>$errcontext)); |
|
547 } |
|
548 |
|
549 if ($this->_origErrorHandler !== null) { |
|
550 return call_user_func($this->_origErrorHandler, $errno, $errstr, $errfile, $errline, $errcontext); |
|
551 } |
|
552 return false; |
|
553 } |
|
554 |
|
555 /** |
|
556 * Set timestamp format for log entries. |
|
557 * |
|
558 * @param string $format |
|
559 * @return Zend_Log |
|
560 */ |
|
561 public function setTimestampFormat($format) |
|
562 { |
|
563 $this->_timestampFormat = $format; |
|
564 return $this; |
|
565 } |
|
566 |
|
567 /** |
|
568 * Get timestamp format used for log entries. |
|
569 * |
|
570 * @return string |
|
571 */ |
|
572 public function getTimestampFormat() |
|
573 { |
|
574 return $this->_timestampFormat; |
|
575 } |
|
576 } |