问题背景
问题描述
Osprey 线上ES的logger出现问题如下:
从而导致数据无法被dump进ES中。
出现原因
问题的原因在于相同字段前后输入的类型不一致导致dump error。
通过检查宁夏线上集群kibana的mapping:
{
"fluentd-2019.12.16": {
"mappings": {
"properties": {
"@timestamp": {
"type": "date"
},
"cost": {
"type": "float"
},
"field": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"json": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"logger": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"msg": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"ts": {
"type": "date"
},
"version": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
}
可以发现ts
这个字段的类型是 date
类型, 而报错信息中的ts
是个时间戳,为float
类型,从而导致了类型不一致,进而导致错误。
解决方法
将时间戳改为与Readygo相同的时间戳记录方式即可:
func GetLogger() (*zap.Logger, error) {
cfg := zap.NewProductionConfig()
// 标准输出,一般只需要配置这个即可
cfg.OutputPaths = []string{
"stdout",
}
// level只是一个简单的过滤, 只有level >= cfg.level 的日志才会被继续输出
cfg.Level = zap.NewAtomicLevelAt(zap.InfoLevel)
// 输出为 JSON 格式
cfg.Encoding = "json"
// 使用默认生产环境日志编码设置
cfg.EncoderConfig = zap.NewProductionEncoderConfig()
cfg.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
cfg.EncoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
return cfg.Build()
}
效果呈现
在上线最新的osprey v1.3.4版本后,kibana上看不到Osprey staging 项目里的dump error。
但这个error在以下项目中出现:
-
jaeger-agent-daemonset
-
kube-cleanup
-
policy-brain-searcher
-
csc-osprey
-
dori
-
jarvis-client-go
具体可以访问 kibana来查询所有的dump error。以上项目需要检查自己的log信息是否与线上的mapping类型一致
总结
400 dump error 的错误原因在于前后输入的值类型不一致,解决方法是采用一套相同标准来规定一些通用字段。建议全部采用Readygo采取的标准,即将时间格式为ISO8601
.。
另外可能预见的后续问题是:不同项目可能会记录相同的字段,比如osprey在记录时间时,采用的cost
字段,类型为float,但是另外一个项目xxx,它的cost代表花费的是带单位的金钱,类型为string,这时候会导致这个项目无法将日志信息推送至ES。我的建议是将所有具体信息的字段通过json的方式包裹在msg
内,不去单独开一个和msg
并列的字段。
例如线上原本是输入{"msg":"新闻搜索消耗时间", "cost":0.0739479}
,导出成
现在变成输入
{'msg':json.dumps({'title':'新闻搜索消耗时间','cost':0.0739479})}
减少外部字段类型不一致造成冲突的可能性
问题追踪
从状态码400
来看,很明显是推送的格式错误,但因为没有给出具体错误的原因,所以仍然无法得知是哪里格式不正确。
由于之前在policy-brain项目中也是用了ES日志推送的服务,当时也发生了相同的问题,如下:
当时问题的解决方法是将项目中自定义的Logger格式换成和Readygo相同的格式,主要是两处改动:
- 将日期时间格式改为
ISO8601
- 将
level
规定为大写
改动完毕后,Policy-brain的日志信息不再出现dump error的问题,因此对问题产生的原因进行猜测:
- 是否是接收端限定了日志等级的格式?
- 是否是接收端限定了时间的格式?
- 是否是接收端限定了能够接收的字段?
- 根据官方github项目中有人提出的类似 issue,是否因为部分ES服务器结点没有更新新的6.x 的template,导致部分日志出现格式错误?
相关问题检索
Fluent-plugin-elasticsearch 插件官方文档
这里
glich
没猜错的话应该是作者拼错了,应该是名词glitch
故障,看上去像是因为元素类型导致的错误,下面的 solution1 给出了 动态类型的配置方法。solution2 给出了将输入值transform的方法。
Simon blog
作者在dump时也出现了相同的问题,原先他dump进的是个string, 后来他改用了复合类型进行dump,从而导致了错误。由于元素的类型,在导入的第一次就会被确定下来,不会被更改,所以后续当它类型发生变化的时候,就会报错。
参考文献
- Elasticsearch rejects data #493, https://github.com/uken/fluent-plugin-elasticsearch/issues/493
- fluent-plugin-elasticsearch issue, https://rubydoc.info/gems/fluent-plugin-elasticsearch/frames#Random_400_-Rejected_by_Elasticsearch_is_occured__why
- Elasticsearch 400 Error When Upgrading Fluent Winston Log Message Format, https://ramsay.xyz/2018/10/13/elasticsearch-400-error-when-upgrading-fluent-winston-log-message-format.html
- fluent-plugin-elasticsearch usage , https://github.com/uken/fluent-plugin-elasticsearch#usage
- elasticsearch 索引出现值冲突, https://aliasmee.github.io/post/resolve-a-conflict-on-elasticsearch/
网友评论