<?php
/**
* Log:: driver to write messages into Growl client
*
* PHP versions 4 and 5
*
* @category Logging
* @package Log
* @author Laurent Laville <pear@laurent-laville.org>
* @copyright 2009 Laurent Laville
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @version CVS: $Id:$
* @link http://pear.php.net/package/Log
*/
require_once 'Net/Growl.php';
define('GROWL_PRIORITY_LOW', -2);
define('GROWL_PRIORITY_MODERATE', -1);
define('GROWL_PRIORITY_NORMAL', 0);
define('GROWL_PRIORITY_HIGH', 1);
define('GROWL_PRIORITY_EMERGENCY', 2);
/**
* The Log_growl class is a concrete implementation of the Log::
* abstract class which writes message into Growl client listener.
*
* http://growl.info/
* http://www.growlforwindows.com
*
* @category Logging
* @package Log
* @author Laurent Laville <pear@laurent-laville.org>
* @copyright 2009 Laurent Laville
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @version Release: @package_version@
* @link http://pear.php.net/package/Log
*/
class Log_growl extends Log
{
/**
* String containing the format of a log line.
* @var string
* @access private
*/
var $_lineFormat = '%1$s %2$s [%3$s] %4$s';
/**
* String containing the timestamp format. It will be passed directly to
* strftime(). Note that the timestamp string will generated using the
* current locale.
*
* @var string
* @access private
*/
var $_timeFormat = '%b %d %H:%M:%S';
/**
* Flag whether to throw PHP errors that have been converted to ErrorException
*
* @var boolean
* @access protected
*/
var $throwErrorExceptions;
/**
* Previous error handler defined by set_error_handler if any
*
* @var mixed
* @access protected
*/
var $oldErrorHandler;
/**
* Instance of PEAR::Net_Growl
*
* @var object
* @access protected
*/
var $growl;
/**
* Constructs a new Log_growl object.
*
* @param string $name Ignored.
* @param string $ident The identity string.
* @param array $conf The configuration array.
* @param int $level Log messages up to and including this level.
*
* @access public
*/
function Log_growl($name = '', $ident = 'PHP', $conf = array(),
$level = PEAR_LOG_DEBUG
) {
$this->_id = md5(microtime());
$this->_ident = $ident;
$this->_mask = Log::UPTO($level);
if (!empty($conf['lineFormat'])) {
$this->_lineFormat = str_replace(
array_keys($this->_formatMap),
array_values($this->_formatMap),
$conf['lineFormat']
);
}
if (!empty($conf['timeFormat'])) {
$this->_timeFormat = $conf['timeFormat'];
}
if (isset($conf['application'])) {
$applicationName = $conf['application'];
} else {
$applicationName = 'PEAR Log_growl';
}
$applicationName = str_replace(':', ' ', $applicationName);
if (isset($conf['notifications'])) {
$notifications = $conf['notifications'];
} else {
$notifications = array('All events');
}
if (isset($conf['password'])) {
$password = $conf['password'];
} else {
$password = '';
}
$options = array();
if (isset($conf['host'])) {
$options['host'] = $conf['host'];
}
if (isset($conf['port'])) {
$options['port'] = $conf['port'];
}
if (isset($conf['protocol'])) {
$options['protocol'] = $conf['protocol'];
}
$this->growl =& Net_Growl::singleton(
$applicationName, $notifications, $password, $options
);
}
/**
* Sends $message to Growl client listener. Also, passes the message
* along to any Log_observer instances that are observing this Log.
*
* @param mixed $message String or object containing the message to log.
* @param string $priority The priority of the message. Valid values are:
* PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
*
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
static $growlpriorities;
if (!isset($growlpriorities)) {
$growlpriorities = array(
GROWL_PRIORITY_LOW,
GROWL_PRIORITY_MODERATE,
GROWL_PRIORITY_NORMAL,
GROWL_PRIORITY_HIGH,
GROWL_PRIORITY_EMERGENCY
);
}
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}
/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}
/* Extract valid Growl components from $message parameter */
if (is_array($message)) {
if (isset($message['notification'])
&& is_string($message['notification'])
) {
$notification = $message['notification'];
} else {
$notification = 'All events';
}
if (isset($message['message'])) {
$object = $message['message'];
} else {
$object = null;
}
if (isset($message['title'])
&& is_string($message['title'])
) {
$title = $message['title'];
} else {
$title = 'Log Growl';
}
$options = array();
if (isset($message['priority'])
&& in_array($message['priority'], $growlpriorities)
) {
$options['priority'] = $message['priority'];
}
if (isset($message['sticky'])
&& is_bool($message['sticky'])
) {
$options['sticky'] = $message['sticky'];
}
} elseif (is_scalar($message)) {
$title = 'Log Growl';
$object = $message;
$notification = 'All events';
$options = array();
} elseif ($message instanceof Exception) {
$title = get_class($message);
$object = $message->getMessage();
$notification = 'All events';
$options = array(
'priority' => GROWL_PRIORITY_EMERGENCY,
'sticky' => true
);
} else {
return false;
}
if (!(isset($object) && is_string($object))) {
return false;
}
/* If message Growl priority is not defined,
used the mapped PEAR Log priority instead */
if (!isset($options['priority'])) {
switch ($priority) {
case PEAR_LOG_EMERG:
case PEAR_LOG_ALERT:
case PEAR_LOG_CRIT:
$options['priority'] = GROWL_PRIORITY_EMERGENCY;
break;
case PEAR_LOG_ERR:
case PEAR_LOG_WARNING:
$options['priority'] = GROWL_PRIORITY_HIGH;
break;
case PEAR_LOG_NOTICE:
case PEAR_LOG_INFO:
case PEAR_LOG_DEBUG:
$options['priority'] = GROWL_PRIORITY_NORMAL;
break;
}
}
if (!isset($options['sticky'])) {
$options['sticky'] = false;
}
/* Extract the string representation of the message. */
$message = $this->_extractMessage($object);
/* The return/line feed character sequence is used
as the end-of-line delimiter in the GNTP protocol. */
$message = str_replace("\r", "", $message);
/* Build the string containing the complete log line. */
$line = $this->_format(
$this->_lineFormat,
strftime($this->_timeFormat), $priority, $message
);
$success = $this->growl->notify($notification, $title, $line, $options);
/* Notify observers about this log message. */
$this->_announce(array('priority' => $priority, 'message' => $message));
return $success;
}
/**
* Register Growl driver as your error handler
*
* @param bool $throwErrorExceptions Convert PHP errors to ErrorException
* @param bool $replaceOldHandler Replace or chain with previous error handler
*
* @return mixed Returns a string containing the previously defined error handler
* (if any), or NULL on error. If the previous handler was
* a class method, this function will return an indexed array
* with the class and the method name.
* @access public
*/
function registerErrorHandler($throwErrorExceptions = false,
$replaceOldHandler = true
) {
$this->throwErrorExceptions = $throwErrorExceptions;
$old_error_handler = set_error_handler(array($this, 'errorHandler'));
$this->oldErrorHandler = ($replaceOldHandler ? null : $old_error_handler);
return $old_error_handler;
}
/**
* Log Growl's error handler
*
* @param int $errno contains the level of the error raised
* @param string $errstr contains the error message
* @param string $errfile contains the filename that the error was raised in
* @param int $errline contains the line number the error was raised at
* @param array $errcontext contain an array of every variable that existed
* in the scope the error was triggered in
*
* @return void
* @access public
*/
function errorHandler($errno, $errstr, $errfile, $errline, $errcontext)
{
// Only catch errors we are asking for
if ((error_reporting() & $errno) == 0) {
return;
}
/* Map the PHP error to a Log priority. */
switch ($errno) {
case E_WARNING:
case E_USER_WARNING:
$growlpriority = GROWL_PRIORITY_NORMAL;
$priority = PEAR_LOG_WARNING;
$sticky = false;
break;
case E_NOTICE:
case E_USER_NOTICE:
case E_STRICT:
$growlpriority = GROWL_PRIORITY_NORMAL;
$priority = PEAR_LOG_NOTICE;
$sticky = false;
break;
case E_ERROR:
case E_USER_ERROR:
$growlpriority = GROWL_PRIORITY_HIGH;
$priority = PEAR_LOG_ERR;
$sticky = true;
break;
default:
$growlpriority = GROWL_PRIORITY_NORMAL;
$priority = PEAR_LOG_INFO;
$sticky = false;
}
if ($this->throwErrorExceptions) {
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
} else {
$this->log(
array(
'message' => $errstr
. ' in ' . $errfile
. ' at line ' . $errline,
'priority' => $growlpriority,
'sticky' => $sticky
),
$priority
);
if (is_callable($this->oldErrorHandler)) {
// chained with previous error handler defined
call_user_func_array(
$this->oldErrorHandler,
array($errno, $errstr, $errfile, $errline)
);
}
}
}
/**
* Register Log Growl as your exception handler
*
* @return string|null Returns the name of the previously defined
* exception handler, or NULL on error. If no previous
* handler was defined, NULL is also returned.
* @access public
*/
function registerExceptionHandler()
{
return set_exception_handler(array($this, 'exceptionHandler'));
}
/**
* Log Growl's exception handler
*
* @param exception $exception contains the exception raised
*
* @return void
* @access public
*/
function exceptionHandler($exception)
{
header('HTTP/1.1 500 Internal Server Error');
$this->log($exception, PEAR_LOG_ALERT);
}
}
?>