背景:之前搭建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排序,修改如下:

  1.   打开own_home源码文件:vim {kibana_home}/plugins/own_home/server/proxy/modify_payload.js
  2. 添加如下脚本到该文件的  " function replaceRequestBody(body) { 下
  3. 重启kibana
  4. 搜索页面验证
// 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。

使用方式:

  1.      下载elasticproxy工具 
  2.     启动 ./elasticproxy -elastic_home you_es_host:es_port  默认服务端口为8899
  3.      修改kibana的es指向指向elasticproxy的8899端口
  4.      验证排序

项目说明:目前该项目只实现了kibana的二级排序, 当然你也可以基于该项目实现其他代理功能例如日志脱敏等代理服务,

                  项目的开发方式我稍后会完善到github上

欢迎大家使用,或者PR