mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-07-01 08:59:42 +02:00
FEATURE: Improved debugging view on CLI interface, by having a separate DebugView subclass that takes care of error output for this situation.
API CHANGE: Added Debug::log_errors_to(), to log errors to a file. git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@60368 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
010c91af0a
commit
db1e79c3b1
57
dev/CliDebugView.php
Normal file
57
dev/CliDebugView.php
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* A basic HTML wrapper for stylish rendering of a developement info view.
|
||||||
|
* Used to output error messages, and test results.
|
||||||
|
*
|
||||||
|
* @package sapphire
|
||||||
|
* @subpackage dev
|
||||||
|
*
|
||||||
|
* @todo Perhaps DebugView should be an interface / ABC, implemented by HTMLDebugView and CliDebugView?
|
||||||
|
*/
|
||||||
|
|
||||||
|
class CliDebugView extends DebugView {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render HTML header for development views
|
||||||
|
*/
|
||||||
|
public function writeHeader($httpRequest) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render HTML footer for development views
|
||||||
|
*/
|
||||||
|
public function writeFooter() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write information about the error to the screen
|
||||||
|
*/
|
||||||
|
public function writeError($httpRequest, $errno, $errstr, $errfile, $errline, $errcontext) {
|
||||||
|
echo "ERROR: $errstr\nIN $httpRequest\n";
|
||||||
|
echo "Line $errline in $errfile\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a fragment of the a source file
|
||||||
|
* @param $lines An array of file lines; the keys should be the original line numbers
|
||||||
|
*/
|
||||||
|
function writeSourceFragment($lines, $errline) {
|
||||||
|
echo "Source\n======\n";
|
||||||
|
foreach($lines as $offset => $line) {
|
||||||
|
echo ($offset == $errline) ? "* " : " ";
|
||||||
|
echo str_pad("$offset:",5);
|
||||||
|
echo wordwrap($line, 100, "\n ");
|
||||||
|
}
|
||||||
|
echo "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a backtrace
|
||||||
|
*/
|
||||||
|
function writeTrace() {
|
||||||
|
Debug::backtrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
|
@ -58,6 +58,15 @@ class Debug {
|
||||||
*/
|
*/
|
||||||
protected static $send_warnings_to;
|
protected static $send_warnings_to;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String indicating the file where errors are logged.
|
||||||
|
* Filename is relative to the site root.
|
||||||
|
* The named file will have a terse log sent to it, and the full log (an
|
||||||
|
* encoded file containing backtraces and things) will go to a file of a similar
|
||||||
|
* name, but with the suffix ".full" added.
|
||||||
|
*/
|
||||||
|
protected static $log_errors_to = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the contents of val in a debug-friendly way.
|
* Show the contents of val in a debug-friendly way.
|
||||||
* Debug::show() is intended to be equivalent to dprintr()
|
* Debug::show() is intended to be equivalent to dprintr()
|
||||||
|
@ -214,6 +223,7 @@ class Debug {
|
||||||
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");
|
||||||
|
self::log_error_if_necessary( $errno, $errstr, $errfile, $errline, $errcontext, "Warning");
|
||||||
|
|
||||||
if(Director::isDev()) {
|
if(Director::isDev()) {
|
||||||
self::showError($errno, $errstr, $errfile, $errline, $errcontext);
|
self::showError($errno, $errstr, $errfile, $errline, $errcontext);
|
||||||
|
@ -233,14 +243,15 @@ class Debug {
|
||||||
*/
|
*/
|
||||||
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");
|
||||||
|
self::log_error_if_necessary( $errno, $errstr, $errfile, $errline, $errcontext, "Error");
|
||||||
|
|
||||||
if(Director::isDev()) {
|
if(Director::isDev() || Director::is_cli()) {
|
||||||
Debug::showError($errno, $errstr, $errfile, $errline, $errcontext);
|
Debug::showError($errno, $errstr, $errfile, $errline, $errcontext);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Debug::friendlyError($errno, $errstr, $errfile, $errline, $errcontext);
|
Debug::friendlyError($errno, $errstr, $errfile, $errline, $errcontext);
|
||||||
}
|
}
|
||||||
die();
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -268,6 +279,14 @@ class Debug {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an instance of an appropriate DebugView object.
|
||||||
|
*/
|
||||||
|
static function create_debug_view() {
|
||||||
|
if(Director::is_cli()) return new CliDebugView();
|
||||||
|
else return new DebugView();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render a developer facing error page, showing the stack trace and details
|
* Render a developer facing error page, showing the stack trace and details
|
||||||
* of the code where the error occured.
|
* of the code where the error occured.
|
||||||
|
@ -284,17 +303,23 @@ class Debug {
|
||||||
echo "ERROR:Error $errno: $errstr\n At l$errline in $errfile\n";
|
echo "ERROR:Error $errno: $errstr\n At l$errline in $errfile\n";
|
||||||
Debug::backtrace();
|
Debug::backtrace();
|
||||||
} else {
|
} else {
|
||||||
$reporter = new DebugView();
|
$reporter = self::create_debug_view();
|
||||||
$reporter->writeHeader();
|
|
||||||
$reporter->writeInfo(strip_tags($errstr), $_SERVER['REQUEST_METHOD'] . " " .$_SERVER['REQUEST_URI'],
|
// Coupling alert: This relies on knowledge of how the director gets its URL, it could be improved.
|
||||||
"Line <strong>$errline</strong> in <strong>$errfile</strong>");
|
$httpRequest = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : $_REQUEST['url'];
|
||||||
echo '<div class="trace"><h3>Source</h3>';
|
if(isset($_SERVER['REQUEST_METHOD'])) $httpRequest = $_SERVER['REQUEST_METHOD'] . ' ' . $httpRequest;
|
||||||
Debug::showLines($errfile, $errline);
|
|
||||||
echo '<h3>Trace</h3>';
|
$reporter->writeHeader($httpRequest);
|
||||||
Debug::backtrace();
|
$reporter->writeError($httpRequest, $errno, $errstr, $errfile, $errline, $errcontext);
|
||||||
echo '</div>';
|
|
||||||
|
$lines = file($errfile);
|
||||||
|
$offset = $errline-10;
|
||||||
|
$lines = array_slice($lines, $offset, 16, true);
|
||||||
|
$reporter->writeSourceFragment($lines, $errline);
|
||||||
|
|
||||||
|
$reporter->writeTrace($lines);
|
||||||
$reporter->writeFooter();
|
$reporter->writeFooter();
|
||||||
die();
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,6 +382,26 @@ class Debug {
|
||||||
mail($emailAddress, "$errorType at $relfile line $errline (http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI])", $data, "Content-type: text/html\nFrom: errors@silverstripe.com");
|
mail($emailAddress, "$errorType at $relfile line $errline (http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI])", $data, "Content-type: text/html\nFrom: errors@silverstripe.com");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the given error, if self::$log_errors is set.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $server IP-Address or domain
|
* @param string $server IP-Address or domain
|
||||||
*/
|
*/
|
||||||
|
@ -397,6 +442,14 @@ class Debug {
|
||||||
return self::$send_warnings_to;
|
return self::$send_warnings_to;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this to enable logging of errors.
|
||||||
|
*/
|
||||||
|
static function log_errors_to($logFile = ".sserrors") {
|
||||||
|
self::$log_errors_to = $logFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deprecated. Send live errors and warnings to the given address.
|
* Deprecated. Send live errors and warnings to the given address.
|
||||||
* @deprecated Use send_errors_to() instead.
|
* @deprecated Use send_errors_to() instead.
|
||||||
|
@ -424,20 +477,20 @@ class Debug {
|
||||||
* @return unknown
|
* @return unknown
|
||||||
*/
|
*/
|
||||||
static function backtrace($returnVal = false, $ignoreAjax = false) {
|
static function backtrace($returnVal = false, $ignoreAjax = false) {
|
||||||
|
|
||||||
$bt = debug_backtrace();
|
$bt = debug_backtrace();
|
||||||
|
|
||||||
// Ingore functions that are plumbing of the error handler
|
// Ingore functions that are plumbing of the error handler
|
||||||
$ignoredFunctions = array('Debug::emailError','Debug::warningHandler','Debug::fatalHandler','errorHandler','Debug::showError','Debug::backtrace', 'exceptionHandler');
|
$ignoredFunctions = array('DebugView::writeTrace', 'CliDebugView::writeTrace', 'Debug::emailError','Debug::warningHandler','Debug::fatalHandler','errorHandler','Debug::showError','Debug::backtrace', 'exceptionHandler');
|
||||||
while( $bt && in_array(self::full_func_name($bt[0]), $ignoredFunctions) ) {
|
while( $bt && in_array(self::full_func_name($bt[0]), $ignoredFunctions) ) {
|
||||||
array_shift($bt);
|
array_shift($bt);
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = "<ul>";
|
$result = "<ul>";
|
||||||
foreach($bt as $item) {
|
foreach($bt as $item) {
|
||||||
if(Director::is_ajax() && !$ignoreAjax) {
|
if(Director::is_cli() || (Director::is_ajax() && !$ignoreAjax)) {
|
||||||
$result .= self::full_func_name($item,true) . "\n";
|
$result .= self::full_func_name($item,true) . "\n";
|
||||||
$result .= "line $item[line] of " . basename($item['file']) . "\n\n";
|
if(isset($item['line']) && isset($item['file'])) $result .= "line $item[line] of " . basename($item['file']) . "\n";
|
||||||
|
$result .= "\n";
|
||||||
} else {
|
} else {
|
||||||
if ($item['function'] == 'user_error') {
|
if ($item['function'] == 'user_error') {
|
||||||
$name = $item['args'][0];
|
$name = $item['args'][0];
|
||||||
|
@ -573,5 +626,3 @@ function errorHandler($errno, $errstr, $errfile, $errline, $errcontext) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
|
|
@ -81,6 +81,43 @@ class DebugView {
|
||||||
echo "</body></html>";
|
echo "</body></html>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write information about the error to the screen
|
||||||
|
*/
|
||||||
|
public function writeError($httpRequest, $errno, $errstr, $errfile, $errline, $errcontext) {
|
||||||
|
echo '<div class="info">';
|
||||||
|
echo "<h1>" . strip_tags($errstr) . "</h1>";
|
||||||
|
echo "<h3>$httpRequest</h3>";
|
||||||
|
echo "<p>Line <strong>$errline</strong> in <strong>$errfile</strong></p>";
|
||||||
|
echo '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a fragment of the a source file
|
||||||
|
* @param $lines An array of file lines; the keys should be the original line numbers
|
||||||
|
*/
|
||||||
|
function writeSourceFragment($lines, $errline) {
|
||||||
|
echo '<div class="trace"><h3>Source</h3>';
|
||||||
|
echo '<pre>';
|
||||||
|
foreach($lines as $offset => $line) {
|
||||||
|
$line = htmlentities($line);
|
||||||
|
if ($offset == $errline) {
|
||||||
|
echo "<span>$offset</span> <span class=\"error\">$line</span>";
|
||||||
|
} else {
|
||||||
|
echo "<span>$offset</span> $line";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
echo '</pre>';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a backtrace
|
||||||
|
*/
|
||||||
|
function writeTrace() {
|
||||||
|
echo '<h3>Trace</h3>';
|
||||||
|
Debug::backtrace();
|
||||||
|
echo '</div>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
Loading…
Reference in New Issue
Block a user