* @category Horde
* @license http://www.horde.org/licenses/bsd BSD
* @package Log
*
* @method void LOGLEVEL() LOGLEVEL($event) Log an event at LOGLEVEL, where LOGLEVEL has been added with addLevel() or already exists
* @method void emerg() emerg($event) Log an event at the EMERG log level
* @method void alert() alert($event) Log an event at the ALERT log level
* @method void crit() crit($event) Log an event at the CRIT log level
* @method void err() err($event) Log an event at the ERR log level
* @method void warn() warn($event) Log an event at the WARN log level
* @method void notice() notice($event) Log an event at the NOTICE log level
* @method void info() info($event) Log an event at the INFO log level
* @method void debug() debug($event) Log an event at the DEBUG log level
*/
class Horde_Log_Logger implements Serializable
{
/* Serialize version. */
const VERSION = 1;
/**
* Log levels where the keys are the level priorities and the values are
* the level names.
*
* @var array
*/
protected $_levels = array();
/**
* Horde_Log_Handler_Base objects.
*
* @var array
*/
protected $_handlers = array();
/**
* Horde_Log_Filter objects.
*
* @var array
*/
protected $_filters = array();
/**
* Constructor.
*
* @param Horde_Log_Handler_Base|null $handler Default handler.
*/
public function __construct($handler = null)
{
if (!is_null($handler)) {
$this->addHandler($handler);
}
$this->_init();
}
/**
* Serialize.
*
* @return string Serialized representation of this object.
*/
public function serialize()
{
return serialize(array(
self::VERSION,
$this->_filters,
$this->_handlers
));
}
/**
* Unserialize.
*
* @param string $data Serialized data.
*
* @throws Exception
*/
public function unserialize($data)
{
$data = @unserialize($data);
if (!is_array($data) ||
!isset($data[0]) ||
($data[0] != self::VERSION)) {
throw new Exception('Cache version change');
}
$this->_filters = $data[1];
$this->_handlers = $data[2];
$this->_init();
}
/**
* Initialization tasks.
*/
protected function _init()
{
$r = new ReflectionClass('Horde_Log');
$this->_levels = $r->getConstants();
}
/**
* Undefined method handler allows a shortcut:
*
* $log->levelName('message');
* instead of
* $log->log('message', Horde_Log_LEVELNAME);
*
*
* @param string $method Log level name.
* @param string $params Message to log.
*/
public function __call($method, $params)
{
$levelName = Horde_String::upper($method);
if (isset($this->_levels[$levelName])) {
$this->log(array_shift($params), $this->_levels[$levelName]);
} else {
throw new Horde_Log_Exception('Bad log level ' . $levelName);
}
}
/**
* Log a message at a level
*
* @param mixed $event Message to log, either an array or a string.
* @param integer $level Log level of message, required if $message is a
* string.
*/
public function log($event, $level = null)
{
if (empty($this->_handlers)) {
throw new Horde_Log_Exception('No handlers were added');
}
// Create an event array from the given arguments.
if (is_array($event)) {
// If we are passed an array, it must contain 'message'
// and 'level' indices.
if (!isset($event['message'])) {
throw new Horde_Log_Exception('Event array did not contain a message');
}
if (!isset($event['level'])) {
if (is_null($level)) {
throw new Horde_Log_Exception('Event array did not contain a log level');
}
$event['level'] = $level;
}
} else {
// Create an event array from the message and level
// arguments.
$event = array('message' => $event, 'level' => $level);
}
if (($level = array_search($event['level'], $this->_levels)) === false) {
throw new Horde_Log_Exception('Bad log level: ' . $event['level']);
}
// Fill in the level name and timestamp for filters, formatters,
// handlers.
$event['levelName'] = $level;
if (!isset($event['timestamp'])) {
$event['timestamp'] = date('c');
}
// If any global filter rejects the event, don't log it.
foreach ($this->_filters as $filter) {
if (!$filter->accept($event)) {
return;
}
}
foreach ($this->_handlers as $handler) {
$handler->log($event);
}
}
/**
* Does this logger have the level $name already?
*
* @param string $name The level name to check for.
*
* @return boolean Whether the logger already has the specific level
* name.
*/
public function hasLevel($name)
{
return isset($this->_levels[$name]);
}
/**
* Add a custom log level
*
* @param string $name Name of level.
* @param integer $level Numeric level.
*/
public function addLevel($name, $level)
{
// Log level names must be uppercase for predictability.
$name = Horde_String::upper($name);
if ($this->hasLevel($name)) {
throw new Horde_Log_Exception('Existing log levels cannot be overwritten');
}
$this->_levels[$name] = $level;
}
/**
* Add a filter that will be applied before all log handlers.
* Before a message will be received by any of the handlers, it
* must be accepted by all filters added with this method.
*
* @param Horde_Log_Filter $filter Filter to add.
*/
public function addFilter($filter)
{
$this->_filters[] = is_integer($filter)
? new Horde_Log_Filter_Level($filter)
: $filter;
}
/**
* Add a handler. A handler is responsible for taking a log
* message and writing it out to storage.
*
* @param Horde_Log_Handler_Base $handler Handler to add.
*/
public function addHandler($handler)
{
$this->_handlers[] = $handler;
}
}