Grok 是一个十分强大的 Logstash Filter 插件,它可以通过正则解析任意文本,将非结构化日志数据格式转换为结构化的、方便查询的结构。它是目前 Logstash 中解析非结构化日志数据最好的方式。
Grok 的语法规则是:
这里的 “语法” 指的是匹配模式,例如,使用 NUMBER 模式可以匹配出数字,IP 模式则会匹配出 127.0.0.1 这样的 IP 地址。比如按以下格式输入内容:
172.16.213.132 [16/Jun/2020:16:24:19 +0800] "GET / HTTP/1.1" 403 5039
那么,
• %{IP:clientip} 匹配模式将获得的结果为:clientip: 172.16.213.132
• %{HTTPDATE:timestamp} 匹配模式将获得的结果为:timestamp: 16/Jun/2020:16:24:19 +0800
• %{QS:referrer} 匹配模式将获得的结果为:referrer: “GET / HTTP/1.1”
到这里为止,我们已经获取了上面输入中前三个部分的内容,分别是 clientip、timestamp 和 referrer 三个字段。如果要获取剩余部分的信息,方法类似。
要 在线调试 Grok,可点击这里进行在线调试,非常方便。
下面是一个组合匹配模式,它可以获取上面输入的所有内容:
%{IP:clientip}\ \[%{HTTPDATE:timestamp}\]\ %{QS:referrer}\ %{NUMBER:response}\ %{NUMBER:bytes}
正则匹配是非常严格的匹配,在这个组合匹配模式中,使用了转义字符 \,这是因为输入的内容中有空格和中括号。
通过上面这个组合匹配模式,我们将输入的内容分成了 5 个部分,即 5 个字段。将输入内容分割为不同的数据字段,这对于日后解析和查询日志数据非常有用,这正是我们使用 grok 的目的。
Logstash 默认提供了近 200 个匹配模式(其实就是定义好的正则表达式)让我们来使用,可以在 Logstash 安装目录下找到。例如,我这里的路径为:
/usr/local/logstash/vendor/bundle/jruby/2.5.0/gems/logstash-patterns-core-4.1.2/patterns
此目录下有定义好的各种匹配模式,基本匹配定义在 grok-patterns 文件中。从这些定义好的匹配模式中,可以查到上面使用的四个匹配模式对应的定义规则。
除此之外,还有很多默认定义好的匹配模式文件,比如 httpd、java、linux-syslog、redis、mongodb、nagios 等,这些已经定义好的匹配模式,可以直接在 Grok 过滤器中进行引用。当然也可以定义自己需要的匹配模式。
在了解完 Grok 的匹配规则之后,下面通过一个配置实例深入介绍下 Logstash 是如何将非结构化日志数据转换成结构化数据的。首先看下面的一个事件配置文件:
input{
stdin{}
}
filter{
grok{
match => ["message","%{IP:clientip}\ \[%{HTTPDATE:timestamp}\]\ %{QS:referrer}\ %{NUMBER:response}\ %{NUMBER:bytes}"]
}
}
output{
stdout{
codec => "rubydebug"
}
}
在这个配置文件中,输入配置成了 stdin,在 filter 中添加了 grok 过滤插件,并通过 match 来执行正则表达式解析,中括号中的正则表达式就是上面提到的组合匹配模式,然后通过 rubydebug 编码格式输出信息。这样的组合有助于调试和分析输出结果。通过此配置启动 Logstash 进程后,我们仍然输入之前给出的那段内容:
172.16.213.132 [16/Jun/2020:16:24:19 +0800] "GET / HTTP/1.1" 403 5039
然后,查看 rubydebug 格式的日志输出,内容如下:
{
"timestamp" => "16/Jun/2020:16:24:19 +0800",
"response" => "403",
"bytes" => "5039",
"@version" => "1",
"clientip" => "172.16.213.132",
"host" => "nnmaster.cloud",
"referrer" => "\"GET / HTTP/1.1\"",
"message" => "172.16.213.132 [16/Jun/2020:16:24:19 +0800] \"GET / HTTP/1.1\" 403 5039",
"@timestamp" => 2020-06-16T07:46:53.120Z
}
从这个输出可知,通过 Grok 定义好的 5 个字段都获取到了内容,并正常输出了。