多彩換新PHP代碼0報錯進化之路
寫在前面
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文檔。
你如果也使用了 capistrano 和 gitlab CI 作為自動化部署工具,那么你還可以在完成修復issue的 merge request 之后將當天的相關報錯log通過shell刪掉,這樣明天的通知在確實不存在本bug的情況下將不會存在相應log,這里很簡單,還用 sed 即可。
當然CI的腳本也有很多想象空間,大家自由發揮好了。
寫在后面
我們在解決以上報錯的時候解決了很多意料之外的問題,一些不被關注的問題,還有某個服務的一個不常用的小部分其實已經有兩天不可用的情況了,幸好比較及時,沒有發生太多的損失。所以說此log是急需被關注的,如果你還沒有做,就抓緊開始吧,不要應驗這句話,”那些年里看到了,懂了,卻不做“。


























