silverstripe-framework/dev/Log.php
2014-08-19 09:17:15 +12:00

186 lines
5.7 KiB
PHP

<?php
require_once 'Zend/Log.php';
/**
* Wrapper class for a logging handler like {@link Zend_Log}
* which takes a message (or a map of context variables) and
* sends it to one or more {@link Zend_Log_Writer_Abstract}
* subclasses for output.
*
* These priorities are currently supported:
* - SS_Log::ERR
* - SS_Log::WARN
* - SS_Log::NOTICE
*
* You can add an error writer by calling {@link SS_Log::add_writer()}
*
* Example usage of logging errors by email notification:
* <code>
* SS_Log::add_writer(new SS_LogEmailWriter('my@email.com'), SS_Log::ERR);
* </code>
*
* Example usage of logging errors by file:
* <code>
* SS_Log::add_writer(new SS_LogFileWriter('/var/log/silverstripe/errors.log'), SS_Log::ERR);
* </code>
*
* Example usage of logging at warnings and errors by setting the priority to '<=':
* <code>
* SS_Log::add_writer(new SS_LogEmailWriter('my@email.com'), SS_Log::WARN, '<=');
* </code>
*
* Each writer object can be assigned a formatter. The formatter is
* responsible for formatting the message before giving it to the writer.
* {@link SS_LogErrorEmailFormatter} is such an example that formats errors
* into HTML for human readability in an email client.
*
* Formatters are added to writers like this:
* <code>
* $logEmailWriter = new SS_LogEmailWriter('my@email.com');
* $myEmailFormatter = new MyLogEmailFormatter();
* $logEmailWriter->setFormatter($myEmailFormatter);
* </code>
*
* @package framework
* @subpackage dev
*/
class SS_Log {
const ERR = Zend_Log::ERR;
const WARN = Zend_Log::WARN;
const NOTICE = Zend_Log::NOTICE;
const INFO = Zend_Log::INFO;
const DEBUG = Zend_Log::DEBUG;
/**
* Logger class to use.
* @see SS_Log::get_logger()
* @var string
*/
public static $logger_class = 'SS_ZendLog';
/**
* @see SS_Log::get_logger()
* @var object
*/
protected static $logger;
/**
* @var array Logs additional context from PHP's superglobals.
* Caution: Depends on logger implementation (mainly targeted at {@link SS_LogEmailWriter}).
* @see http://framework.zend.com/manual/en/zend.log.overview.html#zend.log.overview.understanding-fields
*/
protected static $log_globals = array(
'_SERVER' => array(
'HTTP_ACCEPT',
'HTTP_ACCEPT_CHARSET',
'HTTP_ACCEPT_ENCODING',
'HTTP_ACCEPT_LANGUAGE',
'HTTP_REFERRER',
'HTTP_USER_AGENT',
'HTTPS',
'REMOTE_ADDR',
),
);
/**
* Get the logger currently in use, or create a new one if it doesn't exist.
*
* @return object
*/
public static function get_logger() {
if(!static::$logger) {
// Create default logger
static::$logger = new static::$logger_class;
// Add default context (shouldn't change until the actual log event happens)
foreach(static::$log_globals as $globalName => $keys) {
foreach($keys as $key) {
$val = isset($GLOBALS[$globalName][$key]) ? $GLOBALS[$globalName][$key] : null;
static::$logger->setEventItem(sprintf('$%s[\'%s\']', $globalName, $key), $val);
}
}
}
return static::$logger;
}
/**
* Get all writers in use by the logger.
* @return array Collection of Zend_Log_Writer_Abstract instances
*/
public static function get_writers() {
return static::get_logger()->getWriters();
}
/**
* Remove all writers currently in use.
*/
public static function clear_writers() {
static::get_logger()->clearWriters();
}
/**
* Remove a writer instance from the logger.
* @param object $writer Zend_Log_Writer_Abstract instance
*/
public static function remove_writer($writer) {
static::get_logger()->removeWriter($writer);
}
/**
* Add a writer instance to the logger.
* @param object $writer Zend_Log_Writer_Abstract instance
* @param const $priority Priority. Possible values: SS_Log::ERR, SS_Log::WARN or SS_Log::NOTICE
* @param $comparison Priority comparison operator. Acts on the integer values of the error
* levels, where more serious errors are lower numbers. By default this is "=", which means only
* the given priority will be logged. Set to "<=" if you want to track errors of *at least*
* the given priority.
*/
public static function add_writer($writer, $priority = null, $comparison = '=') {
if($priority) $writer->addFilter(new Zend_Log_Filter_Priority($priority, $comparison));
static::get_logger()->addWriter($writer);
}
/**
* Dispatch a message by priority level.
*
* The message parameter can be either a string (a simple error
* message), or an array of variables. The latter is useful for passing
* along a list of debug information for the writer to handle, such as
* error code, error line, error context (backtrace).
*
* @param mixed $message Exception object or array of error context variables
* @param const $priority Priority. Possible values: SS_Log::ERR, SS_Log::WARN or SS_Log::NOTICE
* @param mixed $extras Extra information to log in event
*/
public static function log($message, $priority, $extras = null) {
if($message instanceof Exception) {
$message = array(
'errno' => '',
'errstr' => $message->getMessage(),
'errfile' => $message->getFile(),
'errline' => $message->getLine(),
'errcontext' => $message->getTrace()
);
} elseif(is_string($message)) {
$trace = SS_Backtrace::filtered_backtrace();
$lastTrace = $trace[0];
$message = array(
'errno' => '',
'errstr' => $message,
'errfile' => isset($lastTrace['file']) ? $lastTrace['file'] : null,
'errline' => isset($lastTrace['line']) ? $lastTrace['line'] : null,
'errcontext' => $trace
);
}
try {
static::get_logger()->log($message, $priority, $extras);
} catch(Exception $e) {
// @todo How do we handle exceptions thrown from Zend_Log?
// For example, an exception is thrown if no writers are added
}
}
}