elastic date时区问题解决办法

之前介绍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时间展示。


总结:

ELK Stack一整套组合拳的时区特性特别好用,但是在国内还是统一时区吧。统一时区还是再数据存储前做调整,否则后期查询会流泪的。

posted @ 2019-03-28 15:52  dance_man  阅读(...)  评论(...编辑  收藏