今下午一同事反馈说在 kibana 中没看到日志,但是在对应的日志文件中是能查到的。一开始以为是 kibana 跨时间的问题,但打开日志文件看那条记录,时间是没啥问题的,距离上一条记录前后也只相差10 min左右,而上一条记录在 kibana 中是能找到的。

# 上一条,kibana 中存在
{"@timestamp":"2021-02-01T06:10:11.494Z","datetime":{"timezone_type":3,"date":"2021-02-01 14:10:11.419730","timezone":"PRC"}...}
# 问题日志,kibana 中没有
{"@timestamp":"2021-02-01T06:21:20.038Z","datetime":{"timezone_type":3,"date":"2021-02-01 14:21:19.959002","timezone":"PRC"}...}

        开始怀疑数据应该是没有写入 es 中,于是开始比对 es 和日志文件中日志条数:

# es 中条数
[root@localhost online]# curl http://xx.xxx.xx.xx:9200/_cat/indices/test-index?v
health status index                   uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   test-index   wwXFWMiJQHm0gFNFJULOug             5   1     75            0       1.2mb      648.5kb
# 日志文件中条数
[root@localhost online]# cat test-index.txt | wc -l
79

        看查询结果显然有4条记录没写到 es 中。一开始想法是将该条记录通过调 api 直接写入 es 中,看看 es 会报什么错。但是经多次尝试,试了各种 content-type,始终报如下错误:

{
  "error" : "Content-Type header [xxx] is not supported",
  "status" : 406
}

        这条路看来走不通了,然后又想到既然写入 es 失败,何不看看 es 那是不是有相关日志可以看看呢?日志确实有,但可惜看不到具体的某个 index 每条记录写入情况。最后能想到的就是 logstash 了,因为日志文件是通过 logstash 同时写入 es 和日志文件的。

output {
    if [type] == "test" {
        elasticsearch {
                hosts => ['xx.xxx.xx.xx:9200']
                index => 'test-index'
        }
        file {
                path =>'/data/test-index.txt'
        }
    }
}

        查看 logstash 日志,果然找到了写入 es 失败报错情况,并且恰好4条,输出其中一行:

[root@localhost logstash]# cat nohup.out | grep 2021-02-01 | grep test-index | grep error | wc -l
4
[root@localhost logstash]# cat nohup.out | grep 2021-02-01 | grep test-index | grep error | tail -n 1
[WARN ] 2021-02-01 14:26:00.918 [[main]>worker11] elasticsearch - Could not index event to Elasticsearch. {:status=>400, :action=>["index", 
{:_id=>nil, :_index=>"test-index", :_type=>"doc", :routing=>nil}, #<LogStash::Event:0x6c21663>], :response=>{"index"=>{"_index"=>"test-index", "_type"=>"doc",
 "_id"=>"68NEXHcB3I8Wa61F_M5P", "status"=>400, "error"=>{"type"=>"mapper_parsing_exception", "reason"=>"failed to parse field [context.response]
 of type [text]", "caused_by"=>{"type"=>"illegal_state_exception", "reason"=>"Can't get text on a START_OBJECT at 1:814"}}}}}

        可以看到 response 字段原先是 text 类型,而待写入的日志中 response 字段类型被识别为 object 类型。而在字段已经存在的情况下, es 是不允许修改字段类型的。因为 es 是根据 lucene 实现的倒排索引,一旦生成后就不允许修改,除非使用 reindex API 重建索引。

        至此,写入 es 失败的原因已经找到,只需在业务代码中修改对应处的代码,统一日志格式即可。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐