2012-11-22 03:25:06 +00:00
|
|
|
<?php defined('SYSPATH') OR die('No direct script access.');
|
2011-01-13 14:49:56 +00:00
|
|
|
/**
|
|
|
|
* Message logging with observer-based log writing.
|
|
|
|
*
|
|
|
|
* [!!] This class does not support extensions, only additional writers.
|
|
|
|
*
|
|
|
|
* @package Kohana
|
|
|
|
* @category Logging
|
|
|
|
* @author Kohana Team
|
2012-11-22 03:25:06 +00:00
|
|
|
* @copyright (c) 2008-2012 Kohana Team
|
2011-01-13 14:49:56 +00:00
|
|
|
* @license http://kohanaframework.org/license
|
|
|
|
*/
|
|
|
|
class Kohana_Log {
|
|
|
|
|
2011-05-16 12:47:16 +00:00
|
|
|
// Log message levels - Windows users see PHP Bug #18090
|
|
|
|
const EMERGENCY = LOG_EMERG; // 0
|
|
|
|
const ALERT = LOG_ALERT; // 1
|
|
|
|
const CRITICAL = LOG_CRIT; // 2
|
|
|
|
const ERROR = LOG_ERR; // 3
|
|
|
|
const WARNING = LOG_WARNING; // 4
|
|
|
|
const NOTICE = LOG_NOTICE; // 5
|
|
|
|
const INFO = LOG_INFO; // 6
|
|
|
|
const DEBUG = LOG_DEBUG; // 7
|
|
|
|
|
2011-01-13 14:49:56 +00:00
|
|
|
/**
|
|
|
|
* @var boolean immediately write when logs are added
|
|
|
|
*/
|
|
|
|
public static $write_on_add = FALSE;
|
|
|
|
|
|
|
|
/**
|
2011-05-16 12:47:16 +00:00
|
|
|
* @var Log Singleton instance container
|
2011-01-13 14:49:56 +00:00
|
|
|
*/
|
2011-05-16 12:47:16 +00:00
|
|
|
protected static $_instance;
|
2011-01-13 14:49:56 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the singleton instance of this class and enable writing at shutdown.
|
|
|
|
*
|
2011-05-16 12:47:16 +00:00
|
|
|
* $log = Log::instance();
|
2011-01-13 14:49:56 +00:00
|
|
|
*
|
2011-05-16 12:47:16 +00:00
|
|
|
* @return Log
|
2011-01-13 14:49:56 +00:00
|
|
|
*/
|
|
|
|
public static function instance()
|
|
|
|
{
|
2011-05-16 12:47:16 +00:00
|
|
|
if (Log::$_instance === NULL)
|
2011-01-13 14:49:56 +00:00
|
|
|
{
|
|
|
|
// Create a new instance
|
2011-05-16 12:47:16 +00:00
|
|
|
Log::$_instance = new Log;
|
2011-01-13 14:49:56 +00:00
|
|
|
|
|
|
|
// Write the logs at shutdown
|
2011-05-16 12:47:16 +00:00
|
|
|
register_shutdown_function(array(Log::$_instance, 'write'));
|
2011-01-13 14:49:56 +00:00
|
|
|
}
|
|
|
|
|
2011-05-16 12:47:16 +00:00
|
|
|
return Log::$_instance;
|
2011-01-13 14:49:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var array list of added messages
|
|
|
|
*/
|
2011-05-16 12:47:16 +00:00
|
|
|
protected $_messages = array();
|
2011-01-13 14:49:56 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var array list of log writers
|
|
|
|
*/
|
2011-05-16 12:47:16 +00:00
|
|
|
protected $_writers = array();
|
2011-01-13 14:49:56 +00:00
|
|
|
|
|
|
|
/**
|
2011-05-16 12:47:16 +00:00
|
|
|
* Attaches a log writer, and optionally limits the levels of messages that
|
2011-01-13 14:49:56 +00:00
|
|
|
* will be written by the writer.
|
|
|
|
*
|
|
|
|
* $log->attach($writer);
|
|
|
|
*
|
2012-11-22 03:25:06 +00:00
|
|
|
* @param Log_Writer $writer instance
|
|
|
|
* @param mixed $levels array of messages levels to write OR max level to write
|
|
|
|
* @param integer $min_level min level to write IF $levels is not an array
|
2011-05-16 12:47:16 +00:00
|
|
|
* @return Log
|
2011-01-13 14:49:56 +00:00
|
|
|
*/
|
2011-05-16 12:47:16 +00:00
|
|
|
public function attach(Log_Writer $writer, $levels = array(), $min_level = 0)
|
2011-01-13 14:49:56 +00:00
|
|
|
{
|
2011-05-16 12:47:16 +00:00
|
|
|
if ( ! is_array($levels))
|
|
|
|
{
|
|
|
|
$levels = range($min_level, $levels);
|
|
|
|
}
|
|
|
|
|
2011-01-13 14:49:56 +00:00
|
|
|
$this->_writers["{$writer}"] = array
|
|
|
|
(
|
|
|
|
'object' => $writer,
|
2011-05-16 12:47:16 +00:00
|
|
|
'levels' => $levels
|
2011-01-13 14:49:56 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Detaches a log writer. The same writer object must be used.
|
|
|
|
*
|
|
|
|
* $log->detach($writer);
|
|
|
|
*
|
2012-11-22 03:25:06 +00:00
|
|
|
* @param Log_Writer $writer instance
|
2011-05-16 12:47:16 +00:00
|
|
|
* @return Log
|
2011-01-13 14:49:56 +00:00
|
|
|
*/
|
2011-05-16 12:47:16 +00:00
|
|
|
public function detach(Log_Writer $writer)
|
2011-01-13 14:49:56 +00:00
|
|
|
{
|
|
|
|
// Remove the writer
|
|
|
|
unset($this->_writers["{$writer}"]);
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Adds a message to the log. Replacement values must be passed in to be
|
|
|
|
* replaced using [strtr](http://php.net/strtr).
|
|
|
|
*
|
2011-05-16 12:47:16 +00:00
|
|
|
* $log->add(Log::ERROR, 'Could not locate user: :user', array(
|
2011-01-13 14:49:56 +00:00
|
|
|
* ':user' => $username,
|
|
|
|
* ));
|
|
|
|
*
|
2012-11-22 03:25:06 +00:00
|
|
|
* @param string $level level of message
|
|
|
|
* @param string $message message body
|
|
|
|
* @param array $values values to replace in the message
|
|
|
|
* @param array $additional additional custom parameters to supply to the log writer
|
2011-05-16 12:47:16 +00:00
|
|
|
* @return Log
|
2011-01-13 14:49:56 +00:00
|
|
|
*/
|
2012-11-22 03:25:06 +00:00
|
|
|
public function add($level, $message, array $values = NULL, array $additional = NULL)
|
2011-01-13 14:49:56 +00:00
|
|
|
{
|
|
|
|
if ($values)
|
|
|
|
{
|
|
|
|
// Insert the values into the message
|
|
|
|
$message = strtr($message, $values);
|
|
|
|
}
|
|
|
|
|
2012-11-22 03:25:06 +00:00
|
|
|
// Grab a copy of the trace
|
|
|
|
if (isset($additional['exception']))
|
|
|
|
{
|
|
|
|
$trace = $additional['exception']->getTrace();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Older php version don't have 'DEBUG_BACKTRACE_IGNORE_ARGS', so manually remove the args from the backtrace
|
|
|
|
if ( ! defined('DEBUG_BACKTRACE_IGNORE_ARGS'))
|
|
|
|
{
|
|
|
|
$trace = array_map(function ($item) {
|
|
|
|
unset($item['args']);
|
|
|
|
return $item;
|
|
|
|
}, array_slice(debug_backtrace(FALSE), 1));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$trace = array_slice(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($additional == NULL)
|
|
|
|
{
|
|
|
|
$additional = array();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a new message
|
2011-01-13 14:49:56 +00:00
|
|
|
$this->_messages[] = array
|
|
|
|
(
|
2012-11-22 03:25:06 +00:00
|
|
|
'time' => time(),
|
|
|
|
'level' => $level,
|
|
|
|
'body' => $message,
|
|
|
|
'trace' => $trace,
|
|
|
|
'file' => isset($trace[0]['file']) ? $trace[0]['file'] : NULL,
|
|
|
|
'line' => isset($trace[0]['line']) ? $trace[0]['line'] : NULL,
|
|
|
|
'class' => isset($trace[0]['class']) ? $trace[0]['class'] : NULL,
|
|
|
|
'function' => isset($trace[0]['function']) ? $trace[0]['function'] : NULL,
|
|
|
|
'additional' => $additional,
|
2011-01-13 14:49:56 +00:00
|
|
|
);
|
|
|
|
|
2011-05-16 12:47:16 +00:00
|
|
|
if (Log::$write_on_add)
|
2011-01-13 14:49:56 +00:00
|
|
|
{
|
|
|
|
// Write logs as they are added
|
|
|
|
$this->write();
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Write and clear all of the messages.
|
|
|
|
*
|
|
|
|
* $log->write();
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function write()
|
|
|
|
{
|
|
|
|
if (empty($this->_messages))
|
|
|
|
{
|
|
|
|
// There is nothing to write, move along
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Import all messages locally
|
|
|
|
$messages = $this->_messages;
|
|
|
|
|
|
|
|
// Reset the messages array
|
|
|
|
$this->_messages = array();
|
|
|
|
|
|
|
|
foreach ($this->_writers as $writer)
|
|
|
|
{
|
2011-05-16 12:47:16 +00:00
|
|
|
if (empty($writer['levels']))
|
2011-01-13 14:49:56 +00:00
|
|
|
{
|
|
|
|
// Write all of the messages
|
|
|
|
$writer['object']->write($messages);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Filtered messages
|
|
|
|
$filtered = array();
|
|
|
|
|
|
|
|
foreach ($messages as $message)
|
|
|
|
{
|
2011-05-16 12:47:16 +00:00
|
|
|
if (in_array($message['level'], $writer['levels']))
|
2011-01-13 14:49:56 +00:00
|
|
|
{
|
|
|
|
// Writer accepts this kind of message
|
|
|
|
$filtered[] = $message;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write the filtered messages
|
|
|
|
$writer['object']->write($filtered);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // End Kohana_Log
|