I have some scripts that run via cron. Some run once a day, some more. I recently checked the log file for one of these scripts and noticed that the script did not finish a few times. I know this because the final lines of code which write to a log file did not write to the log file. It occurred to me that I might be able to check the script output which is captured to a file but the crontab entry looks like this:
0 0 * * * php -q /var/www/vhosts/erepairables.com/httpdocs/erp_php/crons/purge_expired.php > /var/www/vhosts/erepairables.com/cron_jobs/output/purge_expired_log.txt &
The ampersand, intended to let the cron launch a long-running script and proceed on its merry way without holding up other cron activities, has the effect of supressing the output of the script. Moreover, the script output gets overwritten every day. I might be able to go looking at the apache log if the php errors are also getting written there, but I'd be looking for a needle in a haystack I think.
I would therefore like to set up an error handler or shutdown function in these scripts which will send me an email if any errors have occurred. I foresee perhaps two problems
1) Some fatal errors (e.g., declaring a function twice) apparently cannot be trapped.
2) Some things trigger errors, others throw exceptions.
In php 5.3.5, this script will catch attempts to call nonexistent functions and nonexistent methods on nonexistent objects, but it will not catch attempts to define a function twice:
<?php
// this is for the testing of error handling
$sneakyimp_errors = array();
set_error_handler("sneakyimp_error_handler");
function sneakyimp_error_handler($errno, $errstr, $errfile=NULL, $errline=NULL, $errcontext=NULL) {
global $sneakyimp_errors;
$sneakyimp_errors[] = array(
"errno" => $errno,
"errstr" => $errstr,
"errfile" => $errfile,
"errline" => $errline,
"errcontext" => $errcontext
);
// return false to let the php error handler do its thing.
return FALSE;
} // sneakyimp_error_handler()
function sneakyimp_shutdown() {
global $sneakyimp_errors;
$msg = "";
$error = error_get_last();
if (!is_null($error)) {
$msg .= "shutdown detected an error:\n";
$msg .= print_r($error, TRUE);
$msg .= "\n\n";
}
if (sizeof($sneakyimp_errors) > 0) {
$msg .= "errors detected during script execution:\n";
$msg .= print_r($sneakyimp_errors, TRUE);
}
if ($msg != "") {
// email me or whatever
echo "\n=====\n$msg\n=====\n\n";
}
} // sneakyimp_shutdown()
register_shutdown_function("sneakyimp_shutdown");
echo "Here is some output\n";
// this should cause an error
$no_obj->notAFunction();
echo "Here is more output\n";
?>
This seems to work pretty well so far in that it catches most of the fatal errors I've tried (but not defining a function twice). I expect I'll try to do something OOP with a static var so I can avoid defining global vars. It's also kind of annoying but informative to see the entire errcontext for each error (a lengthy bit of text). Can anyone see any problems or does anyone have any suggestions for improvement?