mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 12:05:37 +00:00
API CHANGE Moved Debug::backtrace() to SSBacktrace::backtrace()
API CHANGE Moved Debug::get_rendered_backtrace() to SSBacktrace::get_rendered_backtrace() ENHANCEMENT Added SSLog, SSLogEmailWriter and SSLogErrorEmailFormatter for silverstripe message reporting API CHANGE Debug::send_errors_to() and Debug::send_warnings_to() are deprecated in favour of SSLog. See class documentation for SSLog on configuration of error email notifications MINOR Added SSLogTest for basic testing of the SSLog and SSLogEmailWriter classes git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@84774 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
26ff1f9264
commit
a682ab9c0e
148
dev/Debug.php
148
dev/Debug.php
@ -216,8 +216,21 @@ class Debug {
|
|||||||
* @param unknown_type $errcontext
|
* @param unknown_type $errcontext
|
||||||
*/
|
*/
|
||||||
static function warningHandler($errno, $errstr, $errfile, $errline, $errcontext) {
|
static function warningHandler($errno, $errstr, $errfile, $errline, $errcontext) {
|
||||||
if(error_reporting() == 0) return;
|
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(
|
||||||
|
array(
|
||||||
|
'errno' => $errno,
|
||||||
|
'errstr' => $errstr,
|
||||||
|
'errfile' => $errfile,
|
||||||
|
'errline' => $errline,
|
||||||
|
'errcontext' => $errcontext
|
||||||
|
),
|
||||||
|
SSLog::WARN
|
||||||
|
);
|
||||||
|
|
||||||
self::log_error_if_necessary( $errno, $errstr, $errfile, $errline, $errcontext, "Warning");
|
self::log_error_if_necessary( $errno, $errstr, $errfile, $errline, $errcontext, "Warning");
|
||||||
|
|
||||||
if(Director::isDev()) {
|
if(Director::isDev()) {
|
||||||
@ -237,12 +250,24 @@ class Debug {
|
|||||||
* @param unknown_type $errcontext
|
* @param unknown_type $errcontext
|
||||||
*/
|
*/
|
||||||
static function fatalHandler($errno, $errstr, $errfile, $errline, $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(
|
||||||
|
array(
|
||||||
|
'errno' => $errno,
|
||||||
|
'errstr' => $errstr,
|
||||||
|
'errfile' => $errfile,
|
||||||
|
'errline' => $errline,
|
||||||
|
'errcontext' => $errcontext
|
||||||
|
),
|
||||||
|
SSLog::ERR
|
||||||
|
);
|
||||||
|
|
||||||
self::log_error_if_necessary( $errno, $errstr, $errfile, $errline, $errcontext, "Error");
|
self::log_error_if_necessary( $errno, $errstr, $errfile, $errline, $errcontext, "Error");
|
||||||
|
|
||||||
if(Director::isDev() || Director::is_cli()) {
|
if(Director::isDev() || Director::is_cli()) {
|
||||||
Debug::showError($errno, $errstr, $errfile, $errline, $errcontext, "Error");
|
self::showError($errno, $errstr, $errfile, $errline, $errcontext, "Error");
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Debug::friendlyError();
|
Debug::friendlyError();
|
||||||
@ -373,7 +398,12 @@ class Debug {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispatch an email notification message when an error is triggered.
|
* Dispatch an email notification message when an error is triggered.
|
||||||
* Uses the native PHP mail() function.
|
* @deprecated 2.5
|
||||||
|
* To create error logs by email, use this code instead:
|
||||||
|
* <code>
|
||||||
|
* $emailWriter = new SSLogEmailWriter('my@email.com');
|
||||||
|
* SSLog::add_writer($emailWriter, SSLog::ERR);
|
||||||
|
* </code>
|
||||||
*
|
*
|
||||||
* @param string $emailAddress
|
* @param string $emailAddress
|
||||||
* @param string $errno
|
* @param string $errno
|
||||||
@ -385,25 +415,22 @@ class Debug {
|
|||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
static function emailError($emailAddress, $errno, $errstr, $errfile, $errline, $errcontext, $errorType = "Error") {
|
static function emailError($emailAddress, $errno, $errstr, $errfile, $errline, $errcontext, $errorType = "Error") {
|
||||||
if(strtolower($errorType) == 'warning') {
|
user_error('Debug::send_errors_to() and Debug::emailError() is deprecated. Please use SSLog instead.
|
||||||
$colour = "orange";
|
See the class documentation for SSLog for more information.', E_USER_NOTICE);
|
||||||
} else {
|
$priority = ($errorType == 'Error') ? SSLog::ERR : SSLog::WARN;
|
||||||
$colour = "red";
|
$writer = new SSLogEmailWriter($emailAddress);
|
||||||
}
|
SSLog::add_writer($writer, $priority);
|
||||||
|
SSLog::log(
|
||||||
$data = "<div style=\"border: 5px $colour solid\">\n";
|
array(
|
||||||
$data .= "<p style=\"color: white; background-color: $colour; margin: 0\">$errorType: $errstr<br /> At line $errline in $errfile\n<br />\n<br />\n</p>\n";
|
'errno' => $errno,
|
||||||
|
'errstr' => $errstr,
|
||||||
$data .= Debug::backtrace(true);
|
'errfile' => $errfile,
|
||||||
$data .= "</div>\n";
|
'errline' => $errline,
|
||||||
|
'errcontext' => $errcontext
|
||||||
// override smtp-server if needed
|
),
|
||||||
if(self::$custom_smtp_server) ini_set("SMTP", self::$custom_smtp_server);
|
$priority
|
||||||
|
);
|
||||||
$relfile = Director::makeRelative($errfile);
|
SSLog::remove_writer($writer);
|
||||||
if($relfile[0] == '/') $relfile = substr($relfile,1);
|
|
||||||
|
|
||||||
return mail($emailAddress, "$errorType at $relfile line $errline (http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI])", $data, "Content-type: text/html\nFrom: errors@silverstripe.com");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -498,82 +525,19 @@ class Debug {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render or return a backtrace from the given scope.
|
* @deprecated 2.5 Please use {@link SSBacktrace::backtrace()}
|
||||||
*
|
|
||||||
* @param unknown_type $returnVal
|
|
||||||
* @param unknown_type $ignoreAjax
|
|
||||||
* @return unknown
|
|
||||||
*/
|
*/
|
||||||
static function backtrace($returnVal = false, $ignoreAjax = false) {
|
static function backtrace($returnVal = false, $ignoreAjax = false) {
|
||||||
$bt = debug_backtrace();
|
user_error('Debug::backtrace() is deprecated. Please use SSBacktrace::backtrace() instead', E_USER_NOTICE);
|
||||||
$result = self::get_rendered_backtrace($bt, Director::is_cli() || (Director::is_ajax() && !$ignoreAjax));
|
return SSBacktrace::backtrace($returnVal, $ignoreAjax);
|
||||||
if ($returnVal) {
|
|
||||||
return $result;
|
|
||||||
} else {
|
|
||||||
echo $result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render a backtrace array into an appropriate plain-text or HTML string.
|
* @deprecated 2.5 Please use {@link SSBacktrace::get_rendered_backtrace()}
|
||||||
* @param $bt The trace array, as returned by debug_backtrace() or Exception::getTrace().
|
|
||||||
* @param $plainText Set to false for HTML output, or true for plain-text output
|
|
||||||
*/
|
*/
|
||||||
static function get_rendered_backtrace($bt, $plainText = false) {
|
static function get_rendered_backtrace($bt, $plainText = false) {
|
||||||
// Ingore functions that are plumbing of the error handler
|
user_error('Debug::get_rendered_backtrace() is deprecated. Please use SSBacktrace::get_rendered_backtrace() instead', E_USER_NOTICE);
|
||||||
$ignoredFunctions = array('DebugView->writeTrace', 'CliDebugView->writeTrace',
|
return SSBacktrace::get_rendered_backtrace($bt, $plainText);
|
||||||
'Debug::emailError','Debug::warningHandler','Debug::fatalHandler','errorHandler','Debug::showError',
|
|
||||||
'Debug::backtrace', 'exceptionHandler');
|
|
||||||
|
|
||||||
while( $bt && in_array(self::full_func_name($bt[0]), $ignoredFunctions) ) {
|
|
||||||
array_shift($bt);
|
|
||||||
}
|
|
||||||
|
|
||||||
$result = "<ul>";
|
|
||||||
foreach($bt as $item) {
|
|
||||||
if($plainText) {
|
|
||||||
$result .= self::full_func_name($item,true) . "\n";
|
|
||||||
if(isset($item['line']) && isset($item['file'])) $result .= "line $item[line] of " . basename($item['file']) . "\n";
|
|
||||||
$result .= "\n";
|
|
||||||
} else {
|
|
||||||
if ($item['function'] == 'user_error') {
|
|
||||||
$name = $item['args'][0];
|
|
||||||
} else {
|
|
||||||
$name = self::full_func_name($item,true);
|
|
||||||
}
|
|
||||||
$result .= "<li><b>" . htmlentities($name) . "</b>\n<br />\n";
|
|
||||||
$result .= isset($item['line']) ? "Line $item[line] of " : '';
|
|
||||||
$result .= isset($item['file']) ? htmlentities(basename($item['file'])) : '';
|
|
||||||
$result .= "</li>\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$result .= "</ul>";
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the full function name. If showArgs is set to true, a string representation of the arguments will be shown
|
|
||||||
*/
|
|
||||||
static function full_func_name($item, $showArgs = false) {
|
|
||||||
$funcName = '';
|
|
||||||
if(isset($item['class'])) $funcName .= $item['class'];
|
|
||||||
if(isset($item['type'])) $funcName .= $item['type'];
|
|
||||||
if(isset($item['function'])) $funcName .= $item['function'];
|
|
||||||
|
|
||||||
if($showArgs && isset($item['args'])) {
|
|
||||||
$args = array();
|
|
||||||
foreach($item['args'] as $arg) {
|
|
||||||
if(!is_object($arg) || method_exists($arg, '__toString')) {
|
|
||||||
$args[] = (string) $arg;
|
|
||||||
} else {
|
|
||||||
$args[] = get_class($arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$funcName .= "(" . implode(",", $args) .")";
|
|
||||||
}
|
|
||||||
|
|
||||||
return $funcName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
132
dev/SSBacktrace.php
Normal file
132
dev/SSBacktrace.php
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @package sapphire
|
||||||
|
* @subpackage dev
|
||||||
|
*/
|
||||||
|
class SSBacktrace {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return debug_backtrace() results with functions filtered
|
||||||
|
* specific to the debugging system, and not the trace.
|
||||||
|
*
|
||||||
|
* @param null|array $ignoredFunctions If an array, filter these functions out of the trace
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
static function filtered_backtrace($ignoredFunctions = null) {
|
||||||
|
return self::filter_backtrace(debug_backtrace(), $ignoredFunctions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter a backtrace so that it doesn't show the calls to the
|
||||||
|
* debugging system, which is useless information.
|
||||||
|
*
|
||||||
|
* @param array $bt Backtrace to filter
|
||||||
|
* @param null|array $ignoredFunctions List of extra functions to filter out
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
static function filter_backtrace($bt, $ignoredFunctions = null) {
|
||||||
|
$defaultIgnoredFunctions = array(
|
||||||
|
'SSLog::log',
|
||||||
|
'SSBacktrace::backtrace',
|
||||||
|
'SSBacktrace::filtered_backtrace',
|
||||||
|
'Zend_Log_Writer_Abstract->write',
|
||||||
|
'Zend_Log->log',
|
||||||
|
'Zend_Log->__call',
|
||||||
|
'Zend_Log->err',
|
||||||
|
'DebugView->writeTrace',
|
||||||
|
'CliDebugView->writeTrace',
|
||||||
|
'Debug::emailError',
|
||||||
|
'Debug::warningHandler',
|
||||||
|
'Debug::fatalHandler',
|
||||||
|
'errorHandler',
|
||||||
|
'Debug::showError',
|
||||||
|
'Debug::backtrace',
|
||||||
|
'exceptionHandler'
|
||||||
|
);
|
||||||
|
|
||||||
|
if($ignoredFunctions) foreach($ignoredFunctions as $ignoredFunction) {
|
||||||
|
$defaultIgnoredFunctions[] = $ignoredFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
while($bt && in_array(self::full_func_name($bt[0]), $defaultIgnoredFunctions)) {
|
||||||
|
array_shift($bt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $bt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render or return a backtrace from the given scope.
|
||||||
|
*
|
||||||
|
* @param unknown_type $returnVal
|
||||||
|
* @param unknown_type $ignoreAjax
|
||||||
|
* @return unknown
|
||||||
|
*/
|
||||||
|
static function backtrace($returnVal = false, $ignoreAjax = false, $ignoredFunctions = null) {
|
||||||
|
$plainText = Director::is_cli() || (Director::is_ajax() && !$ignoreAjax);
|
||||||
|
$result = self::get_rendered_backtrace(debug_backtrace(), $plainText, $ignoredFunctions);
|
||||||
|
if($returnVal) {
|
||||||
|
return $result;
|
||||||
|
} else {
|
||||||
|
echo $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the full function name. If showArgs is set to true, a string representation of the arguments will be shown
|
||||||
|
*/
|
||||||
|
static function full_func_name($item, $showArgs = false) {
|
||||||
|
$funcName = '';
|
||||||
|
if(isset($item['class'])) $funcName .= $item['class'];
|
||||||
|
if(isset($item['type'])) $funcName .= $item['type'];
|
||||||
|
if(isset($item['function'])) $funcName .= $item['function'];
|
||||||
|
|
||||||
|
if($showArgs && isset($item['args'])) {
|
||||||
|
$args = array();
|
||||||
|
foreach($item['args'] as $arg) {
|
||||||
|
if(!is_object($arg) || method_exists($arg, '__toString')) {
|
||||||
|
$args[] = (string) $arg;
|
||||||
|
} else {
|
||||||
|
$args[] = get_class($arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$funcName .= "(" . implode(",", $args) .")";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $funcName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render a backtrace array into an appropriate plain-text or HTML string.
|
||||||
|
*
|
||||||
|
* @param string $bt The trace array, as returned by debug_backtrace() or Exception::getTrace()
|
||||||
|
* @param boolean $plainText Set to false for HTML output, or true for plain-text output
|
||||||
|
* @param array List of functions that should be ignored. If not set, a default is provided
|
||||||
|
* @return string The rendered backtrace
|
||||||
|
*/
|
||||||
|
static function get_rendered_backtrace($bt, $plainText = false, $ignoredFunctions = null) {
|
||||||
|
$bt = self::filter_backtrace($bt, $ignoredFunctions);
|
||||||
|
$result = "<ul>";
|
||||||
|
foreach($bt as $item) {
|
||||||
|
if($plainText) {
|
||||||
|
$result .= self::full_func_name($item,true) . "\n";
|
||||||
|
if(isset($item['line']) && isset($item['file'])) $result .= "line $item[line] of " . basename($item['file']) . "\n";
|
||||||
|
$result .= "\n";
|
||||||
|
} else {
|
||||||
|
if ($item['function'] == 'user_error') {
|
||||||
|
$name = $item['args'][0];
|
||||||
|
} else {
|
||||||
|
$name = self::full_func_name($item,true);
|
||||||
|
}
|
||||||
|
$result .= "<li><b>" . htmlentities($name) . "</b>\n<br />\n";
|
||||||
|
$result .= isset($item['line']) ? "Line $item[line] of " : '';
|
||||||
|
$result .= isset($item['file']) ? htmlentities(basename($item['file'])) : '';
|
||||||
|
$result .= "</li>\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$result .= "</ul>";
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
103
dev/SSLog.php
Normal file
103
dev/SSLog.php
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<?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.
|
||||||
|
*
|
||||||
|
* The only priorities currently supported are SSLog::ERR and
|
||||||
|
* SSLog::WARN - this may change in the future if other types
|
||||||
|
* are to be supported.
|
||||||
|
*
|
||||||
|
* You can add an error writer by calling {@link SSLog::add_writer()}
|
||||||
|
*
|
||||||
|
* Example usage (called from mysite/_config.php):
|
||||||
|
* <code>
|
||||||
|
* $emailWriter = new SSErrorEmailWriter('my@email.com');
|
||||||
|
* SSLog::add_writer($emailWriter, SSLog::ERR);
|
||||||
|
* </code>
|
||||||
|
*
|
||||||
|
* @package sapphire
|
||||||
|
* @subpackage dev
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once 'Zend/Log.php';
|
||||||
|
|
||||||
|
class SSLog {
|
||||||
|
|
||||||
|
const ERR = Zend_Log::ERR;
|
||||||
|
const WARN = Zend_Log::WARN;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logger class to use.
|
||||||
|
* @see SSLog::get_logger()
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public static $logger_class = 'SSZendLog';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see SSLog::get_logger()
|
||||||
|
* @var object
|
||||||
|
*/
|
||||||
|
protected static $logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the logger currently in use, or create a new
|
||||||
|
* one if it doesn't exist.
|
||||||
|
*
|
||||||
|
* @return object
|
||||||
|
*/
|
||||||
|
public static function get_logger() {
|
||||||
|
if(!self::$logger) {
|
||||||
|
self::$logger = new self::$logger_class;
|
||||||
|
}
|
||||||
|
return self::$logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all writers in use by the logger.
|
||||||
|
* @return array Collection of Zend_Log_Writer_Abstract instances
|
||||||
|
*/
|
||||||
|
public static function get_writers() {
|
||||||
|
return self::get_logger()->getWriters();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a writer instance from the logger.
|
||||||
|
* @param object $writer Zend_Log_Writer_Abstract instance
|
||||||
|
*/
|
||||||
|
public static function remove_writer($writer) {
|
||||||
|
self::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: SSLog::ERR or SSLog::WARN
|
||||||
|
*/
|
||||||
|
public static function add_writer($writer, $priority = null) {
|
||||||
|
if($priority) $writer->addFilter(new Zend_Log_Filter_Priority($priority, '='));
|
||||||
|
self::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 string|array $message String of error message, or array of variables
|
||||||
|
* @param const $priority Priority. Possible values: SSLog::ERR or SSLog::WARN
|
||||||
|
*/
|
||||||
|
public static function log($message, $priority) {
|
||||||
|
try {
|
||||||
|
self::get_logger()->log($message, $priority);
|
||||||
|
} catch(Exception $e) {
|
||||||
|
// @todo How do we handle exceptions thrown from Zend_Log?
|
||||||
|
// For example, an exception is thrown if no writers are added
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
48
dev/SSLogEmailWriter.php
Normal file
48
dev/SSLogEmailWriter.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Sends an error message to an email whenever an error occurs
|
||||||
|
* in sapphire.
|
||||||
|
*
|
||||||
|
* @package sapphire
|
||||||
|
* @subpackage dev
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once 'Zend/Log/Writer/Abstract.php';
|
||||||
|
|
||||||
|
class SSLogEmailWriter extends Zend_Log_Writer_Abstract {
|
||||||
|
|
||||||
|
protected $emailAddress;
|
||||||
|
|
||||||
|
protected $customSmtpServer;
|
||||||
|
|
||||||
|
public function __construct($emailAddress, $customSmtpServer = false) {
|
||||||
|
$this->emailAddress = $emailAddress;
|
||||||
|
$this->customSmtpServer = $customSmtpServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an email to the designated emails set in
|
||||||
|
* {@link Debug::send_errors_to()}
|
||||||
|
*/
|
||||||
|
public function _write($event) {
|
||||||
|
// If no formatter set up, use the default
|
||||||
|
if(!$this->_formatter) {
|
||||||
|
$formatter = new SSLogErrorEmailFormatter();
|
||||||
|
$this->setFormatter($formatter);
|
||||||
|
}
|
||||||
|
|
||||||
|
$formattedData = $this->_formatter->format($event);
|
||||||
|
$subject = $formattedData['subject'];
|
||||||
|
$data = $formattedData['data'];
|
||||||
|
|
||||||
|
$originalSMTP = ini_get('SMTP');
|
||||||
|
// override the SMTP server with a custom one if required
|
||||||
|
if($this->customSmtpServer) ini_set('SMTP', $this->customSmtpServer);
|
||||||
|
|
||||||
|
mail($this->emailAddress, $subject, $data, "Content-type: text/html\nFrom: errors@silverstripe.com");
|
||||||
|
|
||||||
|
// reset the SMTP server to the original
|
||||||
|
if($this->customSmtpServer) ini_set('SMTP', $originalSMTP);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
52
dev/SSLogErrorEmailFormatter.php
Normal file
52
dev/SSLogErrorEmailFormatter.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Formats SS error emails with a basic layout.
|
||||||
|
* @package sapphire
|
||||||
|
* @subpackage dev
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once 'Zend/Log/Formatter/Interface.php';
|
||||||
|
|
||||||
|
class SSLogErrorEmailFormatter implements Zend_Log_Formatter_Interface {
|
||||||
|
|
||||||
|
public function format($event) {
|
||||||
|
$errorType = ($event['priorityName'] == 'WARN') ? 'Warning' : 'Error';
|
||||||
|
if($event['priorityName'] == 'WARN') {
|
||||||
|
$colour = "orange";
|
||||||
|
} else {
|
||||||
|
$colour = "red";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!is_array($event['message'])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$errno = $event['message']['errno'];
|
||||||
|
$errstr = $event['message']['errstr'];
|
||||||
|
$errfile = $event['message']['errfile'];
|
||||||
|
$errline = $event['message']['errline'];
|
||||||
|
$errcontext = $event['message']['errcontext'];
|
||||||
|
|
||||||
|
$data = "<div style=\"border: 5px $colour solid\">\n";
|
||||||
|
$data .= "<p style=\"color: white; background-color: $colour; margin: 0\">$errorType: $errstr<br /> At line $errline in $errfile\n<br />\n<br />\n</p>\n";
|
||||||
|
|
||||||
|
// Get a backtrace, filtering out debug method calls
|
||||||
|
$data .= SSBacktrace::backtrace(true, false, array(
|
||||||
|
'SSLogErrorEmailFormatter->format',
|
||||||
|
'SSLogEmailWriter->_write'
|
||||||
|
));
|
||||||
|
|
||||||
|
$data .= "</div>\n";
|
||||||
|
|
||||||
|
$relfile = Director::makeRelative($errfile);
|
||||||
|
if($relfile[0] == '/') $relfile = substr($relfile, 1);
|
||||||
|
|
||||||
|
$subject = "$errorType at $relfile line {$errline} (http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI])";
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'subject' => $subject,
|
||||||
|
'data' => $data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
34
dev/SSZendLog.php
Normal file
34
dev/SSZendLog.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Modifications to Zend_Log to make it work nicer
|
||||||
|
* with SSErrorLog. Specifically, this includes removing
|
||||||
|
* writers that have been added to the logger, as well as
|
||||||
|
* listing which ones are currently in use.
|
||||||
|
*
|
||||||
|
* @package sapphire
|
||||||
|
* @subpackage dev
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once 'Zend/Log.php';
|
||||||
|
|
||||||
|
class SSZendLog extends Zend_Log {
|
||||||
|
|
||||||
|
public function getWriters() {
|
||||||
|
return $this->_writers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a writer instance that exists in
|
||||||
|
* the current writers collection for this logger.
|
||||||
|
*
|
||||||
|
* @param object Zend_Log_Writer_Abstract instance
|
||||||
|
*/
|
||||||
|
public function removeWriter($writer) {
|
||||||
|
foreach($this->_writers as $index => $existingWriter) {
|
||||||
|
if($existingWriter == $writer) {
|
||||||
|
unset($this->_writers[$index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
29
tests/dev/SSErrorLogTest.php
Normal file
29
tests/dev/SSErrorLogTest.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @package sapphire
|
||||||
|
* @subpackage tests
|
||||||
|
*/
|
||||||
|
class SSLogTest extends SapphireTest {
|
||||||
|
|
||||||
|
protected $testEmailWriter;
|
||||||
|
|
||||||
|
function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
$this->testEmailWriter = new SSLogEmailWriter('sean@silverstripe.com');
|
||||||
|
SSLog::add_writer($this->testEmailWriter, SSLog::ERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testExistingWriter() {
|
||||||
|
$writers = SSLog::get_writers();
|
||||||
|
$this->assertType('array', $writers);
|
||||||
|
$this->assertEquals(1, count($writers));
|
||||||
|
}
|
||||||
|
|
||||||
|
function testRemoveWriter() {
|
||||||
|
SSLog::remove_writer($this->testEmailWriter);
|
||||||
|
$writers = SSLog::get_writers();
|
||||||
|
$this->assertType('array', $writers);
|
||||||
|
$this->assertEquals(0, count($writers));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user