在 logstash 的使用中,我遇到最多的问题是通过 grok 对日志清洗的正则规则使用了,把案例记录一下,以便存档吧。
logstash 本身提供了一个 grok 预定义常用表达式的文件,包括%{USER}、%{IP}、%{NUMBER} 、%{DATA}等,可以通过这来了解一下基本的正则写法。路径如下:
/usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-patterns-core-4.0.2/patterns/grok-patterns
这是我们要处理的PHP的slow日志,经过filebeats多行合并之后,我们可以把每一个日志事件部分作为一个完整记录来处理。当然,这是前提,否者我们把每一行作为一条记录来处理的话,就无法得到完整的信息了。如果你的一个日志事件只有一行,那就无视多行合并吧。
[01-Apr-2017 09:03:59] [pool zy.dodoedu.com] pid 29923
script_filename = /data/webapp/wenku.dodoedu.com/index.php
[0x00007fa57ffee260] query() /data/webapp/wenku.dodoedu.com/Cola/Com/Db/Pdo/Abstract.php:83
[0x00007fa57ffee130] query() /data/webapp/wenku.dodoedu.com/Cola/Com/Db/Abstract.php:228
[0x00007fa57ffedf60] col() /data/webapp/wenku.dodoedu.com/Cola/Model.php:583
[0x00007fa57ffedd50] getListBySql() /data/webapp/wenku.dodoedu.com/Models/Index.php:285
[0x00007fa57ffedb88] get_resource_list() /data/webapp/wenku.dodoedu.com/Controllers/List.php:113
[0x00007ffff565c0d0] jsonDataAction() unknown:0
[0x00007fa57ffeda10] call_user_func() /data/webapp/wenku.dodoedu.com/Cola/Cola.php:459
[0x00007fa57ffed8d0] dispatch() /data/webapp/wenku.dodoedu.com/index.php:34
因为php-slow日志的事件内容是非常规范一致的,所以grok语句还比较简单,如下:
(?m)^\[%{MONTHDAY}-%{MONTH}-%{YEAR}\s%{TIME}\]\s\s\[(pool)\s(%{DATA:poolname})\]\s(pid\s%{NONNEGINT:pid})\n%{DATA:filename}\n(?<info>.*)$
通过分解来解释一下 grok 语句:
(?m)
设置标记,打开多行模式的开关,让 ^ 和 $ 匹配整个文本的开头和结尾,而非行首和行尾(因为默认是false的)
^\[%{MONTHDAY}-%{MONTH}-%{YEAR}\s%{TIME}\]
匹配以 [ 开头的行,%{MONTHDAY} 是用来匹配预定义表达式MONTHDAT,同理匹配用 – 分割的MONTH/YEAR,至 ] 结束,整个匹配的是“[01-Apr-2017 09:03:59]“这一部分
\s\s
匹配2个空格
\[(pool)\s(%{DATA:poolname})\]
匹配的是”[pool zy.dodoedu.com] “这一部分,这里用(pool)表示的是固定字符串,%{DATA:poolname} 是指把匹配预定义表达式 DATA 的内容命名为 poolname
\s
匹配1个空格
(pid\s%{NONNEGINT:pid})
匹配”pid 29923“这部分内容,%{NONNEGINT:pid} 是指把匹配预定义表达式 NONNEGINT 的内容命名为pid
\n
匹配1个换行符
%{DATA:filename}
是指把匹配预定义表达式 DATA 的内容命名为 filename
\n
匹配1个换行符
(?<info>.*)$
将当前到文本末尾的全部内容,命名为 info,当然所有的预定义表达式都可以通过这种自主命名的方式来写。
输出的结果如下:
{
“MONTHDAY”: [
[
“01”
]
],
“MONTH”: [
[
“Apr”
]
],
“YEAR”: [
[
“2017”
]
],
“TIME”: [
[
“09:03:59”
]
],
“HOUR”: [
[
“09”
]
],
“MINUTE”: [
[
“03”
]
],
“SECOND”: [
[
“59”
]
],
“poolname”: [
[
“zy.dodoedu.com”
]
],
“pid”: [
[
“29923”
]
],
“filename”: [
[
“script_filename = /data/webapp/wenku.dodoedu.com/index.php”
]
],
“info”: [
[
“[0x00007fa57ffee260] query() /data/webapp/wenku.dodoedu.com/Cola/Com/Db/Pdo/Abstract.php:83\n[0x00007fa57ffee130] query() /data/webapp/wenku.dodoedu.com/Cola/Com/Db/Abstract.php:228\n[0x00007fa57ffedf60] col() /data/webapp/wenku.dodoedu.com/Cola/Model.php:583\n[0x00007fa57ffedd50] getListBySql() /data/webapp/wenku.dodoedu.com/Models/Index.php:285\n[0x00007fa57ffedb88] get_resource_list() /data/webapp/wenku.dodoedu.com/Controllers/List.php:113\n[0x00007ffff565c0d0] jsonDataAction() unknown:0\n[0x00007fa57ffeda10] call_user_func() /data/webapp/wenku.dodoedu.com/Cola/Cola.php:459\n[0x00007fa57ffed8d0] dispatch() /data/webapp/wenku.dodoedu.com/index.php:34”
]
]
}