Node.js+ELK日志規(guī)范的實(shí)現(xiàn)
一般前端開發(fā)同學(xué),對(duì)日志其實(shí)不太敏感,畢竟前端大多數(shù)情況下,不太關(guān)心日志。即使有,也可能調(diào)用一些第三方的統(tǒng)計(jì),比如百度統(tǒng)計(jì)或者別的等。在 Node.js(下文中簡稱node) 推進(jìn)過程中,也發(fā)現(xiàn)我們平常打日志太隨意,該打的日志沒有打,打的一些關(guān)鍵日志缺少必要上下文信息,導(dǎo)致在線上定位問題的時(shí)候很困難。
本文主要梳理了目前我們團(tuán)隊(duì)在nodejs開發(fā)中日志方面存在的問題,以及通過統(tǒng)一日志規(guī)范,希望達(dá)到什么樣的效果。
問題
- node日志不規(guī)范,打日志太隨意
- 沒有良好的日志格式、約定的字段,在 ELK 里不能很好的解析&檢索 (PS: ELK文章在路上)
- 由于node對(duì)接的后端服務(wù)化,調(diào)用鏈不清晰,定位問題困難
- 數(shù)據(jù)部門對(duì)node日志的使用,沒有明確的記錄。node修改了日志,導(dǎo)致統(tǒng)計(jì)數(shù)據(jù)異常
目標(biāo)
- 規(guī)范日志打印字段&格式,便于 ELK 檢索
- 增強(qiáng)node上下游(nginx/后端)日志格式,加入惟一 requestId,方便微服務(wù)下定位問題
- 統(tǒng)計(jì)應(yīng)用運(yùn)行情況,性能數(shù)據(jù)
- 維護(hù)數(shù)據(jù)部門對(duì)node日志的使用情況
實(shí)現(xiàn)方案
日志類型
參考一些日志的最佳實(shí)踐,目前將node日志分為如下幾種類型(scope):
- desc: 系統(tǒng)啟動(dòng)、運(yùn)行過程中,打的日志,表明系統(tǒng)的一些啟動(dòng)日志、啟動(dòng)參數(shù)等,也包含在 不能 捕獲到http上下文的時(shí)候,打的日志
- stat: 系統(tǒng)性能統(tǒng)計(jì)日志,應(yīng)用會(huì)定時(shí)收集一些性能信息,便于查詢應(yīng)用當(dāng)前狀態(tài)
- visit: 每個(gè)http請(qǐng)求相關(guān)的日志,會(huì)包含惟一的 requestId,定位該請(qǐng)求相關(guān)的所有日志
- biz: 業(yè)務(wù)數(shù)據(jù)相關(guān)日志,主要提供給數(shù)據(jù)統(tǒng)計(jì)使用
日志級(jí)別
只使用 FATAL、ERROR、WARN、INFO 和 DEBUG 等級(jí)。
- FATAL - 導(dǎo)致程序退出的嚴(yán)重系統(tǒng)級(jí)錯(cuò)誤,不可恢復(fù),當(dāng)錯(cuò)誤發(fā)生時(shí),系統(tǒng)管理員需要立即介入,一般應(yīng)用代碼 不 使用。
- ERROR - 運(yùn)行時(shí)異常以及預(yù)期之外的錯(cuò)誤,也需要立即處理,但緊急程度低于FATAL,當(dāng)錯(cuò)誤發(fā)生時(shí),影響了程序的正確執(zhí)行。需要注意的是這兩種級(jí)別屬于服務(wù)自己的錯(cuò)誤,需要管理員介入,用戶輸入出錯(cuò)不屬于此分類,請(qǐng)求后端、讀文件、數(shù)據(jù)庫等超時(shí)、返回錯(cuò)誤結(jié)構(gòu),屬于ERROR
- WARN - 預(yù)期之外的運(yùn)行時(shí)狀況,表示系統(tǒng)可能出現(xiàn)問題。對(duì)于那些目前還不是錯(cuò)誤,然而不及時(shí)處理也會(huì)變成錯(cuò)誤的情況,也可以記為WARN,如磁盤過低。
- INFO - 有意義的事件信息,記錄程序正常的運(yùn)行狀態(tài),比如收到請(qǐng)求,成功執(zhí)行。通過查看INFO,可以快速定位WARN,ERROR, FATAL。INFO不宜過多,通常情況下不超過 DEBUG 的10%。
- DEBUG - 與程序運(yùn)行時(shí)的流程相關(guān)的詳細(xì)信息以及當(dāng)前變量狀態(tài)。
日志格式/字段
- 日志格式統(tǒng)一采用 JSON ,便于 ELK 解析處理。
- 日志中的各個(gè)字段的值,都應(yīng)該盡量使用 英文 ,不使用中文。
- 日志具體字段,分為 基礎(chǔ)數(shù)據(jù) + 擴(kuò)展數(shù)據(jù)?;A(chǔ)數(shù)據(jù),是底層日志框架自帶的,所有日志都會(huì)包含。擴(kuò)展數(shù)據(jù),不同類型的日志,包含不同的字段。
日志基礎(chǔ)數(shù)據(jù)
目前使用的 node-bunyan 日志庫,官方文檔,基礎(chǔ)字段包含如下:
- v: integer 。bunyan的日志版本號(hào)
- level: integer。日志級(jí)別對(duì)應(yīng)的數(shù)字
- name: string。服務(wù)名
- hostname: string。主機(jī)名
- pid: integer。進(jìn)程號(hào)
- time: string。UTC 格式的日期
- msg: string。日志主體信息
日志擴(kuò)展數(shù)據(jù)
下面定義的各個(gè)數(shù)據(jù)類型的擴(kuò)展數(shù)據(jù),不是 全部的字段,僅包含該日志類型下,必需的字段。這些必需的擴(kuò)展字段,需要在 ELK 中建立索引,方便定位各種問題。
- desc類型日志,擴(kuò)展字段:TODO
- stat類型日志,擴(kuò)展字段:{ perf: {rss: xxxx, cpu: xxx} }
- visit類型日志,擴(kuò)展字段:
- biz
{ ///////////// 基礎(chǔ)數(shù)據(jù) //////// v: 1, level: 20, ///////////// 擴(kuò)展字段 //////// // 標(biāo)志日志類型 scope: "visit", //事件類型:在 visit 的日志類型下,還會(huì)細(xì)分不同的事件,比如 client-req、client-res、 普通trace、請(qǐng)求后端service-start, service-end, service-err等。 event: "trace", //客戶端ID,追蹤用戶、設(shè)備會(huì)話。在web端,可以是長期的cookie;在APP端,可以是device-id等 rrdid: "", //本次請(qǐng)求的惟一ID,串聯(lián)本次請(qǐng)求的所有相關(guān)日志 req_id: "some-uuid-for-request", //本次請(qǐng)求的用戶ID uid: "", //本次請(qǐng)求的客戶端相關(guān)數(shù)據(jù),通過 ctx.logger 打日志時(shí),自動(dòng)加上 d: { url: "/some/path?include-query", //客戶端ip ip: "10.138.10.1", //客戶端的 userAgent ua: "" }, //本次node請(qǐng)求的處理時(shí)間,毫秒 tm: 500, //該日志相關(guān)的上下文數(shù)據(jù),盡量拼成一個(gè)字符串,放在 extra 里 extra: "", //ERROR 級(jí)別日志,最好包含error相關(guān)信息,比如請(qǐng)求后端相關(guān)參數(shù)等 err: { msg: "", stack: "" }, //調(diào)用后端服務(wù)相關(guān)參數(shù)和響應(yīng) service_req: { host: "", path: "", payload: "" }, service_res: { //http狀態(tài)碼 http_code: 200, //響應(yīng)時(shí)間 tm: 100, //響應(yīng)的body body: "", //異常信息 err: "" } }
什么時(shí)候打日志
開發(fā)者目前只關(guān)心 visit 類型的日志,即和某一次http請(qǐng)求相關(guān)聯(lián)的日志。desc和stat類型的日志,統(tǒng)一由開發(fā)框架封裝后實(shí)現(xiàn),業(yè)務(wù)開發(fā) 不用 關(guān)心。下面講的,都是針對(duì) visit 類型的日志。
一次http請(qǐng)求,會(huì)打出一系列相關(guān)聯(lián)的日志。在node層,通常一次請(qǐng)求,會(huì)進(jìn)一步轉(zhuǎn)發(fā)給N個(gè)后端服務(wù),然后對(duì)后端數(shù)據(jù)進(jìn)行一些處理、合并等操作,最后渲染頁面或是輸出JSON。因此,一次請(qǐng)求相關(guān)的日志,大體分為以下幾種 event:
- client-req: client請(qǐng)求到達(dá)node層,統(tǒng)一由框架打日志,開發(fā) 不 關(guān)心
- service-start: node對(duì)某個(gè)后端服務(wù)發(fā)起請(qǐng)求,由通用請(qǐng)求庫負(fù)責(zé)打日志,開發(fā) 不 關(guān)心
- service-end: node請(qǐng)求某個(gè)后端服務(wù)結(jié)束,由通用請(qǐng)求庫負(fù)責(zé)打日志,開發(fā) 不 關(guān)心
- service-err: node請(qǐng)求后端服務(wù)異常,由通用請(qǐng)求庫負(fù)責(zé)打日志,開發(fā) 不 關(guān)心。調(diào)用后端服務(wù)異常,日志級(jí)別為 WARN,不是 ERROR
- trace: node中業(yè)務(wù)層打的日志,如果異常,能幫助定位本次請(qǐng)求相關(guān)問題
- client-res: 結(jié)束client的請(qǐng)求,打印本次請(qǐng)求的http code,本次請(qǐng)求處理時(shí)間等,由框架統(tǒng)一打,開發(fā) 不 關(guān)心
開發(fā)同學(xué)在打日志時(shí),應(yīng)該謹(jǐn)慎的選擇級(jí)別,INFO(含)級(jí)別以上,都應(yīng)該能對(duì)定位問題、具體業(yè)務(wù)統(tǒng)計(jì)需求有要求,才能使用。大部分情況下,可以使用 DEBUG 級(jí)別,線上 不會(huì) 開啟DEBUG級(jí)別。
具體方法調(diào)用
針對(duì)打印 visit類型的日志,調(diào)用 ctx.logger(基于Koa的框架) 屬性打日志,推薦參數(shù)都傳遞 JSON,具體方法如下:
ctx.logger.debug({msg: "", "extra": "a=1 b=2 c=value"}); ctx.logger.info({msg: "xxx", "extra": "其他的額外字段"}); ctx.logger.warn({msg: "xxx", "extra": "額外上下文數(shù)據(jù)"}); //ERROR級(jí)別日志,應(yīng)該提供 Error 對(duì)象 ctx.logger.error({msg: 'xxx', err: error, extra: ""});
注意1,額外的參數(shù),推薦存放在 extra 字段中,統(tǒng)一拼成 string;如果確實(shí)有必要單獨(dú)出每個(gè)字段, 禁止 額外的參數(shù)占用上述通用字段名!!
注意2,基礎(chǔ)數(shù)據(jù)中的msg字段,禁止 包含具體的上下文數(shù)據(jù),和該日志相關(guān)的上下文數(shù)據(jù),應(yīng)該拼成字符串,放在單獨(dú)的 extra 字段中。比如,某個(gè)用戶登錄接口,希望統(tǒng)計(jì)調(diào)用次數(shù),可以這樣打印:
ctx.logger.info({msg: "user login", "extra": 'mobile=18712387101 code=xxxx k3=value3'});
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Nodejs文件上傳、監(jiān)聽上傳進(jìn)度的代碼
這篇文章主要介紹了Nodejs文件上傳、監(jiān)聽上傳進(jìn)度,本文通過實(shí)例代碼給大家詳細(xì)介紹,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03利用adb shell和node.js實(shí)現(xiàn)抖音搶紅包功能(推薦)
這篇文章主要介紹了利用adb shell和node.js實(shí)現(xiàn)抖音搶紅包功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2018-02-02詳解node如何讓一個(gè)端口同時(shí)支持https與http
眾所周知node是一個(gè)高性能的web服務(wù)器,使用它可以很簡單的創(chuàng)建一個(gè)http或https的服務(wù)器。這篇文章主要介紹了詳解node如何讓一個(gè)端口同時(shí)支持https與http2017-07-07Node.js實(shí)現(xiàn)用戶身份驗(yàn)證和授權(quán)的示例代碼
在web開發(fā)中,我們常常需要對(duì)一些敏感的url進(jìn)行訪問權(quán)限控制,本文主要介紹了Node.js實(shí)現(xiàn)用戶身份驗(yàn)證和授權(quán)的示例代碼,具有一定的參考價(jià)值,感興趣的了解一下2024-02-02解決npm?install版本不匹配問題:?npm?ERR!?code?ETARGET?npm?ERR!?
這篇文章主要介紹了如何解決npm?install版本不匹配問題:?npm?ERR!?code?ETARGET?npm?ERR!?notarget?No?matching?version?found?for,文中給出了詳細(xì)的解決方法,需要的朋友可以參考下2024-02-02nodejs部署到騰訊云服務(wù)器的實(shí)現(xiàn)(寶塔面板linux系統(tǒng))
本文主要介紹了nodejs部署到騰訊云服務(wù)器的實(shí)現(xiàn)(寶塔面板linux系統(tǒng)),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06Nest.js Controller路由和請(qǐng)求處理強(qiáng)大功能解析
這篇文章主要為大家,介紹了Nest.js Controller路由和請(qǐng)求處理強(qiáng)大功能解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12