調(diào)試是一個(gè)程序猿非常重要的能力,人寫的程序總會(huì)有 bug,所以需要 debug。如何方便和快速的定位 bug,是我們討論的重點(diǎn),只要 bug 能定位,解決就不是問題。
對于熟悉用 Visual Studio 和 Eclipse 這些強(qiáng)大的集成開發(fā)環(huán)境的來做 C++ 和 Java 的同學(xué)來說,OpenResty 的 debug 要原始很多,但是對于習(xí)慣 Python 開發(fā)的同學(xué)來說,又是那么的熟悉。 張銀奎有本《軟件調(diào)試》的書,windows 客戶端程序猿應(yīng)該都看過,大家可以去試讀下,看看里面有多復(fù)雜:(
對于 OpenResty,壞消息是,沒有單步調(diào)試這些玩意兒(我們嘗試搞出來過 ngx Lua 的單步調(diào)試,但是沒人用...); 好消息是,它像 Python 一樣,非常簡單,不用復(fù)雜的技術(shù),只靠 print 和 log 就能定位絕大部分問題,難題有火焰圖這個(gè)神器。
在調(diào)試的時(shí)候最好關(guān)閉 lua_code_cache
這個(gè)選項(xiàng)。
lua_code_cache off;
關(guān)閉 lua_code_cache
之后,OpenResty 會(huì)給每個(gè)請求創(chuàng)建新的 Lua VM。由于沒有 Lua module 的緩存,新的 VM 會(huì)去加載剛最新的 Lua 文件。
這樣,你修改完代碼后,不用 reload Nginx 就可以生效了。在生產(chǎn)環(huán)境下記得打開這個(gè)選項(xiàng)。
當(dāng)然,由于每個(gè)請求運(yùn)行在獨(dú)立的 Lua VM 里,lua_code_cache off
會(huì)帶來以下幾個(gè)問題:
init_by_lua_file
引用的文件就不會(huì)被更新。*_by_lua_block
里面的代碼,由于不在 Lua 文件里面,設(shè)置 lua_code_cache
對其沒有意義。如果調(diào)試的目標(biāo)涉及以上內(nèi)容,仍需設(shè)置 lua_code_cache on
,通過 reload 來更新代碼。
這個(gè)看上去誰都會(huì)的東西,要想做好也不容易。
你有遇到這樣的情況嗎?QA 發(fā)現(xiàn)了一個(gè) bug,開發(fā)說我修改代碼加個(gè)日志看看,然后 QA 重現(xiàn)這個(gè)問題,發(fā)現(xiàn)日志不夠詳細(xì),需要再加,反復(fù)幾次,然后再給 QA 一個(gè)沒有日志的版本,繼續(xù)測試其他功能。
如果產(chǎn)品已經(jīng)發(fā)布到用戶那里了呢?如果用戶那里是隔離網(wǎng),不能遠(yuǎn)程怎么辦?
你在寫代碼的時(shí)候,就需要考慮到調(diào)試日志。 比如這個(gè)代碼:
local response, err = redis_op.finish_client_task(client_mid, task_id)
if response then
put_job(client_mid, result)
ngx.log(ngx.WARN, "put job:", common.json_encode({channel="task_status", mid=client_mid, data=result}))
end
我們在做一個(gè)操作后,就把結(jié)果記錄到 Nginx 的 error.log 里面,等級是 warn。在生產(chǎn)環(huán)境下,日志等級默認(rèn)為 error,在我們需要詳細(xì)日志的時(shí)候,把等級調(diào)整為 warn 即可。在我們的實(shí)際使用中,我們會(huì)把一些很少發(fā)生的重要事件,做為 error 級別記錄下來,即使它并不是 Nginx 的錯(cuò)誤。
與日志配套的,你需要logrotate來做日志的切分和備份。