日志数据采集中的日期时间格式问题解决方案

最佳实践

按照数据流的顺序:

message: 2022-07-22T16:00:00.000+08:00--------带有分隔符T和时区

  •  如果仅用于搜索

logstash配置:log_time和@timestamp都保留

grok {
    match => {
        "message" => "%{TIMESTAMP_ISO8601:log_time}"
    }
}
date {
    match => ["log_time","ISO8601"]
}

解析结果

{   
    "message" => "2022-07-22T16:00:00.000+08:00",
    "log_time" => "2022-07-22T16:00:00.000+08:00",
    "@timestamp" => 2022-07-22T08:00:00.000Z   -----减了8小时,带Z时区,是UTC标准时间
}

存到es的结果:

{   
    "message" => "2022-07-22T16:00:00.000+08:00",
    "log_time" => "2022-07-22T16:00:00.000+08:00",
    "@timestamp" => 2022-07-22T08:00:00.000Z     -----减了8小时,带Z时区,是UTC标准时间
}

查询和返回:

以log_time显示的时间作为基准传值,用@timestamp这个字段查,返回的时候前端用log_time显示

  • 如果需要去掉时区和T分隔符
filter {
    grok {
        match =>{
            "message" => "(?<date>%{YEAR}-%{MONTHNUM}-%{MONTHDAY})[T ](%{TIME:time})"
        }
        add_field => {
            "log_time" => "%{date} %{time}"
        }
    }
    date {
        match => ["log_time","yyyy-MM-dd HH:mm:ss.SSS"]
    }
}

解析结果

{  
    "message" => "2022-07-22T16:00:00.000+08:00",
    "date" => "2022-07-22",
    "time" => "16:00:00.000",
    "log_time" => "2022-07-22 16:00:00.000",
    "@timestamp" => 2022-07-22T08:00:00.000Z,
}

过程分析

es关于date类型分析

另外,logstash-es生命周期需要读取@timestamp字段值,这个字段不能删除

审计中心logstash流程解析

conf-filter内容

filter {
grok {
  match => {
     "message" => "(?<date>(?:\d\d){1,2}-(?:0?[1-9]|1[0-2])-(?:(?:0?[1-9])|(?:[12][0-9])|(?:3[01])))T%{TIME:time}\+08:00%{SPACE}%{LOGLEVEL:logLevel}%{SPACE}(?<componentId>[a-zA-Z0-9]+)\.(?<segment>[a-zA-Z0-9]+)%{SPACE}\[(?<threadName>[a-zA-Z0-9-]*)\]%{SPACE}\[(?<stackTrace>[a-zA-Z\.]+:\d+)\]%{SPACE}\-(?<log_data>.*)"
  }
  add_field => {
      "timestamp" => "%{date} %{time}"
  }
}
date {
    match => ["timestamp","yyyy-MM-dd HH:mm:ss.SSS"]
    target => "@timestamp"        ------这个是默认值,可以不指定
    timezone => "Asia/Shanghai"    ------读取时间值时候的时区,默认是当前系统时区,不用设置,这个不是指logstash存储时候的时区,存储都是用的UTC标准时间
}
}

结论和建议:grok解析时间的地方改为 (?<date>%{YEAR}-%{MONTHNUM}-%{MONTHDAY})[T ](%{TIME:time})

解析结果示例

结论

message时间解析出来后去掉字符T和时区给到了字段timestamp

然后赋值给@timestamp加了上海时区

message:     2022-07-22T16:00:00.000+08:00

timestamp:  2022-07-22 16:00:00.000  ----给flink用,因为flink不支持解析T和0800

@timestamp:2022-07-22T08:00:00.000Z----存到es的时间,显示上隔8个小时,搜索用这个字段,搜索的结果用timestamp字段

日志汇搜logstash流程解析

conf-filter内容

filter {
   grok {
      match => {
         "message" => "%{TIMESTAMP_ISO8601:log_time}%{SPACE}%{LOGLEVEL:log_level}%{SPACE}(?<component>[a-zA-Z0-9]+)\.(?<segment>[a-zA-Z0-9]+)%{SPACE}\[(?<thread_name>[a-zA-Z0-9-]*)\]%{SPACE}\[(?<java_class>[a-zA-Z\.]+:\d+)\]%{SPACE}(<(?<trace_id>[a-z0-9]*))?,?((?<span_id>[a-z0-9]*)>)?%{SPACE}\[?(?<error_code>[a-zA-Z0-9]*)?\]?%{SPACE}%{SPACE}(?<log_data>.*)"
      }
   }
}

解析结果示例

 

结论

解析出来的日志时间字段是log_time,原封不动的截取的字符值2022-07-22T16:00:00.000+08:00

带有+08:00时区标志,存入es后的显示时间和日志本身的时间一致,查询条件和搜索结果都不需要处理

@timestamp是采集时间,没有实际业务含义

Es测试动态mapping下不同日期格式的测试方案

1、 创建2个索引,均为动态mapping,时间字段均为@timestamp

(1)yanbiao_test_01(动态不指定date)

put    http://10.192.77.152:9200/yanbiao_test_01

{
       "mappings": {"dynamic": "true"  }
 }

(2)yanbiao_test_02(动态mapping且指定date)

put    http://10.192.77.152:9200/yanbiao_test_02

{
    "mappings": {
           "dynamic": "true",
           "properties": {
                "@timestamp":{
                       "type":"date",
                       "format": "yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd'T'HH:mm:ss.SSS’Z’"
                 }
           }
     }
}

2、向2个索引分别插入值为

2022-07-22T16:00:00.000+08:00

2022-07-22T16:00:00.000Z

2022-07-22 16:00:00.000

插入第一个索引

Post  http://10.192.77.152:9200/yanbiao_test_01/_doc/

{"@timestamp":"2022-07-22T16:00:00.000+08:00"}  --成功

{"@timestamp":"2022-07-22T16:00:00.000Z"}          --成功

{"@timestamp":"2022-07-22 16:00:00.000"}             ---失败,印证了上述结论,这种格式需要事先指定格式

 插入第二个索引

Post  http://10.192.77.152:9200/yanbiao_test_02/_doc/

{"@timestamp":"2022-07-22T16:00:00.000+08:00"} ------失败,指定的格式中不支持这种

{"@timestamp":"2022-07-22T16:00:00.000Z"}     ------成功

{"@timestamp":"2022-07-22 16:00:00.000"}       ------成功

观察插入结果,主要观察插入是否成功,插入后在head中查看时是否减去了8小时

结论:插入后都没有8小时误差

3、针对2个索引做时间范围查询,确定查询条件是否需要增加时区或者加8小时才能查到

观察查询结果

 

注意:查询条件只需要转为时间戳查询,不需要处理8小时的问题

Logstash关于时间字段的测试方案

bin/logstash -f yanbiao/test_date_es.conf  --path.data=/opt/test/logstash-7.16.2/data/test --path.logs=/opt/test/logstash-7.16.2/logs/test

用这种方式:

grok {
    match => {
        "message" => "%{TIMESTAMP_ISO8601:log_time}"
    }
}

date {
    match => ["log_time","ISO8601"]
    target => "@timestamp"
   # timezone => "Asia/Shanghai"
}

查询用@timestamp,生命周期用@timestamp,这个显示时间会-8小时

展示用log_time(message解析的时间)

@timestamp必须保留,因为后面生命周期可能会用

如果不处理,默认是采集日志时的处理时间,所以必须覆盖掉

几种有问题的思路和结果

grok {
     match => {
         "message" => "%{TIMESTAMP_ISO8601:@timestamp}"
     }
}

上面这种写法,解析后无法覆盖@timestamp

ruby {
     code =>"event.set('@timestamp', LogStash::Timestamp.at(event.get('@timestamp').time.localtime + 8*60*60))"
}

上面这种写法,@timestamp看上去是加了8小时,和正常时间一致,但是查询的时候需要将查询条件也加8小时

mutate {
     rename => { "timestamp" => "@timestamp" }
}

这种写法会报错,@timestamp是系统自带的特殊的字段名,不支持rename插件重命名为这个字段名

 

posted @ 2022-09-09 17:19  鼠标的博客  阅读(2227)  评论(0编辑  收藏  举报