API CHANGE Added SSLogFileWriter to replace Debug::log_errors_to() and Debug::log_error_if_necessary() - the existing formatting for the Debug deprecation functions is now wrapped into SSLogErrorFileFormatter

MINOR Moved SSErrorLogTest to SSLogTest
MINOR Documentation updates for SSLog and other bits and pieces



git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@84828 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Sean Harvey 2009-08-19 21:55:03 +00:00
parent c4dcf4f2d3
commit 2cca0b0a7b
7 changed files with 190 additions and 34 deletions

View File

@ -224,7 +224,9 @@ class Debug {
*/
static function warningHandler($errno, $errstr, $errfile, $errline, $errcontext) {
if(error_reporting() == 0) return;
if(self::$send_warnings_to) self::emailError(self::$send_warnings_to, $errno, $errstr, $errfile, $errline, $errcontext, "Warning");
if(self::$send_warnings_to) {
self::emailError(self::$send_warnings_to, $errno, $errstr, $errfile, $errline, $errcontext, "Warning");
}
// Send out the error details to the logger for writing
SSLog::log(
@ -238,7 +240,9 @@ class Debug {
SSLog::WARN
);
if(self::$log_errors_to) {
self::log_error_if_necessary( $errno, $errstr, $errfile, $errline, $errcontext, "Warning");
}
if(Director::isDev()) {
self::showError($errno, $errstr, $errfile, $errline, $errcontext, "Warning");
@ -257,7 +261,9 @@ class Debug {
* @param unknown_type $errcontext
*/
static function fatalHandler($errno, $errstr, $errfile, $errline, $errcontext) {
if(self::$send_errors_to) self::emailError(self::$send_errors_to, $errno, $errstr, $errfile, $errline, $errcontext, "Error");
if(self::$send_errors_to) {
self::emailError(self::$send_errors_to, $errno, $errstr, $errfile, $errline, $errcontext, "Error");
}
// Send out the error details to the logger for writing
SSLog::log(
@ -271,7 +277,9 @@ class Debug {
SSLog::ERR
);
if(self::$log_errors_to) {
self::log_error_if_necessary( $errno, $errstr, $errfile, $errline, $errcontext, "Error");
}
if(Director::isDev() || Director::is_cli()) {
self::showError($errno, $errstr, $errfile, $errline, $errcontext, "Error");
@ -422,7 +430,7 @@ class Debug {
*/
static function emailError($emailAddress, $errno, $errstr, $errfile, $errline, $errcontext, $errorType = "Error") {
user_error('Debug::send_errors_to() and Debug::emailError() is deprecated. Please use SSLog instead.
See the class documentation for SSLog for more information.', E_USER_NOTICE);
See the class documentation in SSLog.php for more information.', E_USER_NOTICE);
$priority = ($errorType == 'Error') ? SSLog::ERR : SSLog::WARN;
$writer = new SSLogEmailWriter($emailAddress);
SSLog::add_writer($writer, $priority);
@ -447,22 +455,25 @@ class Debug {
*
* @todo Detect script path for CLI errors
* @todo Log detailed errors to full file
* @deprecated 2.5 See SSLog on setting up error file logging
*/
protected static function log_error_if_necessary($errno, $errstr, $errfile, $errline, $errcontext, $errtype) {
if(self::$log_errors_to) {
$shortFile = "../" . self::$log_errors_to;
$fullFile = $shortFile . '.full';
$relfile = Director::makeRelative($errfile);
if($relfile[0] == '/') $relfile = substr($relfile,1);
$urlSuffix = "";
if(isset($_SERVER['HTTP_HOST']) && $_SERVER['HTTP_HOST'] && isset($_SERVER['REQUEST_URI'])) {
$urlSuffix = " (http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI])";
}
error_log('[' . date('d-M-Y h:i:s') . "] $errtype at $relfile line $errline: $errstr$urlSuffix\n", 3, $shortFile);
}
user_error('Debug::log_error_if_necessary() and Debug::log_errors_to() are deprecated. Please use SSLog instead.
See the class documentation in SSLog.php for more information.', E_USER_NOTICE);
$priority = ($errtype == 'Error') ? SSLog::ERR : SSLog::WARN;
$writer = new SSLogFileWriter('../' . self::$log_errors_to);
SSLog::add_writer($writer, $priority);
SSLog::log(
array(
'errno' => $errno,
'errstr' => $errstr,
'errfile' => $errfile,
'errline' => $errline,
'errcontext' => $errcontext
),
$priority
);
SSLog::remove_writer($writer);
}
/**
@ -522,6 +533,7 @@ class Debug {
/**
* Call this to enable logging of errors.
* @deprecated 2.5 See SSLog on setting up error file logging
*/
static function log_errors_to($logFile = ".sserrors") {
self::$log_errors_to = $logFile;

View File

@ -12,11 +12,28 @@
*
* You can add an error writer by calling {@link SSLog::add_writer()}
*
* Example usage (called from mysite/_config.php) which adds a writer
* that will write all errors:
* Example usage of logging errors by email notification:
* <code>
* $emailWriter = new SSErrorEmailWriter('my@email.com');
* SSLog::add_writer($emailWriter, SSLog::ERR);
* $logEmailWriter = new SSErrorEmailWriter('my@email.com');
* SSLog::add_writer($logEmailWriter, SSLog::ERR);
* </code>
*
* Example usage of logging errors by file:
* <code>
* $logFileWriter = new SSLogFileWriter('/var/log/silverstripe/errors.log');
* SSLog::add_writer($logFileWriter, SSLog::ERR);
* </code>
*
* Each writer object can be assigned a formatter. The formatter is
* responsible for formatting the message before giving it to the writer.
* {@link SSLogErrorEmailFormatter} 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 SSErrorEmailWriter('my@email.com');
* $myEmailFormatter = new MyLogEmailFormatter();
* $logEmailWriter->setFormatter($myEmailFormatter);
* </code>
*
* @package sapphire
@ -65,6 +82,13 @@ class SSLog {
return self::get_logger()->getWriters();
}
/**
* Remove all writers currently in use.
*/
public static function clear_writers() {
self::get_logger()->clearWriters();
}
/**
* Remove a writer instance from the logger.
* @param object $writer Zend_Log_Writer_Abstract instance

View File

@ -23,8 +23,8 @@ class SSLogEmailWriter extends Zend_Log_Writer_Abstract {
}
/**
* Send an email to the designated emails set in
* {@link Debug::send_errors_to()}
* Send an email to the email address set in
* this writer.
*/
public function _write($event) {
// If no formatter set up, use the default

View File

@ -0,0 +1,42 @@
<?php
/**
* Formats SS error entries in an error file log.
* Format: [d-M-Y h:i:s] <type> at <file> line <line>: <errormessage> <url>
* @package sapphire
* @subpackage dev
*/
require_once 'Zend/Log/Formatter/Interface.php';
class SSLogErrorFileFormatter implements Zend_Log_Formatter_Interface {
public function format($event) {
$errno = $event['message']['errno'];
$errstr = $event['message']['errstr'];
$errfile = $event['message']['errfile'];
$errline = $event['message']['errline'];
$errcontext = $event['message']['errcontext'];
switch($event['priorityName']) {
case 'ERR':
$errtype = 'Error';
break;
case 'WARN':
$errtype = 'Warning';
break;
case 'NOTICE':
$errtype = 'Notice';
break;
}
$urlSuffix = '';
$relfile = Director::makeRelative($errfile);
if($relfile[0] == '/') $relfile = substr($relfile, 1);
if(isset($_SERVER['HTTP_HOST']) && $_SERVER['HTTP_HOST'] && isset($_SERVER['REQUEST_URI'])) {
$urlSuffix = " (http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI])";
}
return '[' . date('d-M-Y h:i:s') . "] $errtype at $relfile line $errline: $errstr$urlSuffix\n";
}
}

62
dev/SSLogFileWriter.php Normal file
View File

@ -0,0 +1,62 @@
<?php
/**
* Sends an error message to an email whenever an
* error occurs in sapphire.
*
* Note: You need to make sure your web server is able
* to write to the file path that you specify to write
* logs to.
*
* @uses error_log() built-in PHP function.
* @see SSLog for more information on using writers.
*
* @package sapphire
* @subpackage dev
*/
require_once 'Zend/Log/Writer/Abstract.php';
class SSLogFileWriter extends Zend_Log_Writer_Abstract {
/**
* The path to the file that errors will be stored in.
* For example, "/var/logs/silverstripe/errors.log".
*
* @var string
*/
protected $path;
/**
* Message type to pass to error_log()
* @see http://us3.php.net/manual/en/function.error-log.php
* @var int
*/
protected $messageType;
/**
* Extra headers to pass to error_log()
* @see http://us3.php.net/manual/en/function.error-log.php
* @var string
*/
protected $extraHeaders;
public function __construct($path, $messageType = 3, $extraHeaders = '') {
$this->path = $path;
$this->messageType = $messageType;
$this->extraHeaders = $extraHeaders;
}
/**
* Write the log message to the file path set
* in this writer.
*/
public function _write($event) {
if(!$this->_formatter) {
$formatter = new SSLogErrorFileFormatter();
$this->setFormatter($formatter);
}
$message = $this->_formatter->format($event);
error_log($message, $this->messageType, $this->path, $this->extraHeaders);
}
}

View File

@ -1,10 +1,10 @@
<?php
/**
* Modifications to Zend_Log to make it work nicer
* with {@link SSLog}. Specifically, this includes removing
* writers that have been added to the logger, as well as
* listing which ones are currently in use since the Zend_Log
* API does not support these methods.
* Extensions to Zend_Log to make it work nicer
* with {@link SSLog}.
*
* Please refer to {@link SSLog} for information on
* setting up logging for your projects.
*
* @package sapphire
* @subpackage dev
@ -14,14 +14,16 @@ require_once 'Zend/Log.php';
class SSZendLog extends Zend_Log {
/**
* Get all writers in this logger.
* @return array of Zend_Log_Writer_Abstract instances
*/
public function getWriters() {
return $this->_writers;
}
/**
* Remove a writer instance that exists in
* the current writers collection for this logger.
*
* Remove a writer instance that exists in this logger.
* @param object Zend_Log_Writer_Abstract instance
*/
public function removeWriter($writer) {
@ -32,4 +34,11 @@ class SSZendLog extends Zend_Log {
}
}
/**
* Clear all writers in this logger.
*/
public function clearWriters() {
$this->_writers = array();
}
}

View File

@ -9,20 +9,27 @@ class SSLogTest extends SapphireTest {
function setUp() {
parent::setUp();
SSLog::clear_writers(); // this test will break if existing writers are available!
$this->testEmailWriter = new SSLogEmailWriter('sean@silverstripe.com');
$this->testFileWriter = new SSLogFileWriter('../test.log');
SSLog::add_writer($this->testEmailWriter, SSLog::ERR);
SSLog::add_writer($this->testFileWriter, SSLog::WARN);
}
function testExistingWriter() {
$writers = SSLog::get_writers();
$this->assertType('array', $writers);
$this->assertEquals(1, count($writers));
$this->assertEquals(2, count($writers));
}
function testRemoveWriter() {
SSLog::remove_writer($this->testEmailWriter);
$writers = SSLog::get_writers();
$this->assertType('array', $writers);
$this->assertEquals(1, count($writers));
SSLog::remove_writer($this->testFileWriter);
$writers = SSLog::get_writers();
$this->assertType('array', $writers);
$this->assertEquals(0, count($writers));
}