當運營向我們上報BUG時,我們第一時間是捕獲相關的接口。從監控系統中,就可以查到用戶使用時接口的請求和響應數據。
若接口的請求正常,那么就需要深入到接口代碼中,查看相關的日志,通常會先瀏覽數據庫查詢語句以及內部接口的通信日志。
在本地也可以查看到上述日志,但有個問題,有時候打開某個頁面會報錯,那是因為本地的數據庫沒有與測試或正式環境的同步。
可能是有些字段缺失了,也可能是某張表缺失了,情況比較多。所以,最保險的是在測試或正式環境查看。
在這兩個環境中,都有日志管理系統,但日志量是非常巨大的,若要查找某一條記錄,就得有非常精確的過濾條件,並且日志無法連續。
這條日志下面的一條,很可能是另外一個接口留下的,因此,需要一個小工具能查看到指定接口的日志,解決日常開發的一個痛點。
一、搜集日志
1)管理系統
首先需要將需要的日志搜集起來,我使用了一個比較簡單的方法。
就是在啟動文件中,新增一個全局的logMessages變量,聲明為一個空數組。
global.logMessages = [];
然后在MongoDB、MySQL、請求內部接口函數中,將他們的查詢語句日志和通信日志塞入logMessages數組內。
mongoose.set('debug', (...args) => { logger.debug(...args); global.logMessages.push(args); }); new Sequelize(database, username, password, { ...options, logging: (msg, benchmark) => { logger.debug(msg, `${benchmark}ms`); global.logMessages.push(msg); } });
再新增一個中間件(Server項目基於KOA2),這個中間件的作用就是清空logMessages數組,免得將所有接口的日志都搜集起來,因為我只要一個接口的日志。
export default () => async (ctx, next) => { //每次請求清空要讀取的日志數組 global.logMessages.length = 0; await next(); };
這么設計會有一個問題,服務器在處理多個請求(高並發)時,互相會影響各自的日志搜集,可能會出現這個接口日志中夾雜着另一個接口的日志,也可能是搜集到一半的日志就被清除了。
當然,在測試環境,這種情況可以控制住。但是測試環境有時候數據不完整,邏輯可能走不下去,得上生產環境,那生產環境就有概率出現上述問題。
后面將中間件去除,logMessages變量在一個接口中聲明,這個接口就是下面界面中點提交時請求的接口,能解決日志被無故清除的問題,但還是會出現串線的問題。
生產環境暫時無解,好在還有一個預發環境,它使用的數據源和生產是相同的,只要保證代碼和生產同步,那么就能得到想要的日志列表。
2)Web API
Web API是另一個接口服務,也需要監控其中的日志,但是它與之前的管理系統不同,它是一個獨立的服務。
也就是說,我無法直接在管理系統中通過 global.logMessages 讀取日志。
一開始是想將日志寫入緩存中,然后在管理系統中讀取緩存中的日志,不過這樣做不僅太繞,平添復雜度,而且日志寫法也會與之前的不一致。
於是否決了此方案,改用一個中間件,日志的寫入和讀取與之前保持一致。不同點是在一個中間件中,將日志作為響應的參數返回。
在下面的代碼中,當需要日志時,我會帶上一個特殊的參數:isLogMessages,只有這個參數存在時,才表示需要返回記錄。
export default () => async (ctx, next) => { // 只有帶了特殊參數的請求,才會把接口日志帶上 const isLogMessages = ctx.query.isLogMessages || ctx.request.body.isLogMessages; if(isLogMessages) { global.logMessages = []; } await next(); if(isLogMessages) { const { body } = ctx; if(typeof body === 'string') { ctx.body = { data: body }; }else { ctx.body = { ...body } } ctx.body.logMessages = global.logMessages; delete global.logMessages; }
二、界面
在完成上述的日志搜集之后,就需要有一張操作界面(如圖所示),提升我們組自己的用戶體驗,借助之前封裝的模板組件,搭建這樣一個頁面幾十分鍾就好了。
界面中包括API路徑、方法、項目和參數,其中參數可動態增加,點擊提交就會開始模擬請求接口,得到日志(如圖所示)和響應。
這樣一套操作之后,就能馬上知道接口內的細節,可幫助我們快速定位問題,也是一種降低時間成本的手段。