之前介绍filter date插件时就谈到时区问题,但是没有说明白。最近在使用range查询时间范围内的数据时出现了数据量不一致的情况。特地了解了下ELK Stack中关于时区的问题。
问题:
使用kibana discovery界面搜索时,数据量一致。使用curl 搜索时少了数据。
再说时间问题前,简单了解下UTC:
UTC(Universal Time Coordinated) 叫做世界统一时间,中国大陆和 UTC 的时差是 + 8 ,也就是 UTC+8。
UTC时区参考文档
查看官方文档后得到的结论:
ELK Stack集群各服务对时间处理的介绍:
logstash :根据所在机器的时区并对date类型数据进行处理,整理成UTC时间
elastic :所有date类型数据都存储为GMT(毫秒级)
kibana :根据kibana配置的时区,从elastic取出的timestamp时间转换为相应时区的时间。
问题原因:
logstash处理后以UTC时间存储进elastic,kibana取出来后,在恢复成相应时区的时间。因为我机器都是CST的时间,所以使用kibana搜索没有问题,但是curl命令不会对所取出来的时间进行时区转换,所以就少了8小时数据。
解决方法:
一:
logstash 过滤字段信息时,删除或分开匹配时间和时区信息,timestamp
只匹配具体时间,timezone
则匹配+0800
这样的时区信息,并同时定义timezone为UTC,这样从根本上就得到原始的时间。
UTC时间的示例:
$ bin/logstash -f text.conf
[26/Mar/2019:00:00:08 +0800] #这里以nginx日志中的时间为例
{
"timestamp" => "26/Mar/2019:00:00:08",
"message" => "[26/Mar/2019:00:00:08 +0800]",
"@timestamp" => 2019-03-26T00:00:08.000Z, #@timestamp的时间和输入的时间一致
"@version" => "1",
"timezone" => "+0800",
"host" => "node2007"
}
$ cat text.conf
input {
stdin {}
}
filter {
grok {
match => {
"message" => "[%{NOTSPACE:timestamp} %{INT:timezone}]"
}
}
date {
match => [ "timestamp", "dd/MMM/yyyy:HH:mm:ss" ]
timezone => "UTC" #无法从timestamp中提取时区。设置时区为UTC时间,忽略系统时区,如果date插件中的match匹配到了时区,则此处的时区不生效。所以在grok插件中将timezone和timestamp分隔开
}
}
output {
stdout{
codec => rubydebug
}
}
正常时间处理:
$ bin/logstash -f text.conf
[26/Mar/2019:00:00:08 +0800]
{
"@version" => "1",
"@timestamp" => 2019-03-25T16:00:08.000Z, #转换成UTC时间,减少8小时,
"message" => "[26/Mar/2019:00:00:08 +0800]",
"host" => "node2007",
"timestamp" => "26/Mar/2019:00:00:08 +0800"
}
$ cat text.conf
input {
stdin {}
}
filter {
grok {
match => {
"message" => "[%{HTTPDATE:timestamp}]"
}
}
date {
match => [ "timestamp", "dd/MMM/yyyy:HH:mm:ss Z" ]
timezone => "UTC"
}
}
output {
stdout{
codec => rubydebug
}
}
系统日志中不带有时区信息,则可以直接在配置文件中指定timezone => "UTC"
即可。无需要做匹配工作。
二:
匹配到时区时间没有关系,可以在过滤时,在把时间补回来。
...
date {
match => [ "timestamp", "dd/MMM/yyyy:HH:mm:ss Z" ]
target => "time"
}
ruby {
code => "event.set('timestamp', event.get('time').time.localtime + 8*60*60)" #处理时将logstash自动减少的时间在给加回来
}
ruby {
code => "event.set('@timestamp',event.get('timestamp'))"
}
...
以上代码经过我测试,可以正常使用。这里使用ruby插件,我不懂,time -> timestamp -> @timestamp需要经由两个变量才能最后赋值给@timestamp,为什么不能直接使用@timestamp处理并赋值,如果有懂得的人,还请留言告知。
对时间进行处理后,我们可以使用curl命令随意进行查询啦,但是使用kibana时,还需要设置一下默认的时区: Management -> kibana(高级设置) -> Timezone for date formatting 并选择UTC时间展示。 ![](https://img2018.cnblogs.com/blog/1202606/201903/1202606-20190328154358262-1829927564.png)
总结:
ELK Stack一整套组合拳的时区特性特别好用,但是在国内还是统一时区吧。统一时区还是再数据存储前做调整,否则后期查询会流泪的。