title: logstash过滤插件——grok #标题tags: grok #标签
date: 2020-05-14
categories: elastic stack # 分类

这篇博文用于整理下grok的使用方法。

grok简单使用示例

示例日志如下:

  1. $ cat /var/log/http.log
  2. 55.3.244.1 GET /index.html 15824 0.043

logstash配置如下:

  1. input {
  2. file {
  3. path => "/var/log/http.log"
  4. }
  5. }
  6. filter {
  7. grok {
  8. match => { "message" => "%{IP:client} %{WORD:method} %{URIPATHPARAM:request} %{NUMBER:bytes} %{NUMBER:duration}" }
  9. }
  10. }
  11. output {
  12. stdout {
  13. codec => rubydebug
  14. }
  15. }

在经过grok过滤器后,日志中的消息应该会多出以下几个字段:

  • client: 55.3.244.1
  • method: GET
  • request: /index.html
  • bytes: 15824
  • duration: 0.043

输出如下:

  1. {
  2. "path" => "/var/log/http.log",
  3. "request" => "/index.html", # uri也匹配到了
  4. "bytes" => "15824", # 字节数也匹配到了
  5. "host" => "es2",
  6. "duration" => "0.043", # 时长也匹配到了
  7. "method" => "GET", # method也匹配到了
  8. "@version" => "1",
  9. "client" => "55.3.244.1", # 第一个ip匹配到了
  10. "message" => "55.3.244.1 GET /index.html 15824 0.043",
  11. "@timestamp" => 2020-05-13T14:39:34.533Z
  12. }

而当我将grok字段注释掉后,则输出如下:

  1. {
  2. "@timestamp" => 2020-05-13T14:47:31.989Z,
  3. "path" => "/var/log/http.log",
  4. "message" => "55.3.244.1 GET /index.html 15824 0.043",
  5. "host" => "es2",
  6. "@version" => "1"
  7. }

grok提供的常用patterns说明

grok提供100多个常用正则表达式可供使用,这100多个正则表达式定义在logstash/vendor/bundle/jruby/x.x/gems/logstash-patterns-core-xxx/patterns/grok-patterns文件中(同时也托管在Github上),想要灵活的匹配各种数据,那么必须查看该文件,大概了解grok提供了什么内置的正则表达式。调用它们的语法如下:%{SYNTAX:SEMANTIC}

  • SYNTAX:表示内置的正则表达式名称
  • SEMANTIC:表示在事件中创建该字段名来存储匹配到的值。

例如:输出的数据内容为“[debug] 127.0.0.1 - test log content”,我们想提取127.0.0.1这个IP地址,那么可以使用以下语法来匹配:%{IP:client},将获得“client: 127.0.0.1”的结果,该结果将成为Event的一个新的字段和字段值;如果你在捕获数据时想进行数据类型转换可以使用%{NUMBER:num:int}这种语法,默认情况下,所有的返回结果都是string类型,当前Logstash所支持的转换类型仅有“int”和“float”;

示例:

  1. # 假设要提取的日志如下:
  2. /index.html GET 114.114.12.166 15824 0.043
  3. # 我要提取其uri、method、ip这三段,则grok对应的语法为:
  4. filter {
  5. grok {
  6. match => {"message" => "%{URIPATHPARAM:request} %{WORD:method} %{IP:myip}"}
  7. }
  8. }

根据上面定义的语法,则捕获到的消息如下:

  1. {
  2. "message" => "/index.html GET 114.114.12.166 15824 0.043",
  3. "host" => "es2",
  4. "path" => "/var/log/http.log",
  5. "@version" => "1",
  6. "request" => "/index.html",
  7. "@timestamp" => 2020-05-13T23:50:38.940Z,
  8. "method" => "GET",
  9. "myip" => "114.114.12.166"
  10. }
  11. # 比默认增加了myip、method、request这三个字段。

grok常用自带表达式

常见字段

USERNAME或USER

正则:

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

作用:

匹配用户名,由数字、大小写及特殊字符(._-)组成的字符串,比如:1234BobAlex.Wong等.

EMAILLOCALPART

正则:

  1. EMAILLOCALPART [a-zA-Z][a-zA-Z0-9_.+-=:]+

作用:

电子邮件用户名部分,首位由大小写字母组成,其他位由数字、大小写及特殊字符(_.+-=:)组成的字符串。注意,国内的QQ纯数字邮箱账号是无法匹配的,需要修改正则。可以匹配:stoneGary_Luabc-123等字符。

EMAILADDRESS

正则:

  1. EMAILADDRESS %{EMAILLOCALPART}@%{HOSTNAME}

作用:

匹配电子邮件(同样无法匹配以数字开头的邮箱,需要修改EMAILLOCALPART的正则即可)可以匹配:stone@abc.comGary_Lu@gmail.comabc-123@163.com

INT

正则:

  1. INT (?:[+-]?(?:[0-9]+))

作用:

整数,包括0和正负整数,比如:0-12343987等。

BASE10NUM及NUMBER

正则

  1. BASE10NUM (?<![0-9.+-])(?>[+-]?(?:(?:[0-9]+(?:\.[0-9]+)?)|(?:\.[0-9]+)))
  2. NUMBER (?:%{BASE10NUM})

作用

十进制数字,包括整数和小数。比如:0-12343987等。

BASE16NUM

正则

  1. BASE16NUM (?<![0-9A-Fa-f])(?:[+-]?(?:0x)?(?:[0-9A-Fa-f]+))

作用

匹配十六进制数字,整数。比如:0x0045fa2d-0x3F8709等。

BASE16FLOAT

正则

  1. BASE16FLOAT \b(?<![0-9A-Fa-f.])(?:[+-]?(?:0x)?(?:(?:[0-9A-Fa-f]+(?:\.[0-9A-Fa-f]*)?)|(?:\.[0-9A-Fa-f]+)))\b

作用

十六进制数字,整数和小数

WORD

正则:

  1. WORD \b\w+\b

作用

匹配字符串,包括数字和大小写字母。比如:String3529345ILoveYou等。

NOTSPACE

正则

  1. NOTSPACE \S+

作用

不带任何空格的字符串。

SPACE

正则

  1. SPACE \s*

作用

空格字符串。

DATA

正则

  1. DATA .*?

作用
. 表示除\n之外的任意字符,表示匹配前面的表达式任意次,例如,zo能匹配“z”,也能匹配“zo”以及“zoo”。*等价于o{0,},z后面匹配0~任意多个o。?匹配前面的子表达式零次或一次。例如,“do(es)?”可以匹配“do”或“does”中的“do”。?等价于{0,1}。

GREEDYDATA

正则

  1. GREEDYDATA .*

作用

如果DATA无法匹配,可以尝试使用这个,或许会有意外之喜。

QUOTEDSTRING

正则

  1. QUOTEDSTRING (?>(?<!\\)(?>"(?>\\.|[^\\"]+)+"|""|(?>'(?>\\.|[^\\']+)+')|''|(?>`(?>\\.|[^\\`]+)+`)|``))

作用

带引号的字符串。如:"This is an apple"'What is your name?'

UUID

正则

  1. UUID [A-Fa-f0-9]{8}-(?:[A-Fa-f0-9]{4}-){3}[A-Fa-f0-9]{12}

作用

标准UUID。比如:550E8400-E29B-11D4-A716-446655440000

网络相关

MAC

正则

  1. MAC (?:%{CISCOMAC}|%{WINDOWSMAC}|%{COMMONMAC})

作用

MAC地址,可以是Cisco设备里的MAC地址,也可以是通用或者Windows系统的MAC地址以及通用得mac地址格式。

CISCOMAC

正则

  1. CISCOMAC (?:(?:[A-Fa-f0-9]{4}\.){2}[A-Fa-f0-9]{4})

作用

用于匹配cisco设备的mac地址。

WINDOWSMAC

正则

  1. WINDOWSMAC (?:(?:[A-Fa-f0-9]{2}-){5}[A-Fa-f0-9]{2})

用途

用于匹配windows的mac地址。

COMMONMAC

正则

  1. COMMONMAC (?:(?:[A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2})

用途

用于匹配通用的mac地址。

IPV6、IPV4、IP

正则

  1. IPV6 ((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?
  2. IPV4 (?<![0-9])(?:(?:[0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5])[.](?:[0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5])[.](?:[0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5])[.](?:[0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5]))(?![0-9])
  3. IP (?:%{IPV6}|%{IPV4})

用途

IPV6用于匹配IPV6地址,IPV4用于匹配IPV4地址,IP则两者都匹配。

HOSTNAME

正则

  1. HOSTNAME \b(?:[0-9A-Za-z][0-9A-Za-z-]{0,62})(?:\.(?:[0-9A-Za-z][0-9A-Za-z-]{0,62}))*(\.?|\b)

用途

用于匹配主机名称。

IPORHOST

正则

  1. IPORHOST (?:%{IP}|%{HOSTNAME})

用途

用于匹配ip或主机名称。

HOSTPORT

  1. HOSTPORT %{IPORHOST}:%{POSINT}

作用

用于匹配主机名(IP)+端口,比如:127.0.0.1:3306api.stozen.net:8000

路径相关

PATH

正则

  1. PATH (?:%{UNIXPATH}|%{WINPATH})

用途

用于匹配路径,unix系统或windows系统里的路径都可以匹配。比如:/usr/local/nginx/sbin/nginxc:\windows\system32\clr.exe

UNIXPATH

正则

  1. UNIXPATH (/([\w_%!$@:.,+~-]+|\\.)*)+

作用

匹配unix系统中的路径。

WINPATH

正则

  1. WINPATH (?>[A-Za-z]+:|\\)(?:\\[^\\?*]*)+

用于匹配windows中的路径。

TTY

正则

  1. TTY (?:/dev/(pts|tty([pq])?)(\w+)?/?(?:[0-9]+))

作用

URIPROTO

正则

  1. URIPROTO [A-Za-z]([A-Za-z0-9+\-.]+)+

用途

URI协议,如:httpftp等。

URIHOST

正则

  1. URIHOST %{IPORHOST}(?::%{POSINT:port})?

用途

URI主机,比如:www.stozen.net10.0.0.1:22等。

URIPATH

正则

  1. URIPATH (?:/[A-Za-z0-9$.+!*'(){},~:;=@#%&_\-]*)+

用途

URI路径,比如://www.stozen.net/abc//api.php等。

URIPARAM

正则

  1. URIPARAM \?[A-Za-z0-9$.+!*'|(){},~@#%&/=:;_?\-\[\]<>]*

URI里的GET参数,如:?a=1&b=2&c=3

URIPATHPARAM

正则

  1. URIPATHPARAM %{URIPATH}(?:%{URIPARAM})?

作用

URI路径+GET参数,比如://www.stozen.net/abc/api.php?a=1&b=2&c=3

URI

正则

  1. URI %{URIPROTO}://(?:%{USER}(?::[^@]*)?@)?(?:%{URIHOST})?(?:%{URIPATHPARAM})?

作用

完整的URI,如:http://www.stozen.net/abc/api.php?a=1&b=2&c=3

时间日期相关

MONTH

正则

  1. MONTH \b(?:[Jj]an(?:uary|uar)?|[Ff]eb(?:ruary|z)?|[Aa]pr(?:il)?|[Mm]a(?:y|i)?|[Jj]un(?:e|i)?|[Jj]ul(?:y)?|[Aa]ug(?:ust)?|[Ss]ep(?:tember)?|[Oo](?:c|k)?t(?:ober)?|[Nn]ov(?:ember)?|[Dd]e(?:c|z)(?:ember)?)\b

作用

月份名称,如:JanJanuary等。

MONTHNUM

正则

  1. MONTHNUM (?:0?[1-9]|1[0-2])

用途

月份数字,比如:03912等。

对于MONTHNUM,还有一个差不多类似的MONTHNUM2,其正则如下:

  1. MONTHNUM2 (?:0[1-9]|1[0-2])

MONTHDAY

正则:

  1. MONTHDAY (?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9])

作用:

日期数字,如:03931等。

DAY

正则:

  1. DAY (?:Mon(?:day)?|Tue(?:sday)?|Wed(?:nesday)?|Thu(?:rsday)?|Fri(?:day)?|Sat(?:urday)?|Sun(?:day)?)

作用:

星期几名称,如:MonMonday等。

YEAR

正则:

  1. YEAR (?>\d\d){1,2}

作用:

年份数字。

HOUR

正则:

  1. HOUR (?:2[0123]|[01]?[0-9])

作用:

小时数字。

MINUTE

正则:

  1. MINUTE (?:[0-5][0-9])

作用:

分钟数字。

SECOND

正则:

  1. SECOND (?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?)

作用:

秒数字。

TIME

正则:

  1. TIME (?!<[0-9])%{HOUR}:%{MINUTE}(?::%{SECOND})(?![0-9])

作用:

时间,如:00:01:23

DATE_US

正则:

  1. DATE_US %{MONTHNUM}[/-]%{MONTHDAY}[/-]%{YEAR}

作用:

美国日期格式,如:10-15-198210/15/1982等。

DATE_EU

正则:

  1. DATE_EU %{MONTHDAY}[./-]%{MONTHNUM}[./-]%{YEAR}

作用:

欧洲日期格式,如:15-10-198215/10/198215.10.1982等。

ISO8601_TIMEZONE

正则:

  1. ISO8601_TIMEZONE (?:Z|[+-]%{HOUR}(?::?%{MINUTE}))

作用:

ISO8601时间格式,如:+10:23-1023等。

TIMESTAMP_ISO8601

正则:

  1. TIMESTAMP_ISO8601 %{YEAR}-%{MONTHNUM}-%{MONTHDAY}[T ]%{HOUR}:?%{MINUTE}(?::?%{SECOND})?%{ISO8601_TIMEZONE}?

作用:

ISO8601时间戳格式,如:2016-07-03T00:34:06+08:00

DATE

正则:

  1. DATE %{DATE_US}|%{DATE_EU}

作用:

日期,美国日期%{DATE_US}或者欧洲日期%{DATE_EU}

DATESTAMP

正则:

  1. DATESTAMP %{DATE}[- ]%{TIME}

作用:

完整日期+时间,如:07-03-2016 00:34:06

HTTPDATE

正则:

  1. HTTPDATE %{MONTHDAY}/%{MONTH}/%{YEAR}:%{TIME} %{INT}

作用:

http默认日期格式,如:03/Jul/2016:00:36:53 +0800

Log相关

SYSLOGTIMESTAMP

正则:

  1. SYSLOGTIMESTAMP %{MONTH} +%{MONTHDAY} %{TIME}

作用:

如:Jan 03 00:01:23

logLEVEL

正则:

  1. LOGLEVEL ([Aa]lert|ALERT|[Tt]race|TRACE|[Dd]ebug|DEBUG|[Nn]otice|NOTICE|[Ii]nfo|INFO|[Ww]arn?(?:ing)?|WARN?(?:ING)?|[Ee]rr?(?:or)?|ERR?(?:OR)?|[Cc]rit?(?:ical)?|CRIT?(?:ICAL)?|[Ff]atal|FATAL|[Ss]evere|SEVERE|EMERG(?:ENCY)?|[Ee]merg(?:ency)?)

作用:日志等级,如:AlertalertALERTError等。

创建自己的grok表达式

在业务中,可能logstash自带的正则表达式并不能很好的满足我们,如:用户身份证号、手机号信息等。所以,手动编写这些正则表达式也是不可能避免的。我这里编写了几个,如下:

表达式 正则表达式 说明
DATE_CHS %{YEAR}[./-]%{MONTHNUM}[./-]%{MONTHDAY} 中国人习惯的日期格式
ZIPCODE_CHS [1-9]\d{5} 国内邮政编码
GAME_ACCOUNT [a-zA-Z][a-zA-Z0-9_]{4,15} 游戏账号,首字符为字母,4-15位字母、数字、下划线组成
NOSQUARE [^[]]+ 非方括号

调试grok正则语法工具

网上也看到过一些在线测试语法的工具,比如:grok debugger,但是体验并不好,个人更喜欢使用kibana带的grok语法调试工具,使用方法如下:

logstash过滤插件——grok - 图1

logstash过滤插件——grok - 图2

匹配nignx日志示例

示例1

日志数据如下:

  1. 10.252.201.136 - - [27/Apr/2020:00:00:01 +0800] "POST /api-stkp/callback HTTP/1.1 200 221" "//192.168.20.4:5601/app/kibana#/dev_tools/grokdebugger?_g=()" "Java/1.8.0_77"

定义的gork规则如下:

  1. %{IP:client} - (%{WORD:remote_user}|-) \[%{HTTPDATE:http_date}\] \"%{WORD:method} %{URIPATHPARAM:url} %{NOTSPACE:http_version} %{NUMBER:status:int} %{NUMBER:body_bytes:int}\" "(%{URIPATHPARAM:http_refere}|-)" \"%{NOTSPACE:http_x_forwarded_for}\"

对数据进行结构化处理后如下:

  1. {
  2. "method": "POST",
  3. "body_bytes": 221,
  4. "http_version": "HTTP/1.1",
  5. "url": "/api-stkp/callback",
  6. "http_refere": "//192.168.20.4:5601/app/kibana#/dev_tools/grokdebugger?_g=()",
  7. "http_date": "27/Apr/2020:00:00:01 +0800",
  8. "http_x_forwarded_for": "Java/1.8.0_77",
  9. "client": "10.252.201.136",
  10. "status": 200
  11. }

示例2

日志格式如下:

  1. 211.136.64.35 - zhangsan [27/Apr/2020:00:00:10 +0800] "GET /XCcorpinter/marketingAcr=19808970412&sign=0f0f839de3f016ffec9b64fd1185a15e&t%3FcBSign%3D18422020042700000949405153e5a87f HTTP/1.0" 200 31 "-" "Java/1.8.0_191"

定义grok规则如下:

  1. %{IP:client} - (%{WORD:remote_user}|-) \[%{HTTPDATE:http_date}\] \"%{WORD:method} %{URIPATHPARAM:url} %{NOTSPACE:http_version}\" %{NUMBER:status:int} %{NUMBER:body_bytes:int} "(%{URIPATHPARAM:http_refere}|-)" \"%{NOTSPACE:http_x_forwarded_for}\"

对数据进行结构化处理后如下:

  1. {
  2. "method": "GET",
  3. "body_bytes": 31,
  4. "http_version": "HTTP/1.0",
  5. "url": "/XCcorpinter/marketingAcr=19808970412&sign=0f0f839de3f016ffec9b64fd1185a15e&t%3FcBSign%3D18422020042700000949405153e5a87f",
  6. "remote_user": "zhangsan",
  7. "http_date": "27/Apr/2020:00:00:10 +0800",
  8. "http_x_forwarded_for": "Java/1.8.0_191",
  9. "client": "211.136.64.35",
  10. "status": 200
  11. }