使用 date 插件解析字段中的日期,然后使用该日期或时间戳作为事件的 logstash 时间戳。对于排序事件和导入旧数据,日期过滤器尤其重要。如果您在事件中没有得到正确的日期,那么稍后搜索它们可能会出现问题。
如果时间戳尚未在事件中设置,logstash 将根据第一次看到事件(在输入时)创建一个时间戳。例如,对于文件输入,时间戳设置为每次读取的时间。
本文演示如何把现有的日志数据导入到 elasticsearch 中,并用日志中的时间信息设置事件的时间戳。
拆分日志信息
比如我们的日志格式如下:
[Trace] [e1a618cf-186f-49c5-b486-111e1e5f0023] [2019/03/25] [23:47:20 618]
第一个字段为 loglevel,第二个字段标识 SessionID,第三个字段是产生日志的日志,第四个字段是产生日志的时间,第三、四字段记录的是本地时间,即东八区区时(哈哈,居然不是记一个 UTC 时间戳!)。
我们先使用下面的 grok 规则切分出日志中的字段:
filter { grok { match => { "message" => "[%{LOGLEVEL:loglevel}]s*[(?<SessionID>.*)]s*[(?<Date>%{YEAR}/%{MONTHNUM}/%{MONTHDAY})]s*[(?<Time>%{HOUR}:%{MINUTE}:%{SECOND} %{INT})]" } } }
得到 json 格式的日志记录如下(Grok Debugger 的输出):
{ "loglevel": [ [ "Trace" ] ], "SessionID": [ [ "e1a618cf-186f-49c5-b486-111e1e5f0023" ] ], "Date": [ [ "2019/03/25" ] ], "Time": [ [ "23:47:20 618" ] ] }
合并日期和时间字段
把分散的两个字段合并为时间戳字段,并移除 Date 和 Time 字段:
filter { mutate { add_field => { "Datetime" => "%{Date} %{Time}" } } mutate { remove_field => ["Date"] } mutate { remove_field => ["Time"] } }
拼出来的 DateTime 字段中的内容格式为:
"2019/03/25 23:47:20 618"
为事件设置时间戳
下面使用 date 插件解析字段中的日期,然后使用该日期或时间戳作为事件的 logstash 时间戳:
filter { mutate { add_field => { "logtime" => "%{Datetime}" } } date { timezone => "Asia/Chongqing" match => ["logtime", "yyyy/MM/dd HH:mm:ss SSS"] target => "@timestamp" remove_field => [ "logtime" ] } }
这里使用了一个临时字段 logtime 来保存时间戳,原因是 date 插件会把该字段的类型转换为 date,使用一个临时的字段就不会影响到 Datetime 字段的类型(这也是自定义 @timestamp 时的常用手法)。
注意上面的 timezone 配置,如果日志中的信息是以 UTC 格式保存的,就不需要指定时区。但是笔者处理的日志中,时间信息保存的是东八区的区时,因此需要指定时区信息,date 插件才能把它转换为 UTC 时间。
下图是该记录导入后在 Kibana 中显示的情况,可以看到日期信息和时间戳是一致的: