4 * $Horde: horde/lib/Log.php,v 1.15 2000/06/29 23:39:45 jon Exp $
6 * @version $Revision: 310238 $
10 define('PEAR_LOG_EMERG', 0); /* System is unusable */
11 define('PEAR_LOG_ALERT', 1); /* Immediate action required */
12 define('PEAR_LOG_CRIT', 2); /* Critical conditions */
13 define('PEAR_LOG_ERR', 3); /* Error conditions */
14 define('PEAR_LOG_WARNING', 4); /* Warning conditions */
15 define('PEAR_LOG_NOTICE', 5); /* Normal but significant */
16 define('PEAR_LOG_INFO', 6); /* Informational */
17 define('PEAR_LOG_DEBUG', 7); /* Debug-level messages */
19 define('PEAR_LOG_ALL', 0xffffffff); /* All messages */
20 define('PEAR_LOG_NONE', 0x00000000); /* No message */
22 /* Log types for PHP's native error_log() function. */
23 define('PEAR_LOG_TYPE_SYSTEM', 0); /* Use PHP's system logger */
24 define('PEAR_LOG_TYPE_MAIL', 1); /* Use PHP's mail() function */
25 define('PEAR_LOG_TYPE_DEBUG', 2); /* Use PHP's debugging connection */
26 define('PEAR_LOG_TYPE_FILE', 3); /* Append to a file */
27 define('PEAR_LOG_TYPE_SAPI', 4); /* Use the SAPI logging handler */
30 * The Log:: class implements both an abstraction for various logging
31 * mechanisms and the Subject end of a Subject-Observer pattern.
33 * @author Chuck Hagenbuch <chuck@horde.org>
34 * @author Jon Parise <jon@php.net>
41 * Indicates whether or not the log can been opened / connected.
49 * Instance-specific unique identification number.
57 * The label that uniquely identifies this set of log messages.
65 * The default priority to use when logging an event.
70 var $_priority = PEAR_LOG_INFO;
73 * The bitmask of allowed log levels.
78 var $_mask = PEAR_LOG_ALL;
81 * Holds all Log_observer objects that wish to be notified of new messages.
86 var $_listeners = array();
89 * Starting depth to use when walking a backtrace in search of the
90 * function that invoked the log system.
95 var $_backtrace_depth = 0;
98 * Maps canonical format keys to position arguments for use in building
99 * "line format" strings.
104 var $_formatMap = array('%{timestamp}' => '%1$s',
105 '%{ident}' => '%2$s',
106 '%{priority}' => '%3$s',
107 '%{message}' => '%4$s',
110 '%{function}' => '%7$s',
111 '%{class}' => '%8$s',
115 * Attempts to return a concrete Log instance of type $handler.
117 * @param string $handler The type of concrete Log subclass to return.
118 * Attempt to dynamically include the code for
119 * this subclass. Currently, valid values are
120 * 'console', 'syslog', 'sql', 'file', and 'mcal'.
122 * @param string $name The name of the actually log file, table, or
123 * other specific store to use. Defaults to an
124 * empty string, with which the subclass will
125 * attempt to do something intelligent.
127 * @param string $ident The identity reported to the log system.
129 * @param array $conf A hash containing any additional configuration
130 * information that a subclass might need.
132 * @param int $level Log messages up to and including this level.
134 * @return object Log The newly created concrete Log instance, or
139 public static function factory($handler, $name = '', $ident = '',
140 $conf = array(), $level = PEAR_LOG_DEBUG)
142 $handler = strtolower($handler);
143 $class = 'Log_' . $handler;
144 $classfile = 'Log/' . $handler . '.php';
147 * Attempt to include our version of the named class, but don't treat
148 * a failure as fatal. The caller may have already included their own
149 * version of the named class.
151 if (!class_exists($class, false)) {
152 include_once $classfile;
155 /* If the class exists, return a new instance of it. */
156 if (class_exists($class, false)) {
157 $obj = new $class($name, $ident, $conf, $level);
166 * Attempts to return a reference to a concrete Log instance of type
167 * $handler, only creating a new instance if no log instance with the same
168 * parameters currently exists.
170 * You should use this if there are multiple places you might create a
171 * logger, you don't want to create multiple loggers, and you don't want to
172 * check for the existance of one each time. The singleton pattern does all
173 * the checking work for you.
175 * <b>You MUST call this method with the $var = &Log::singleton() syntax.
176 * Without the ampersand (&) in front of the method name, you will not get
177 * a reference, you will get a copy.</b>
179 * @param string $handler The type of concrete Log subclass to return.
180 * Attempt to dynamically include the code for
181 * this subclass. Currently, valid values are
182 * 'console', 'syslog', 'sql', 'file', and 'mcal'.
184 * @param string $name The name of the actually log file, table, or
185 * other specific store to use. Defaults to an
186 * empty string, with which the subclass will
187 * attempt to do something intelligent.
189 * @param string $ident The identity reported to the log system.
191 * @param array $conf A hash containing any additional configuration
192 * information that a subclass might need.
194 * @param int $level Log messages up to and including this level.
196 * @return object Log The newly created concrete Log instance, or
201 public static function singleton($handler, $name = '', $ident = '',
202 $conf = array(), $level = PEAR_LOG_DEBUG)
205 if (!isset($instances)) $instances = array();
207 $signature = serialize(array($handler, $name, $ident, $conf, $level));
208 if (!isset($instances[$signature])) {
209 $instances[$signature] = Log::factory($handler, $name, $ident,
213 return $instances[$signature];
217 * Abstract implementation of the open() method.
226 * Abstract implementation of the close() method.
235 * Abstract implementation of the flush() method.
244 * Abstract implementation of the log() method.
247 function log($message, $priority = null)
253 * A convenience function for logging a emergency event. It will log a
254 * message at the PEAR_LOG_EMERG log level.
256 * @param mixed $message String or object containing the message
259 * @return boolean True if the message was successfully logged.
264 function emerg($message)
266 return $this->log($message, PEAR_LOG_EMERG);
270 * A convenience function for logging an alert event. It will log a
271 * message at the PEAR_LOG_ALERT log level.
273 * @param mixed $message String or object containing the message
276 * @return boolean True if the message was successfully logged.
281 function alert($message)
283 return $this->log($message, PEAR_LOG_ALERT);
287 * A convenience function for logging a critical event. It will log a
288 * message at the PEAR_LOG_CRIT log level.
290 * @param mixed $message String or object containing the message
293 * @return boolean True if the message was successfully logged.
298 function crit($message)
300 return $this->log($message, PEAR_LOG_CRIT);
304 * A convenience function for logging a error event. It will log a
305 * message at the PEAR_LOG_ERR log level.
307 * @param mixed $message String or object containing the message
310 * @return boolean True if the message was successfully logged.
315 function err($message)
317 return $this->log($message, PEAR_LOG_ERR);
321 * A convenience function for logging a warning event. It will log a
322 * message at the PEAR_LOG_WARNING log level.
324 * @param mixed $message String or object containing the message
327 * @return boolean True if the message was successfully logged.
332 function warning($message)
334 return $this->log($message, PEAR_LOG_WARNING);
338 * A convenience function for logging a notice event. It will log a
339 * message at the PEAR_LOG_NOTICE log level.
341 * @param mixed $message String or object containing the message
344 * @return boolean True if the message was successfully logged.
349 function notice($message)
351 return $this->log($message, PEAR_LOG_NOTICE);
355 * A convenience function for logging a information event. It will log a
356 * message at the PEAR_LOG_INFO log level.
358 * @param mixed $message String or object containing the message
361 * @return boolean True if the message was successfully logged.
366 function info($message)
368 return $this->log($message, PEAR_LOG_INFO);
372 * A convenience function for logging a debug event. It will log a
373 * message at the PEAR_LOG_DEBUG log level.
375 * @param mixed $message String or object containing the message
378 * @return boolean True if the message was successfully logged.
383 function debug($message)
385 return $this->log($message, PEAR_LOG_DEBUG);
389 * Returns the string representation of the message data.
391 * If $message is an object, _extractMessage() will attempt to extract
392 * the message text using a known method (such as a PEAR_Error object's
393 * getMessage() method). If a known method, cannot be found, the
394 * serialized representation of the object will be returned.
396 * If the message data is already a string, it will be returned unchanged.
398 * @param mixed $message The original message data. This may be a
399 * string or any object.
401 * @return string The string representation of the message.
405 function _extractMessage($message)
408 * If we've been given an object, attempt to extract the message using
409 * a known method. If we can't find such a method, default to the
410 * "human-readable" version of the object.
412 * We also use the human-readable format for arrays.
414 if (is_object($message)) {
415 if (method_exists($message, 'getmessage')) {
416 $message = $message->getMessage();
417 } else if (method_exists($message, 'tostring')) {
418 $message = $message->toString();
419 } else if (method_exists($message, '__tostring')) {
420 $message = (string)$message;
422 $message = var_export($message, true);
424 } else if (is_array($message)) {
425 if (isset($message['message'])) {
426 if (is_scalar($message['message'])) {
427 $message = $message['message'];
429 $message = var_export($message['message'], true);
432 $message = var_export($message, true);
434 } else if (is_bool($message) || $message === NULL) {
435 $message = var_export($message, true);
438 /* Otherwise, we assume the message is a string. */
443 * Using debug_backtrace(), returns the file, line, and enclosing function
444 * name of the source code context from which log() was invoked.
446 * @param int $depth The initial number of frames we should step
447 * back into the trace.
449 * @return array Array containing four strings: the filename, the line,
450 * the function name, and the class name from which log()
456 function _getBacktraceVars($depth)
458 /* Start by generating a backtrace from the current call (here). */
459 $bt = debug_backtrace();
461 /* Store some handy shortcuts to our previous frames. */
462 $bt0 = isset($bt[$depth]) ? $bt[$depth] : null;
463 $bt1 = isset($bt[$depth + 1]) ? $bt[$depth + 1] : null;
466 * If we were ultimately invoked by the composite handler, we need to
467 * increase our depth one additional level to compensate.
469 $class = isset($bt1['class']) ? $bt1['class'] : null;
470 if ($class !== null && strcasecmp($class, 'Log_composite') == 0) {
472 $bt0 = isset($bt[$depth]) ? $bt[$depth] : null;
473 $bt1 = isset($bt[$depth + 1]) ? $bt[$depth + 1] : null;
474 $class = isset($bt1['class']) ? $bt1['class'] : null;
478 * We're interested in the frame which invoked the log() function, so
479 * we need to walk back some number of frames into the backtrace. The
480 * $depth parameter tells us where to start looking. We go one step
481 * further back to find the name of the encapsulating function from
482 * which log() was called.
484 $file = isset($bt0) ? $bt0['file'] : null;
485 $line = isset($bt0) ? $bt0['line'] : 0;
486 $func = isset($bt1) ? $bt1['function'] : null;
489 * However, if log() was called from one of our "shortcut" functions,
490 * we're going to need to go back an additional step.
492 if (in_array($func, array('emerg', 'alert', 'crit', 'err', 'warning',
493 'notice', 'info', 'debug'))) {
494 $bt2 = isset($bt[$depth + 2]) ? $bt[$depth + 2] : null;
496 $file = is_array($bt1) ? $bt1['file'] : null;
497 $line = is_array($bt1) ? $bt1['line'] : 0;
498 $func = is_array($bt2) ? $bt2['function'] : null;
499 $class = isset($bt2['class']) ? $bt2['class'] : null;
503 * If we couldn't extract a function name (perhaps because we were
504 * executed from the "main" context), provide a default value.
506 if ($func === null) {
510 /* Return a 4-tuple containing (file, line, function, class). */
511 return array($file, $line, $func, $class);
515 * Sets the starting depth to use when walking a backtrace in search of
516 * the function that invoked the log system. This is used on conjunction
517 * with the 'file', 'line', 'function', and 'class' formatters.
519 * @param int $depth The new backtrace depth.
524 public function setBacktraceDepth($depth)
526 $this->_backtrace_depth = $depth;
530 * Produces a formatted log line based on a format string and a set of
531 * variables representing the current log record and state.
533 * @return string Formatted log string.
538 function _format($format, $timestamp, $priority, $message)
541 * If the format string references any of the backtrace-driven
542 * variables (%5 %6,%7,%8), generate the backtrace and fetch them.
544 if (preg_match('/%[5678]/', $format)) {
545 /* Plus 2 to account for our internal function calls. */
546 $d = $this->_backtrace_depth + 2;
547 list($file, $line, $func, $class) = $this->_getBacktraceVars($d);
551 * Build the formatted string. We use the sprintf() function's
552 * "argument swapping" capability to dynamically select and position
553 * the variables which will ultimately appear in the log string.
555 return sprintf($format,
558 $this->priorityToString($priority),
560 isset($file) ? $file : '',
561 isset($line) ? $line : '',
562 isset($func) ? $func : '',
563 isset($class) ? $class : '');
567 * Returns the string representation of a PEAR_LOG_* integer constant.
569 * @param int $priority A PEAR_LOG_* integer constant.
571 * @return string The string representation of $level.
576 function priorityToString($priority)
579 PEAR_LOG_EMERG => 'emergency',
580 PEAR_LOG_ALERT => 'alert',
581 PEAR_LOG_CRIT => 'critical',
582 PEAR_LOG_ERR => 'error',
583 PEAR_LOG_WARNING => 'warning',
584 PEAR_LOG_NOTICE => 'notice',
585 PEAR_LOG_INFO => 'info',
586 PEAR_LOG_DEBUG => 'debug'
589 return $levels[$priority];
593 * Returns the the PEAR_LOG_* integer constant for the given string
594 * representation of a priority name. This function performs a
595 * case-insensitive search.
597 * @param string $name String containing a priority name.
599 * @return string The PEAR_LOG_* integer contstant corresponding
600 * the the specified priority name.
605 function stringToPriority($name)
608 'emergency' => PEAR_LOG_EMERG,
609 'alert' => PEAR_LOG_ALERT,
610 'critical' => PEAR_LOG_CRIT,
611 'error' => PEAR_LOG_ERR,
612 'warning' => PEAR_LOG_WARNING,
613 'notice' => PEAR_LOG_NOTICE,
614 'info' => PEAR_LOG_INFO,
615 'debug' => PEAR_LOG_DEBUG
618 return $levels[strtolower($name)];
622 * Calculate the log mask for the given priority.
624 * This method may be called statically.
626 * @param integer $priority The priority whose mask will be calculated.
628 * @return integer The calculated log mask.
633 public static function MASK($priority)
635 return (1 << $priority);
639 * Calculate the log mask for all priorities up to the given priority.
641 * This method may be called statically.
643 * @param integer $priority The maximum priority covered by this mask.
645 * @return integer The resulting log mask.
650 * @deprecated deprecated since Log 1.9.4; use Log::MAX() instead
652 public static function UPTO($priority)
654 return Log::MAX($priority);
658 * Calculate the log mask for all priorities greater than or equal to the
659 * given priority. In other words, $priority will be the lowest priority
660 * matched by the resulting mask.
662 * This method may be called statically.
664 * @param integer $priority The minimum priority covered by this mask.
666 * @return integer The resulting log mask.
671 public static function MIN($priority)
673 return PEAR_LOG_ALL ^ ((1 << $priority) - 1);
677 * Calculate the log mask for all priorities less than or equal to the
678 * given priority. In other words, $priority will be the highests priority
679 * matched by the resulting mask.
681 * This method may be called statically.
683 * @param integer $priority The maximum priority covered by this mask.
685 * @return integer The resulting log mask.
690 public static function MAX($priority)
692 return ((1 << ($priority + 1)) - 1);
696 * Set and return the level mask for the current Log instance.
698 * @param integer $mask A bitwise mask of log levels.
700 * @return integer The current level mask.
705 function setMask($mask)
707 $this->_mask = $mask;
713 * Returns the current level mask.
715 * @return interger The current level mask.
726 * Check if the given priority is included in the current level mask.
728 * @param integer $priority The priority to check.
730 * @return boolean True if the given priority is included in the current
736 function _isMasked($priority)
738 return (Log::MASK($priority) & $this->_mask);
742 * Returns the current default priority.
744 * @return integer The current default priority.
749 function getPriority()
751 return $this->_priority;
755 * Sets the default priority to the specified value.
757 * @param integer $priority The new default priority.
762 function setPriority($priority)
764 $this->_priority = $priority;
768 * Adds a Log_observer instance to the list of observers that are listening
769 * for messages emitted by this Log instance.
771 * @param object $observer The Log_observer instance to attach as a
774 * @param boolean True if the observer is successfully attached.
779 function attach(&$observer)
781 if (!is_a($observer, 'Log_observer')) {
785 $this->_listeners[$observer->_id] = &$observer;
791 * Removes a Log_observer instance from the list of observers.
793 * @param object $observer The Log_observer instance to detach from
794 * the list of listeners.
796 * @param boolean True if the observer is successfully detached.
801 function detach($observer)
803 if (!is_a($observer, 'Log_observer') ||
804 !isset($this->_listeners[$observer->_id])) {
808 unset($this->_listeners[$observer->_id]);
814 * Informs each registered observer instance that a new message has been
817 * @param array $event A hash describing the log event.
821 function _announce($event)
823 foreach ($this->_listeners as $id => $listener) {
824 if ($event['priority'] <= $this->_listeners[$id]->_priority) {
825 $this->_listeners[$id]->notify($event);
831 * Indicates whether this is a composite class.
833 * @return boolean True if this is a composite class.
838 function isComposite()
844 * Sets this Log instance's identification string.
846 * @param string $ident The new identification string.
851 function setIdent($ident)
853 $this->_ident = $ident;
857 * Returns the current identification string.
859 * @return string The current Log instance's identification string.
866 return $this->_ident;