Skip to content

Grok Parser

Sun Jianbo edited this page Aug 8, 2018 · 13 revisions

Grok Parser是一个类似于Logstash Grok Parser一样的解析配置方式,其本质是按照正则表达式匹配解析日志。

典型配置如下

    "parser":{
        "name":"nginx_parser",
        "type":"grok",
        "grok_mode":"",#默认为空
        "grok_patterns":"%{QINIU_LOG_FORMAT}",
        "grok_custom_pattern_files":"/etc/logkit/pattern1,/etc/logkit/pattern2",
        "grok_custom_patterns":"",
        "timezone_offset":"+08",
        "labels":"machine nb110,team pandora"
    },
  • grok_patterns 必填项, 用于匹配日志的grok表达式,多个用逗号分隔。填写解析日志的grok pattern名称,包括一些logkit自身内置的patterns以及自定义的pattern名称,以及社区的常见grok pattern,如logstash的内置pattern以及常见的grok库pattern
    • 填写方式是%{QINIU_LOG_FORMAT},%{COMMON_LOG_FORMAT},以百分号和花括号包裹pattern名称,多个pattern名称以逗号分隔。
    • 实际匹配过程中会按顺序依次去parse文本内容,以第一个匹配的pattern解析文本内容。
    • 需要注意的是,每多一个pattern,解析时都会多解析一个,直到成功为止,所以pattern的数量多有可能降低解析的速度,在数据量大的情况下,建议一个pattern解决数据解析问题。
  • labels 可选项, 填一些额外的标签信息,同样逗号分隔,每个部分由空格隔开,左边是标签的key,右边是value。
  • grok_mode 可选项, 若指定grok_modemulti 可以针对多行日志解析,默认为空,单行匹配。grok和普通正则一样,默认是不支持匹配回车换行,只针对单行进行解析。注意:指定为multi以后,grok会把日志中的换行符替换为空格解析。同时若grok parser希望解析多行,则需要在reader模块填写 head_pattern 行首正则表达式。
  • grok_custom_patterns 用户自定义的grok pattern内容,需符合logkit自定义pattern的写法,按行分隔,参见自定义pattern的写法和用法说明
  • grok_custom_pattern_files 用户自定义的一些grok pattern文件,当自定义pattern太长太多,建议用文件功能。 !!!注意:如果修改pattern文件,需要更新logkit Runner相关配置文件,或者重启logkit才能生效!!!
  • Grok Parser中解析出的字段 就是grok表达式中命名的字段,还包括labels中定义的标签名,可以在sender中选择需要发送的字段和标签。
  • timezone_offset 解析出的时区信息默认为UTC时区,使用timezone_offset可以修改时区偏移量,默认偏移量为0,写法为"+08"、"08"、"8" 均表示比读取时间加8小时,"-08","-8",表示比读取的时间减8小时。若实际为东八区时间,读取为UTC时间,则实际多读取了8小时,需要写"-8",修正回CST中国北京时间。
  • logkit grok pattern 其格式符合 %{<捕获语法>[:<字段名>][:<字段类型>]},其中中括号的内容可以省略
    • logkit的grok pattern是logstash grok pattern的增强版,除了完全兼容logstash grok pattern规则以外,还增加了类型,与telegraf的grok pattern规则一致,但是使用的类型是logkit自身定义的。你可以在logstash grok文档中找到详细的grok介绍.
    • 捕获语法 是一个正则表达式的名字,比如内置了USERNAME [a-zA-Z0-9._-]+,那么此时USERNAME就是一个捕获语法。所以,在使用自定义的正则表达式之前,你需要先为你的正则命名,然后把这个名字当作捕获语法填写patterns中,当然,不推荐自己写正则,建议首选内置的捕获语法。
    • 字段名 按照捕获语法对应的正则表达式解析出的字段,其字段名称以此命名,该项可以不填,但是没有字段名的grok pattern不解析,无法被logkit sender使用,但可以作为一个中间捕获语法与别的捕获语法共同组合一个新的捕获语法
    • 字段类型 可以不填,默认为string。logkit支持以下类型。
      • string 默认的类型
      • long 整型
      • float 浮点型
      • date 时间类型,包括以下格式 - 2006/01/02 15:04:05,
        • 2006-01-02 15:04:05 -0700 MST,
        • 2006-01-02 15:04:05 -0700,
        • 2006-01-02 15:04:05,
        • 2006/01/02 15:04:05 -0700 MST,
        • 2006/01/02 15:04:05 -0700,
        • 2006-01-02 -0700 MST,
        • 2006-01-02 -0700,
        • 2006-01-02,
        • 2006/01/02 -0700 MST,
        • 2006/01/02 -0700,
        • 2006/01/02,
        • Mon Jan _2 15:04:05 2006 ANSIC,
        • Mon Jan _2 15:04:05 MST 2006 UnixDate,
        • Mon Jan 02 15:04:05 -0700 2006 RubyDate,
        • 02 Jan 06 15:04 MST RFC822,
        • 02 Jan 06 15:04 -0700 RFC822Z,
        • Monday, 02-Jan-06 15:04:05 MST RFC850,
        • Mon, 02 Jan 2006 15:04:05 MST RFC1123,
        • Mon, 02 Jan 2006 15:04:05 -0700 RFC1123Z,
        • 2006-01-02T15:04:05Z07:00 RFC3339,
        • 2006-01-02T15:04:05.999999999Z07:00 RFC3339Nano,
        • 3:04PM Kitchen,
        • Jan _2 15:04:05 Stamp,
        • Jan _2 15:04:05.000 StampMilli,
        • Jan _2 15:04:05.000000 StampMicro,
        • Jan _2 15:04:05.000000000 StampNano,
      • drop 表示扔掉该字段
    • 验证自定义pattern的正确性http://grokdebug.herokuapp.com, 这个网站可以debug你的grok pattern
  • disable_record_errdata 默认为false,解析失败的数据会默认出现在"pandora_stash"字段,该选项可以禁止记录解析失败的数据。

如何调试您的grok pattern【grokdebug用法】

  1. 访问网址: http://grokdebug.herokuapp.com
  2. 如下图所示,填写各类信息:

一条示例日志:

[04/Jun/2016:12:41:45 +0100] 1.25 200 192.168.1.1 5.432µs 101

最终使用的grok pattern

%{TEST_LOG_A}

基础的grok pattern构成

# Test A log line:
#   [04/Jun/2016:12:41:45 +0100] 1.25 200 192.168.1.1 5.432µs 101
DURATION %{NUMBER}[nuµm]?s
RESPONSE_CODE %{NUMBER:response_code}
RESPONSE_TIME %{DURATION:response_time}
TEST_LOG_A \[%{HTTPDATE:timestamp:date}\] %{NUMBER:myfloat:float} %{RESPONSE_CODE} %{IPORHOST:clientip} %{RESPONSE_TIME} %{NUMBER:myint:long}

# Test B log line:
#   [04/06/2016--12:41:45] 1.25 mystring dropme nomodifier
TEST_TIMESTAMP %{MONTHDAY}/%{MONTHNUM}/%{YEAR}--%{TIME}
TEST_LOG_B \[%{TEST_TIMESTAMP:timestamp:date}\] %{NUMBER:myfloat:float} %{WORD:mystring:string} %{WORD:dropme:drop} %{WORD:nomodifier}

将grok pattern debug调试完成后的配置落实到logkit配置中

  1. 基础的grok pattern构成 里面的grok pattern填写到本地文件中,假设存储路径为 /home/user/logkit/grok_pattern注意,若修改这个/home/user/logkit/grok_pattern配置文件,需要重启logkit服务(或者修改对应的grok parser的runner配置文件)才能生效
  2. 在 logkit的Runner配置文件中,填写grok parser的 grok_custom_pattern_files 配置项 :"grok_custom_pattern_files":"/home/user/logkit/grok_pattern"
  3. 最终使用的grok pattern 里面的模式串,填写到 grok parser的 grok_patterns配置项:"grok_patterns":"%{TEST_LOG_A}"

根据上述配置,一个完整的grok parser配置如下:

"parser":{
        "name":"nginx_parser",
        "type":"grok",
        "grok_patterns":"%{TEST_LOG_A}",
        "grok_custom_pattern_files":"/home/user/logkit/grok_pattern"
    },

如何使用grok parser 解析nginx/apache日志?

使用grok parser解析nginx/apache日志的过程,实际上就是利用grok pattern(正则表达式)去匹配您的nginx日志,对于像nginx/apache日志这样的成熟日志内容,日志的所有组成部分均已经有非常成熟的grok pattern可以使用,下面我们先介绍下用于解析nginx/apache日志时常用的几个内置在logkit的grok pattern。

常用grok pattern介绍

  1. NOTSPACE 匹配所有非空格的内容,这个是性能较高且最为常用的一个pattern,比如你的日志内容是abc efg,那么你只要写两个NOTSPACE的组合Pattern即可,如 %{NOTSPACE:field1} %{NOTSPACE:field2}
  2. QUOTEDSTRING , 匹配所有被双引号括起来的字符串内容,跟NOTSAPCE类似,会包含双引号一起解析出来,如"abc" - "efx sx" 这样一串日志,写一个组合Pattern%{QUOTEDSTRING:field1} - %{QUOTEDSTRING:field2},field2就包含数据"efx sx",这个同样性能较高,好处是不怕有空格等其他特殊字符,缺点是解析的内容包含了双引号本身,如果要转换成long等类型需要去掉引号。
  3. DATA 匹配所有字符,这个pattern需要结合一些特殊的语境使用,如双引号等特殊字符。举例来说 "abc" - "efx sx",这样一串日志,可以写一个组合Pattern "%{DATA:field1}" - "%{DATA:field2}",这个就起到了QUOTEDSTRING的效果,另外数据中不会包含双引号。
  4. HTTPDATE 匹配常见的HTTP日期类型,类似nginx和Apache生产的timestamp都可以用这个Pattern解析。如[30/Sep/2017:10:50:53 +0800],就可以写一个组合Pattern [%{HTTPDATE:ts:date}],中括号里面包含 HTTPDATE 这个Pattern,就把时间字符串匹配出来了。
  5. NUMBER 匹配数字类型,包括整数和浮点数,利用这个Pattern就可以把nginx里面的如响应时间这样的数据解析出来。如"10.10.111.117:8888" [200] "0.002",就可以写"%{NOTSPACE:ip}" [%{NUMBER:status:long}] "%{NUMBER:resptime:float}" 来解析出status状态码以及resptime响应时间。

基本上,上述这些基础的grok Pattern 组合起来,就可以解决几乎所有nginx的日志解析,但有时候会遇到一些特殊情况,如某个字段可能存在也可能不存在,比如如下两行日志,我们都希望解析。

  1. POST中包含HTTP协议信息
"POST /resouce/abc HTTP/1.1"
  1. GET中不包含协议信息
"GET /resouce/abc"

此时就需要编写一种组合场景,表达的逻辑,此时可以在Pattern组合中融入正则表达式的组概念,如下串即可解析:

MYLOGFIANL "%{WORD:verb} %{NOTSPACE:request}\s*(?: HTTP/%{NUMBER:httpversion}|)"

其中括号就是正则表达式的组,组里面还可以包含组,每个组通过"?"问号开头表示可以存在0次或1次,":"冒号后表达匹配的内容。

在nginx日志中常常还会出现内容为空的情况,为空时nginx字段填充-横杠,此时也可以用类似的方法写。 如这两种数据 0.123 以及 -,如果把"-"当成正常的数字去解析,就会出错,所以需要去掉没有数字的情况,如:

(?:%{NUMBER:bytes}|-)

最后,假设我们遇到一种不太规则的nginx日志写法,如:

110.220.330.550 - - [12/Oct/2017:14:16:50 +0800] "POST /v2/repos/xsxsxs/data HTTP/1.1" 200 729 2 "-" "Faraday v0.13.1" "-" 127.9.2.1:80 www.qiniu.com xsxsxsxsx122dxsxs 0.019

我们就可以用上面描述的方法拼接出如下的串:

NGINX_LOG %{NOTSPACE:client_ip} %{USER:ident} %{USER:auth} \[%{HTTPDATE:ts:date}\] "(?:%{WORD:verb} %{NOTSPACE:request}(?: HTTP/%{NUMBER:http_version:float})?|%{DATA})" %{NUMBER:resp_code} (?:%{NUMBER:resp_bytes:long}|-) (?:%{NUMBER:resp_body_bytes:long}|-) "(?:%{NOTSPACE:referrer}|-)" %{QUOTEDSTRING:agent} %{QUOTEDSTRING:forward_for} %{NOTSPACE:upstream_addr} (%{HOSTNAME:host}|-) (%{NOTSPACE:reqid}) %{NUMBER:resp_time:float}

最后,你可以在logkit的web页面上调试一下。

Clone this wiki locally