多彩換新PHP代碼0報錯進化之路
寫在前面
PHP在運行過程當(dāng)中會有各種各樣的錯誤報出,有很多卻被忽略了,比如下面幾個:
眾所周知,其實PHP工程師很容易犯一個開發(fā)中經(jīng)常會犯的小毛病,即使用數(shù)組的時候會不小心直接使用一個并不存在的key,如下代碼:
$array = array("a" => "1", "b" => "2");
$use = $array["c"];
其實很簡單,大家都知道會報一個PHP Notice級別的錯誤,并不會影響代碼向下執(zhí)行,測試環(huán)境報在頁面上可能會不美觀,但你測試的時候恰好數(shù)據(jù)是全的,沒有看到,到線上又不影響使用,所以很少有人會關(guān)注。
再舉個例子:
Warning: Invalid argument supplied for foreach() in
這個相信大家如果打開php的 error log 也經(jīng)常會見到,意思也很明顯,就是循環(huán)了一個錯誤的數(shù)組,foreach 的***個參數(shù)必須是一個數(shù)組。
當(dāng)然,大家還會看到諸如Parse error,Fatal error的錯誤提示,代碼量小的時候大部分人都選擇忽略了,但是多彩的小木工還是做了一些小小的工作,把php的 error log 由多變少,***變成了0。先給大家看一下我們的成果:

可以看到開始我們的 error log 有21M之多,***變成了現(xiàn)在的沒有了!
雖然有一些bug改起來還是比較棘手的,但大部分其實代碼作者看到就明白是什么問題了,但是如果他從不知道,也沒有系統(tǒng)的看到,就永遠(yuǎn)可能不會去修改了。這時候一個能自動分析log并把相關(guān)問題發(fā)送給對應(yīng)責(zé)任人的腳本就呼之欲出了。
寫在中間(腳本設(shè)計)
首先由于這本身定義為一個分析日志的腳本,怕是log文件過大分析的時候占用生產(chǎn)機資源,因為我們本身就有生產(chǎn)機使用消息隊列機制同步日志到開發(fā)機的現(xiàn)成流程,所以就直接用了。
- php_error_log 同步到非生產(chǎn)機
可以和大家分享的是多彩使用了nsq 。不斷的把生產(chǎn)機log同步到非生產(chǎn)機。這里呢是一位瓦工小哥使用go弄了一個小工具來實現(xiàn)tail的功能來直接把log不斷發(fā)送到消息中心。***寫到非生產(chǎn)機以供分析。
- 分析 log 文件的內(nèi)容
好,log文件有了,下面開始寫腳本,linux有個awk命令灰常好用,能順利完成我們的需求,所以我們直接選用shell腳本來搞。
大家可以對比自己的error_log修改相關(guān)細(xì)節(jié)。
先寫一個awk命令:
awk -v today="31-Jul-2017" -FAsia/Chongqing] '{if($0~today) print $2}' 20170731.log | sort | uniq -c | sort -k1nr | grep 'on line'
我們用時區(qū)切割將真正需要的當(dāng)天錯誤詳情拿出來,排序。
這里面有一個需要說明的地方,為什么在uniq之前要先sort,因為實測uniq的統(tǒng)計,是在相鄰的行一樣的時候才能夠合并計數(shù),所以我們先排序使得相同的錯誤能夠在相鄰的行。***你得到的結(jié)果應(yīng)該是這樣的:
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
***列是錯誤發(fā)生的次數(shù),后面分別為錯誤詳情以及文件包括代碼所在的行。
到這里其實已經(jīng)可以完成一部分需求了,只是需要大家自行認(rèn)領(lǐng)相關(guān)問題,因為多彩使用了git作為倉庫,我們還可以做的更好。
- 使用 git blame 獲取作者和相關(guān)代碼詳情
關(guān)鍵代碼:
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')
解釋一下,當(dāng)你使用git blame -e 命令的時候,可以得到如下類似的結(jié)果:
d8eabd28c (<mumulaonian@gmail.com> 2017-07-12 16:58:38 +0800 4) * // some code by akmumu
-L 參數(shù)是查看指定行的結(jié)果,如代碼所示,再使用awk和sed可以獲得作者郵箱和代碼詳情。
其實到這里為止你已經(jīng)可以搞一個循環(huán)生成一個包含table的html源碼,然后通過郵件服務(wù)器發(fā)給相關(guān)的人了,作者看到,大概很快就能搞掉一半的報錯了,希望幾天之后你們也可以做到 error_log 文件 0KB。但如果你們也恰好使用自己搭建的gitlab管理代碼,那么其實還可以做的更多。
- 使用gitlab的相關(guān)Api完成一些自動化的事情
其實gitlab提供給了我們很多的Api,你可以用之來做很多的事情,可以自由選擇一些使用,比如我們有使用issues相關(guān)的Api,直接創(chuàng)建issue,文檔:issues文檔。
你如果也使用了 capistrano 和 gitlab CI 作為自動化部署工具,那么你還可以在完成修復(fù)issue的 merge request 之后將當(dāng)天的相關(guān)報錯log通過shell刪掉,這樣明天的通知在確實不存在本bug的情況下將不會存在相應(yīng)log,這里很簡單,還用 sed 即可。
當(dāng)然CI的腳本也有很多想象空間,大家自由發(fā)揮好了。
寫在后面
我們在解決以上報錯的時候解決了很多意料之外的問題,一些不被關(guān)注的問題,還有某個服務(wù)的一個不常用的小部分其實已經(jīng)有兩天不可用的情況了,幸好比較及時,沒有發(fā)生太多的損失。所以說此log是急需被關(guān)注的,如果你還沒有做,就抓緊開始吧,不要應(yīng)驗這句話,”那些年里看到了,懂了,卻不做“。