使用register_shutdown_function实现php项目脚本执行失败的实时报警
背景:当线上php脚本执行失败时,希望能够实时地自动发送报警邮件,而不是等收到用户的反馈才知道有bug存在。
分析:当我们的php脚本正常执行完成或意外死掉导致PHP执行即将结束时,register_shutdown_function指定的函数将会被调用。
实现思路:在脚本开始处设置一个变量,值为false,然后在脚本末尾将之设置为true,让PHP关闭回调函数(即我们指定的函数)检查脚本是否已经完成【如果我们的变量仍旧是false,我们就知道脚本的最后一行没有执行,因此它肯定在程序执行到某处死掉了】
以下是一个演示例子:
1、主入口index.php文件:
<?php
// start
function shutdown_func() { //定义关闭回调函数
// shutdown
global $completeFlag;
global $completeFlagKey;
if (!$completeFlag) {
$monitorVal = "URL地址:".$_SERVER["REQUEST_URI"]."<br>";
$monitorVal .= "GET参数:".json_encode($_GET)."<br>"; $monitorVal .= "POST参数:".json_encode($_POST)."<br>"; $monitorVal .= "当前用户:".$_SESSION["currUserName"]."<br>";
$monitorVal .= "时间:".date("Y-m-d H:i:s")."<br>";
$monitorVal .= "错误信息:".json_encode(error_get_last());
$redis = new Redis();
$redis->connect("127.0.0.1", 6379);
$redis->set($completeFlagKey, $monitorVal);
}
return false; }
register_shutdown_function("shutdown_func"); $completeFlag = false; $completeFlagKey = uniqid("scriptShutdownMonitor_");
/*...这里是其他功能代码...*/
$completeFlag = true; // end ?> 2、各控制器都集成CommonController,CommonController文件的析构函数: function __destruct() { // destruct global $g_curr_run_env;
global $completeFlagKey;
if ($g_curr_run_env == "online") {
$redis = new Redis();
$redis->connect("127.0.0.1", 6379);
$redis->delete($completeFlagKey);
}
}
注意:__destruct里面如果要操作文件,也要写绝对路径 (1)如果是正常运行完,执行流程为:start 代码 destruct end shutdown (2)如果是脚本发生error,执行流程为:start 代码 shutdown (3)如果是代码里面主动exit()或die(),执行流程为:start 代码 shutdown destruct
3、监控报警邮件。通过crontab定时调用 set_time_limit(0);
date_default_timezone_set("Asia/shanghai");
$redis = new Redis();
$redis->connect("127.0.0.1", 6379);
$keys = $redis->keys("scriptShutdownMonitor_*");
$msg = "";
foreach ($keys as $key) {
$val = $redis->get($key);
if ($val) {
$msg .= $val."<br><hr><br>";
}
$redis->del($key);
}
if ($msg != "") {
$logCon = "当前时间:".date("Y-m-d H:i:s").";msg:".$msg." ";
file_put_contents("send_email.log", $logCon, FILE_APPEND);
require_once("send_email.php"); send_email( "xx@qq.com", "线上脚本执行失败报警", $msg ); }
附上博主的个人网站:w3cstudy学习网,上面的有很多供学习文章,有兴趣可以去逛逛
几点说明: 1、 register_shutdown_function("shutdown_func"); 对应回调函数的定义以及这句话要放在有可能引发错误的代码前面,否则在错误代码处崩溃后,这行代码也不会执行 参数:可以是一个字符串,即指定的关闭回调函数的名称,无需带括号,用引号包住即可; 也可以是一个数组,如array(‘error’,’shutdown_errow’)表示指定error类中的shutdown_error函数为关闭回调函数。 2、exit();//即使使用了exit();也会在exit()执行完后调用register_shutdown_function函数! 3、register_shutdown_function执行机制是:php把要调用的函数调入内存。当页面所有php语句都执行完成时,再调用此函数。注意,在这个时候从内存中调用,不是从php页面中调用,所以上面的例子中回调函数内如果要操作文件不能使用相对路径,因为php已经当原来的页面不存在了。就没有什么相对路 径可言。 4、可以这样理解调用条件: (1)当页面被用户代码如exit()强制停止时 (2)当程序代码运行超时或者出现错误时 (3)当php代码正常执行完成时
global $completeFlagKey;
if (!$completeFlag) {
$monitorVal = "URL地址:".$_SERVER["REQUEST_URI"]."<br>";
$monitorVal .= "GET参数:".json_encode($_GET)."<br>"; $monitorVal .= "POST参数:".json_encode($_POST)."<br>"; $monitorVal .= "当前用户:".$_SESSION["currUserName"]."<br>";
$monitorVal .= "时间:".date("Y-m-d H:i:s")."<br>";
$monitorVal .= "错误信息:".json_encode(error_get_last());
$redis = new Redis();
$redis->connect("127.0.0.1", 6379);
$redis->set($completeFlagKey, $monitorVal);
}
return false; }
register_shutdown_function("shutdown_func"); $completeFlag = false; $completeFlagKey = uniqid("scriptShutdownMonitor_");
/*...这里是其他功能代码...*/
$completeFlag = true; // end ?> 2、各控制器都集成CommonController,CommonController文件的析构函数: function __destruct() { // destruct global $g_curr_run_env;
global $completeFlagKey;
if ($g_curr_run_env == "online") {
$redis = new Redis();
$redis->connect("127.0.0.1", 6379);
$redis->delete($completeFlagKey);
}
}
注意:__destruct里面如果要操作文件,也要写绝对路径 (1)如果是正常运行完,执行流程为:start 代码 destruct end shutdown (2)如果是脚本发生error,执行流程为:start 代码 shutdown (3)如果是代码里面主动exit()或die(),执行流程为:start 代码 shutdown destruct
3、监控报警邮件。通过crontab定时调用 set_time_limit(0);
date_default_timezone_set("Asia/shanghai");
$redis = new Redis();
$redis->connect("127.0.0.1", 6379);
$keys = $redis->keys("scriptShutdownMonitor_*");
$msg = "";
foreach ($keys as $key) {
$val = $redis->get($key);
if ($val) {
$msg .= $val."<br><hr><br>";
}
$redis->del($key);
}
if ($msg != "") {
$logCon = "当前时间:".date("Y-m-d H:i:s").";msg:".$msg." ";
file_put_contents("send_email.log", $logCon, FILE_APPEND);
require_once("send_email.php"); send_email( "xx@qq.com", "线上脚本执行失败报警", $msg ); }
附上博主的个人网站:w3cstudy学习网,上面的有很多供学习文章,有兴趣可以去逛逛
几点说明: 1、 register_shutdown_function("shutdown_func"); 对应回调函数的定义以及这句话要放在有可能引发错误的代码前面,否则在错误代码处崩溃后,这行代码也不会执行 参数:可以是一个字符串,即指定的关闭回调函数的名称,无需带括号,用引号包住即可; 也可以是一个数组,如array(‘error’,’shutdown_errow’)表示指定error类中的shutdown_error函数为关闭回调函数。 2、exit();//即使使用了exit();也会在exit()执行完后调用register_shutdown_function函数! 3、register_shutdown_function执行机制是:php把要调用的函数调入内存。当页面所有php语句都执行完成时,再调用此函数。注意,在这个时候从内存中调用,不是从php页面中调用,所以上面的例子中回调函数内如果要操作文件不能使用相对路径,因为php已经当原来的页面不存在了。就没有什么相对路 径可言。 4、可以这样理解调用条件: (1)当页面被用户代码如exit()强制停止时 (2)当程序代码运行超时或者出现错误时 (3)当php代码正常执行完成时
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。
