ELK elasticsearch kibana 日誌排序 之 日誌二級排序
背景:之前搭建ELK時候經常聽開發人員反饋說日誌的資料和伺服器的日誌順序不一致, 看日誌給他們帶來許多煩惱
問題分析:kibana向es(elasticsearch)傳送請求的時候預設排序為@timestamp欄位,然而@timestamp欄位的精度是毫秒, 也就是說如果同一毫秒內輸出多條日誌則在kibana展示的日誌就會出現和伺服器日誌不一致的問題。
解決方案:1 調整日誌收集把時間精度調整到微妙,當時確實也嘗試過,好像不太容易實現(如果讀者有該解決方案可以留言)
2 讓kibana展示日誌除了@timestamp 排序外在加一個二級排序
方案實施:最終我選用了方案二, 方案說明:
我的採集器為filebeat, filebeat採集日誌的時候會增加一個屬性叫做offset欄位, offset欄位標識所讀取日誌的偏移量(行數), 方案二思路:讓kibana請求es的時候除了基於@timestamp外在基於offset排序,那麼如果讓kibana基於offset做二次排序呢, 實現方式為:攔截kibana 傳送到es的請求(_msearch)需改請求內容新增基於offset排序。如何攔截kibana請求報文呢?以下是我的實現方式可供參考:
實現方式一:我們生產環境的kibana是用到了ownhome外掛 ,該外掛其實就是一個代理服務,通過修改ownhome程式碼實現新增offset排序,修改如下:
- 開啟own_home原始碼檔案:vim {kibana_home}/plugins/own_home/server/proxy/modify_payload.js
- 新增如下指令碼到該檔案的 " function replaceRequestBody(body) { 下
- 重啟kibana
- 搜尋頁面驗證
// Replace kibana.index in mget request body function replaceRequestBody(body) { // add default secondary sort for kibana, sort by offset field, add by zhangyuming try{ if (request.path === '/_msearch'){ let lines = body.split('\n'); for(var i = 0; i < lines.length; i++){ if(lines[i].length > 2){ var tmp = JSON.parse(lines[i]); if( typeof(tmp) == "object" && tmp.hasOwnProperty("sort") && tmp["sort"].length == 1 && typeof(tmp["sort"][0]) == "object" && tmp["sort"][0].hasOwnProperty("@timestamp") && tmp["sort"][0]["@timestamp"]["order"] == "desc" ){ server.log(['plugin:own-home', 'debug'], '################ request.path: ' + i + ' : '+ lines[i]); var offsetSort = JSON.parse("{\"offset\":{\"order\":\"desc\",\"unmapped_type\":\"boolean\"}}"); tmp["sort"][1] = offsetSort; lines[i] = JSON.stringify(tmp); body = lines.join("\n"); server.log(['plugin:own-home', 'debug'], '################ request.path: ' + body); } } } } } catch(err){ server.log(['plugin:own-home', 'debug'], 'body add sort fail ' + body + ' : ' + err); } // end default sort for kibana if (!request.path.endsWith('_mget')) { return new Buffer(body); }
實現方式二:我們測試環境沒有用到ownhome外掛,後來自己想了想寫了代理用於修改kibana的報文的工具elsaticproxy。
使用方式:
- 下載elasticproxy工具
- 啟動 ./elasticproxy -elastic_home you_es_host:es_port 預設服務埠為8899
- 修改kibana的es指向指向elasticproxy的8899埠
- 驗證排序
專案說明:目前該專案只實現了kibana的二級排序, 當然你也可以基於該專案實現其他代理功能例如日誌脫敏等代理服務,
專案的開發方式我稍後會完善到github上
歡迎大家使用,或者PR