PHP代码0报错进化之路

Posted by admin on 2017, August 18

写在前面

PHP在运行过程当中会有各种各样的错误报出,有很多却被忽略了,比如下面几个:

众所周知,其实PHP工程师很容易犯一个开发中经常会犯的小毛病,即使用数组的时候会不小心直接使用一个并不存在的key,如下代码:

$array = array("a" => "1", "b" => "2");
$use   = $array["c"];

其实很简单,大家都知道会报一个PHP Notice级别的错误,并不会影响代码向下执行,测试环境报在页面上可能会不美观,但你测试的时候恰好数据是全的,没有看到,到线上又不影响使用,所以很少有人会关注。

再举个例子:

Warning: Invalid argument supplied for foreach() in

这个相信大家如果打开php的 error log 也经常会见到,意思也很明显,就是循环了一个错误的数组,foreach 的第一个参数必须是一个数组。

当然,大家还会看到诸如Parse error,Fatal error的错误提示,代码量小的时候大部分人都选择忽略了,其实做了一些小小的工作,把php的 error log 由多变少,最后变成了0。先给大家看一下我们的成果:

可以看到开始我们的 error log 有21M之多,最后变成了现在的没有了!

虽然有一些bug改起来还是比较棘手的,但大部分其实代码作者看到就明白是什么问题了,但是如果他从不知道,也没有系统的看到,就永远可能不会去修改了。这时候一个能自动分析log并把相关问题发送给对应责任人的脚本就呼之欲出了。

写在中间(脚本设计)

首先由于这本身定义为一个分析日志的脚本,怕是log文件过大分析的时候占用生产机资源,因为我们本身就有生产机使用消息队列机制同步日志到开发机的现成流程,所以就直接用了。

  • php_error_log 同步到非生产机

可以和大家分享的是我们使用了nsq 。不断的把生产机log同步到非生产机。这里呢是一位小哥使用go弄了一个小工具来实现tail的功能来直接把log不断发送到消息中心。最后写到非生产机以供分析。

  • 分析 log 文件的内容

好,log文件有了,下面开始写脚本,linux有个awk命令灰常好用,能顺利完成我们的需求,所以我们直接选用shell脚本来搞。 大家可以对比自己的error_log修改相关细节。

先写一个awk命令: awk -v today="31-Jul-2017" -FAsia/Chongqing] '{if($0~today) print $2}' 20170731.log | sort | uniq -c | sort -k1nr | grep 'on line' 我们用时区切割将真正需要的当天错误详情拿出来,排序。 这里面有一个需要说明的地方,为什么在uniq之前要先sort,因为实测uniq的统计,是在相邻的行一样的时候才能够合并计数,所以我们先排序使得相同的错误能够在相邻的行。最后你得到的结果应该是这样的:

 960  PHP Notice:  some notice in /some/path/notice.php on line 119
 850  PHP Warning:  some Warning in /some/path/warning.php on line 110

第一列是错误发生的次数,后面分别为错误详情以及文件包括代码所在的行。 到这里其实已经可以完成一部分需求了,只是需要大家自行认领相关问题,因为使用了git作为仓库,我们还可以做的更好。

  • 使用 git blame 获取作者和相关代码详情

关键代码:

code_writer=$(git blame -L$file_line,$file_line -e $file_name | awk 'BEGIN{FS=")"}  {print $1}' | awk -F '[<>]' '{print $2}')

code_content=$(echo $(git blame -L$file_line,$file_line -e $file_name | awk 'BEGIN{FS=")"}  {print $2}') | sed 's/^ //g;s/ $//g')

解释一下,当你使用git blame -e 命令的时候,可以得到如下类似的结果:

d8eabd28c (<mumulaonian@gmail.com> 2017-07-12 16:58:38 +0800 4)  * // some code by akmumu

-L 参数是查看指定行的结果,如代码所示,再使用awk和sed可以获得作者邮箱和代码详情。

其实到这里为止你已经可以搞一个循环生成一个包含table的html源码,然后通过邮件服务器发给相关的人了,作者看到,大概很快就能搞掉一半的报错了,希望几天之后你们也可以做到 error_log 文件 0KB。但如果你们也恰好使用自己搭建的gitlab管理代码,那么其实还可以做的更多。

  • 使用gitlab的相关Api完成一些自动化的事情

其实gitlab提供给了我们很多的Api,你可以用之来做很多的事情,可以自由选择一些使用,比如我们有使用issues相关的Api,直接创建issue,文档:issues文档

你如果也使用了 capistranogitlab CI 作为自动化部署工具,那么你还可以在完成修复issue的 merge request 之后将当天的相关报错log通过shell删掉,这样明天的通知在确实不存在本bug的情况下将不会存在相应log,这里很简单,还用 sed 即可。

当然CI的脚本也有很多想象空间,大家自由发挥好了。

写在后面

我们在解决以上报错的时候解决了很多意料之外的问题,一些不被关注的问题,还有某个服务的一个不常用的小部分其实已经有两天不可用的情况了,幸好比较及时,没有发生太多的损失。所以说此log是急需被关注的,如果你还没有做,就抓紧开始吧,不要应验这句话,”那些年里看到了,懂了,却不做“。