Logstash filter 插件之 grok Grok 的主要功能 Grok 语法 切出 path 中的特殊目录名称 切出 http 请求的返回状态和响应时间 切分 nginx 日志

本文简单介绍一下 Logstash 的过滤插件 grok。

Grok 是 Logstash 最重要的插件。它可以解析任意文本并把它结构化。因此 Grok 是将非结构化的日志数据解析为可查询的结构化数据的好方法
这个工具非常适合 syslog 日志、apache 和其他 web 服务器日志、mysql 日志,以及那些通常为人(而不是计算机)编写的日志格式。

Grok 使用正则表达式提取日志记录中的数据,这也正是 grok 强大的原因。Grok 使用的正则表达式语法与 Perl 和 Ruby 语言中的正则表达式语法类似。你还可以在 grok 里预定义好命名正则表达式,并在稍后(grok 参数或者其他正则表达式里)引用它。

Grok 语法

语法格式:
%{SYNTAX:SEMANTIC}

SYNTAX 是文本匹配的正则表达式模式。比如 NUMBER 模式可以匹配到 3.15 之类的数字;IP 模式可以匹配到 192.168.0.1 等 IP 地址。
SEMANTIC 是为匹配的文本提供的标识符。比如,3.15 可以是事件的 duration(持续时间),因此可以简单地将其称为 duration;字符串 192.168.0.1 用来标识发出请求的 client。
因此和用下面的模式来结构化日志记录:
%{NUMBER:duration} %{IP:client}

其实上面的模式还不完善,%{NUMBER:duration} 匹配到的内容为字符串。如果你通过 duration 字段进行查询,比较的方式为字符串间的比较。我们可以在 duration 模式中添加数据类型转换的逻辑,将字符串更改为整数,只需要添加目标数据类型的后缀就可以了。例如 %{NUMBER:duration:float},它将 duration 语义从字符串转换为浮点数。目前支持的转换的类型只有 int 和 float。

我们可以通过 Grok Debugger 来学习和测试 grok 模式:

Logstash filter 插件之 grok
Grok 的主要功能
Grok 语法
切出 path 中的特殊目录名称
切出 http 请求的返回状态和响应时间
切分 nginx 日志

下面介绍一些常见的 demo

切出 path 中的特殊目录名称

笔者运维的一个系统中日志文件所在的目录以服务的名称命名,比如下面的 path:

/home/kr/work/sxs/logs/xxx.log

其中 sxs 为服务的名称,所有服务的日志都以该策略保存。所以可以通过 grok 轻松的从 path 中切出服务的名称:

grok {
    match => {
        "path" => "work/(?<service>%{WORD})/logs"
    }
}

使用 grok debugger 测试的结果如下:

Logstash filter 插件之 grok
Grok 的主要功能
Grok 语法
切出 path 中的特殊目录名称
切出 http 请求的返回状态和响应时间
切分 nginx 日志

切出 http 请求的返回状态和响应时间

笔者系统中的日志记录中记录了 http 请求的返回状态和响应时间,其格式大致如下:

xxxxxxx <= [172.18.0.10] [GET /api/users/me] [200] [103.055334 ms]

其中最后两个方括号中分别是返回状态和响应时间(单位毫秒)。可以使用下面的模式切出返回状态和响应时间:

grok {
    match => {
        "message" => "<= [.*] [%{NUMBER:responsestatus}:int] [%{NUMBER:responsetime:float} ms]"
    }
}

上面的代码同时把切出的结果进行了类型转换。由于 grok debuger 不支持类型转换,所以使用下面的模式进行测试:

<= [.*] [%{NUMBER:responsestatus}] [%{NUMBER:responsetime} ms]

结果如下:

Logstash filter 插件之 grok
Grok 的主要功能
Grok 语法
切出 path 中的特殊目录名称
切出 http 请求的返回状态和响应时间
切分 nginx 日志

在 kibana 中,我们可以看到对应字段的类型显示为 number:

Logstash filter 插件之 grok
Grok 的主要功能
Grok 语法
切出 path 中的特殊目录名称
切出 http 请求的返回状态和响应时间
切分 nginx 日志

在 elasticsearch 中这两个字段的类型分别为 long 和 float:

"responsestatus": {
    "type": "long"
},
"responsetime": {
    "type": "float"
},

切分 nginx 日志

我们可以在 nginx 的配置文件中指定其日志的格式,比如下面的配置:

log_format  main  '[$time_local] [$remote_addr] [$request] [$http_user_agent] [$http_referer] [$status] [$request_time]';

使用下面的 grok 规则就能够正确切分出日志记录中的每一个字段:

grok {
    match => {
        "message" => "[%{HTTPDATE:timestamp}] [%{IPV4:client}] [%{DATA:request}] [%{DATA:useragent}] [%{DATA:referer}] [%{NUMBER:responsestatus}] [%{NUMBER:responsetime}]"
    }
}

我们使用下面的一条日志记录在 Grok Debugger 中测试:

[26/Mar/2019:10:13:19 +0000] [52.187.2.193] ["GET /api/hc/mongo HTTP/1.1"] ["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.104 Safari/537.36"] ["-"] [301] [0.050]

Logstash filter 插件之 grok
Grok 的主要功能
Grok 语法
切出 path 中的特殊目录名称
切出 http 请求的返回状态和响应时间
切分 nginx 日志

解析出的内容如下:

{
  "timestamp": [
    [
      "26/Mar/2019:10:13:19 +0000"
    ]
  ],
  "client": [
    [
      "52.187.2.193"
    ]
  ],
  "request": [
    [
      ""GET /api/hc/mongo HTTP/1.1""
    ]
  ],
  "useragent": [
    [
      ""Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.104 Safari/537.36""
    ]
  ],
  "referer": [
    [
      ""-""
    ]
  ],
  "responsestatus": [
    [
      "301"
    ]
  ],
  "responsetime": [
    [
      "0.050"
    ]
  ]
}

参考:
Grok filter plugin
Grok Debugger
《ELK Stack 权威指南》