时区问题
其实这个问题是最难受的,记得刚开始研究elk的时候,就发现时间在logstash里比北京时间慢8小时,写入es后,es里的时间也同样是比北京时间慢8小时。
我们也用了kibana,开始奇怪的是在kibana中,时间又显示正常了。后来发现一篇帖子logstash最佳实践中有一段话
很多中国用户经常提一个问题:为什么 @timestamp 比我们早了 8 个小时?怎么修改成北京时间?
其实,Elasticsearch 内部,对时间类型字段,是统一采用 UTC 时间,存成 long 长整形数据的!对日志统一采用 UTC 时间存储,是国际安全/运维界的一个通识——欧美公司的服务器普遍广泛分布在多个时区里——不像中国,地域横跨五个时区却只用北京时间。
对于页面查看,ELK 的解决方案是在 Kibana 上,读取浏览器的当前时区,然后在页面上转换时间内容的显示。
所以,建议大家接受这种设定。否则,即便你用 .getLocalTime 修改,也还要面临在 Kibana 上反过去修改,以及 Elasticsearch 原有的 ["now-1h" TO "now"] 这种方便的搜索语句无法正常使用的尴尬。
以上,请读者自行斟酌。
最后发现如果时间串是带时区的,例如这样2020-04-29T09:39:15.000+0800这个串的含义是UTC+8,也就是2020-04-29T09:39:15.000这个时间已经是加过8小时的。这样在es的mapping中这样设置
"xxx_time" : {
"format" : [
"yyyy-MM-dd'T'HH:mm:ss.SSSZ"
],
"type" : "date"
}
这样es能够识别时区,且kibana显示正常。
分为两种情况,一种是读jdbc时间是timestamp类型,另一种是字符串形式
读jdbc
个人经验,在filter|ruby中,一条数据被封装成了一个event对象。如果是input|jdbc,那么在logstash中的做法如下:
filter{
ruby {
# event.get('time')这个类型在ruby中是timestamp。
# event.get('time').time这是ruby中timestamp类型转换成time类型
# event.get('time').time.localtime这是转换成操作系统本地的时区
# 最后就是输出我们想要的字符串 注意后面的小写z
# 输出效果为2020-05-28T11:15:24.000+0800
code => "event.set('time', event.get('time').time.localtime.strftime('%Y-%m-%dT%H:%M:%S.%3N%z'))"
}
}
读文本
input是kafka的话,数据就是字符串,这时候就想办法把时间字符串后面补上+0800即可
# 例如kafka中的数据是json:{"time":"2020-05-28T13:25:31.774"}
filter {
ruby {
code => "
# 直接在后面跟上+0800 凑齐这个格式就OK
event.set('time',event.get('message')+'+0800')
"
}
}
convert转换数据类型
今天在公司有个需求,数据是一条条\t分割的结构化数据。需要做成json数据吐到kafka。正好对logstash比较熟,打算拿logstash做
logstash默认吐出来的数据都是String类型的,同事被吐槽了我一顿。- 使用
filter里的mutute#convert可以自定义数据类型。 - 自己测试的数据如
1 张三 96.9
mutate {
convert => {
"score" => "float"
"id" => "integer"
}
remove_field => ["@timestamp","@version","message"]
}
得到的结果为
{
"name" => "张三",
"score" => 96.9,
"id" => 1
}
- 解决需求!