本文由雲+社群發表
我們都有過上機器查日誌的經歷,當集群數量增多的時候,這種原始的操作帶來的低效率不僅給我們定位現網問題帶來極大的挑戰,同時,我們也無法對我們服務框架的各項指標進行有效的量化診斷,更無從談有針對性的優化和改進。這個時候,構建具備資訊查詢,服務診斷,資料分析等功能的實時日誌監控系統尤為重要。
elk (elk stack: elasticsearch, logstash, kibana, beats) 是一套成熟的日誌解決方案,其開源及高效能在各大公司廣泛使用。而我們業務所使用的服務框架,如何接入 elk 系統呢?
我們的業務框架背景:
我們將整個框架接入 elk 簡單歸納為下面幾個步驟:
傳統的,我們在做日誌輸出的時候,是直接輸出日誌的等級(level)和日誌的內容字串(message)。然而我們不僅關注什麼時間,發生了什麼,可能還需要關注類似的日誌發生了多少次,日誌的細節與上下文,以及關聯的日誌。 因此我們不只是簡單地將我們的日誌結構化一下為物件,還要提取出日誌關鍵的字段。
我們將每一條日誌的發生都抽像為乙個事件。事件包含:
事件元欄位
事件等級:level
, 例如:error
,info
,warning
,debug
事件名稱:event
, 例如:client-request
事件發生的相對時間(單位:納秒):reqlife
, 此字段為事件相對請求開始發生的時間(間隔)
事件發生的位置:line
,**位置;server
, 伺服器的位置
請求元欄位
資料字段
不同型別的事件,需要輸出的細節不盡相同,我們將這些細節(非元字段)統一放到d
-- data,之中。使我們的事件結構更加清晰,同時,也能避免資料字段對元字段造成汙染。
e.g. 如client-init
事件,該事件會在每次伺服器接收到使用者請求時列印,我們將使用者的ip
,url
等事件獨有的統一歸為資料字段放到d
物件中
舉個完整的例子
,
"browser":"",
"engine":"",
"os":"",
"content":"(empty)",
"line":"middlewares/foo.js:14",
"server":"127.0.0.1"
}複製**
一些字段,如:browser,os,engine為什麼在外層 有時候我們希望日誌盡量扁平(最大深度為2),以避免 es 不必要的索引帶來的效能損耗。在實際輸出的時候,我們會將深度大於1的值輸出為字串。而有時候一些物件欄位是我們關注的,所以我們將這些特殊字段放在外層,以保證輸出深度不大於2的原則。一般的,我們在列印輸出日誌的時候,只須關注
事件名稱
及資料字段
即可。其他,我們可以在列印日誌的方法中,通過訪問上下文統一獲取,計算,輸出。
前面我們提到了如何定義乙個日誌事件, 那麼,我們如何基於已有日誌方案做公升級,同時,相容舊**的日誌呼叫方式。
公升級關鍵節點的日誌
// 改造前
logger.info('client-init => ' + json.stringfiy());
// 改造後
logger.info();
複製**
相容舊的日誌呼叫方式logger.debug('checklogin');
複製**
因為 winston 的 日誌方法本身就支援string
或者object
的傳入方式, 所以對於舊的字串傳入寫法,formatter 接收到的實際上是
。formatter 是 winston 的日誌輸出前調整日誌格式的一道工序, 這一點使我們在日誌輸出前有機會將這類呼叫方式輸出的日誌,轉為乙個純輸出事件 -- 我們稱它們為raw-log
事件,而不需要修改呼叫方式。
改造日誌輸出格式
前面提到 winston 輸出日誌前,會經過我們預定義的formatter,因此除了相容邏輯的處理外,我們可以將一些公共邏輯統一放在這裡處理。而呼叫上,我們只關注字段本身即可。
如何提取元欄位,這裡涉及上下文的建立與使用,這裡簡單介紹一下 domain 的建立與使用。
複製**這樣,我們就可以將reqid
輸出到一次請求中所有的事件, 從而達到關聯事件的目的。
我們要在**輸出事件?
事件要輸出什麼細節?
結合一般常見的請求鏈路(使用者請求,服務側接收請求,服務請求下游伺服器/資料庫(*多次),資料聚合渲染,服務響應),如下方的流程圖
流程圖
那麼,我們可以這樣定義我們的事件:
http-success
: 列印於請求返回200:請求位址,請求包體,響應包體(code & msg & data),耗時
http-error
: 列印於請求返回非 200,亦即連線伺服器失敗:請求位址,請求包體,響應包體(code & message & stack),耗時。
字段這麼多,該怎麼選擇? 一言以蔽之,事件輸出的字段原則就是:輸出你關注的,方便檢索的,方便後期聚合的字段。請求下游的請求體和返回體有固定格式, e.g. 輸入:
}
輸出:}
我們可以在事件輸出 action,code 等,以便後期通過 action 檢索某模組具體某個介面的各項指標和聚合。
保證輸出字段型別一致由於所有事件都儲存在同乙個 es 索引, 因此,相同字段不管是相同事件還是不同事件,都應該保持一致,例如:code不應該既是數字,又是字串,這樣可能會產生字段衝突,導致某些記錄(document)無法被衝突字段檢索到。
首先,es 基本的儲存型別大概列舉下,有以下幾種
e.g.
put my_logs
, }}}}
複製**
put _template/my_logs_template
, }}}}
複製**
至此,日誌改造及接入的準備工作都已經完成了,我們只須在機器上安裝 filebeat -- 乙個輕量級的檔案日誌agent, 它負責將日誌檔案中的日誌傳輸到 elk。接下來,我們便可使用 kibana 快速的檢索我們的日誌。 Node 框架接入 ELK 實踐總結
本文由 j2x發表於 雲 社群專欄 我們都有過上機器查日誌的經歷,當集群數量增多的時候,這種原始的操作帶來的低效率不僅給我們定位現網問題帶來極大的挑戰,同時,我們也無法對我們服務框架的各項指標進行有效的量化診斷,更無從談有針對性的優化和改進。這個時候,構建具備資訊查詢,服務診斷,資料分析等功能的實時...
介面測試框架接入效能測試實踐分享
前言 現如今介面測試在軟體質量行業中的地位,已經越來越重要,相對於上層的ui自動化測試和下層的單元測試,介面測試的 低 投入 高 回報,也成了絕大多數質量保障實踐的首選。在開展介面測試時,往往很多時候都只在關注介面的功能性質量,而對於非功能性的質量保障驗證,比如效能 安全,在實際工程應用或者設計用例...
Node實踐總結2 views
既然是寫web應用,自然少不了網頁了。所以我打算先寫檢視的部分,這一塊相較其他部分也更簡單一些。koa2內建支援ejs和jade 由於版權原因已經更名為pug 網頁模板,給開發帶來了一些便利。ejs更接近與原生的html 只是將變數 迴圈等部分嵌入其中,習慣jsp的同學可能會更容易接受。jade模板...