返回介绍

filter配置 - grok

发布于 2020-06-28 10:03:41 字数 6818 浏览 1446 评论 0 收藏 0

Grok 是 Logstash 最重要的插件。你可以在 grok 里预定义好命名正则表达式,在稍后(grok参数或者其他正则表达式里)引用它。

正则表达式语法

运维工程师多多少少都会一点正则。你可以在 grok 里写标准的正则,像下面这样:

  1. s+(?<request_time>d+(?:.d+)?)s+

小贴士:这个正则表达式写法对于 Perl 或者 Ruby 程序员应该很熟悉了,Python 程序员可能更习惯写 (?P<name>pattern),没办法,适应一下吧。

现在给我们的配置文件添加第一个过滤器区段配置。配置要添加在输入和输出区段之间(logstash 执行区段的时候并不依赖于次序,不过为了自己看得方便,还是按次序书写吧):

  1. input {stdin{}}
  2. filter {
  3. grok {
  4. match => {
  5. "message" => "s+(?<request_time>d+(?:.d+)?)s+"
  6. }
  7. }
  8. }
  9. output {stdout{codec => rubydebug}}

运行 logstash 进程然后输入 “begin 123.456 end”,你会看到类似下面这样的输出:

  1. {
  2. "message" => "begin 123.456 end",
  3. "@version" => "1",
  4. "@timestamp" => "2014-08-09T11:55:38.186Z",
  5. "host" => "raochenlindeMacBook-Air.local",
  6. "request_time" => "123.456"
  7. }

漂亮!不过数据类型好像不太满意……request_time 应该是数值而不是字符串。

我们已经提过稍后会学习用 LogStash::Filters::Mutate 来转换字段值类型,不过在 grok 里,其实有自己的魔法来实现这个功能!

Grok 表达式语法

Grok 支持把预定义的 grok 表达式 写入到文件中,官方提供的预定义 grok 表达式见:https://github.com/logstash-plugins/logstash-patterns-core/tree/master/patterns

注意:在新版本的logstash里面,pattern目录已经为空,最后一个commit提示core patterns将会由logstash-patterns-core gem来提供,该目录可供用户存放自定义patterns

下面是从官方文件中摘抄的最简单但是足够说明用法的示例:

  1. USERNAME [a-zA-Z0-9._-]+
  2. USER %{USERNAME}

第一行,用普通的正则表达式来定义一个 grok 表达式;第二行,通过打印赋值格式(sprintf format),用前面定义好的 grok 表达式来定义另一个 grok 表达式。

grok 表达式的打印赋值格式的完整语法是下面这样的:

  1. %{PATTERN_NAME:capture_name:data_type}

小贴士:data_type 目前只支持两个值:intfloat

所以我们可以改进我们的配置成下面这样:

  1. filter {
  2. grok {
  3. match => {
  4. "message" => "%{WORD} %{NUMBER:request_time:float} %{WORD}"
  5. }
  6. }
  7. }

重新运行进程然后可以得到如下结果:

  1. {
  2. "message" => "begin 123.456 end",
  3. "@version" => "1",
  4. "@timestamp" => "2014-08-09T12:23:36.634Z",
  5. "host" => "raochenlindeMacBook-Air.local",
  6. "request_time" => 123.456
  7. }

这次 request_time 变成数值类型了。

最佳实践

实际运用中,我们需要处理各种各样的日志文件,如果你都是在配置文件里各自写一行自己的表达式,就完全不可管理了。所以,我们建议是把所有的 grok 表达式统一写入到一个地方。然后用 filter/grokpatterns_dir 选项来指明。

如果你把 “message” 里所有的信息都 grok 到不同的字段了,数据实质上就相当于是重复存储了两份。所以你可以用 remove_field 参数来删除掉 message 字段,或者用 overwrite 参数来重写默认的 message 字段,只保留最重要的部分。

重写参数的示例如下:

  1. filter {
  2. grok {
  3. patterns_dir => ["/path/to/your/own/patterns"]
  4. match => {
  5. "message" => "%{SYSLOGBASE} %{DATA:message}"
  6. }
  7. overwrite => ["message"]
  8. }
  9. }

更多有关 grok 正则性能的最佳实践(timeout_millis 等),见:https://www.elastic.co/blog/do-you-grok-grok

小贴士

多行匹配

在和 codec/multiline 搭配使用的时候,需要注意一个问题,grok 正则和普通正则一样,默认是不支持匹配回车换行的。就像你需要 =~ //m 一样也需要单独指定,具体写法是在表达式开始位置加 (?m) 标记。如下所示:

  1. match => {
  2. "message" => "(?m)s+(?<request_time>d+(?:.d+)?)s+"
  3. }

多项选择

有时候我们会碰上一个日志有多种可能格式的情况。这时候要写成单一正则就比较困难,或者全用 | 隔开又比较丑陋。这时候,logstash 的语法提供给我们一个有趣的解决方式。

文档中,都说明 logstash/filters/grok 插件的 match 参数应该接受的是一个 Hash 值。但是因为早期的 logstash 语法中 Hash 值也是用 [] 这种方式书写的,所以其实现在传递 Array 值给 match 参数也完全没问题。所以,我们这里其实可以传递多个正则来匹配同一个字段:

  1. match => [
  2. "message", "(?<request_time>d+(?:.d+)?)",
  3. "message", "%{SYSLOGBASE} %{DATA:message}",
  4. "message", "(?m)%{WORD}"
  5. ]

logstash 会按照这个定义次序依次尝试匹配,到匹配成功为止。虽说效果跟用 | 分割写个大大的正则是一样的,但是可阅读性好了很多。

最后也是最关键的,我强烈建议每个人都要使用 Grok Debugger 来调试自己的 grok 表达式。

grokdebugger

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文