logstash之grok插件学习
环境
为了方便, 使用docker版本的logstash直接跑实验.
- OS: Ubuntu 18.04.1 64Bit
- Kernel: 5.0.0-37-generic
- logstash v7.5.0
- grok: v4.2.0
- docker community 19.03.5
概述
logstash是一个日志过滤/解析程序, 它基本的工作过程为:
输入(input) => 过滤(filter) => 输出(output)
grok插件工作在filter这一层.
grok可以将任意的文本转换为结构化的数据.
logstash内置了约120种模式(pattern). 你可以在这里找到它们.
当然你也可以添加自己写的模式(请查看设置项: patterns_dir
).
摘抄了一部分"内置模式", 如下:
USERNAME [a-zA-Z0-9._-]+
USER %{USERNAME}
EMAILLOCALPART [a-zA-Z][a-zA-Z0-9_.+-=:]+
EMAILADDRESS %{EMAILLOCALPART}@%{HOSTNAME}
INT (?:[+-]?(?:[0-9]+))
BASE10NUM (?<![0-9.+-])(?>[+-]?(?:(?:[0-9]+(?:\.[0-9]+)?)|(?:\.[0-9]+)))
NUMBER (?:%{BASE10NUM})
BASE16NUM (?<![0-9A-Fa-f])(?:[+-]?(?:0x)?(?:[0-9A-Fa-f]+))
BASE16FLOAT \b(?<![0-9A-Fa-f.])(?:[+-]?(?:0x)?(?:(?:[0-9A-Fa-f]+(?:\.[0-9A-Fa-f]*)?)|(?:\.[0-9A-Fa-f]+)))\b
其实就是预先定义好一些正则, 到时方便引用.
logstash基本使用
默认配置
首先看看logstash的默认配置:
$ docker run --rm -it logstash:7.5.0 bash
bash-4.2$ cat /usr/share/logstash/pipeline/logstash.conf
input {
beats {
port => 5044
}
}
output {
stdout {
codec => rubydebug
}
}
默认从5044端口接收beats的输入, 输出为标准输出(stdout), 也就是打印到屏幕上.
基本测试
为了方便实验, 我们用标准输入(stdin)作为input的部分, 配置如下:
gerrylon@Inspiron-7472:/mnt/data/workspace/test/logstash-grok
$ cat config/logstash.yml
xpack.monitoring.enabled: false
log.level: error
gerrylon@Inspiron-7472:/mnt/data/workspace/test/logstash-grok
$ cat pipeline/logstash.conf
input {
stdin {
}
}
output {
stdout {
codec => rubydebug
}
}
然后用docker启动并随机输入测试:
$ docker run --rm -it -v `pwd`/pipeline/logstash.conf:/usr/share/logstash/pipeline/logstash.conf -v `pwd`/config/logstash.yml:/usr/share/logstash/config/logstash.yml logstash:7.5.0
......省略logstash日志信息
The stdin plugin is now waiting for input:
hello
/usr/share/logstash/vendor/bundle/jruby/2.5.0/gems/awesome_print-1.7.0/lib/awesome_print/formatters/base_formatter.rb:31: warning: constant ::Fixnum is deprecated
{
"@version" => "1",
"message" => "hello",
"@timestamp" => 2019-12-22T02:26:07.653Z,
"host" => "7d4f894f7425"
}
world
{
"@version" => "1",
"message" => "world",
"@timestamp" => 2019-12-22T02:26:13.018Z,
"host" => "7d4f894f7425"
}
grok使用
在上面的基本测试中, 可以看到, 在我们输入"hello"后, logstash会输出:
{
"@version" => "1",
"message" => "hello",
"@timestamp" => 2019-12-22T02:26:07.653Z,
"host" => "7d4f894f7425"
}
自动转成了json格式(结构化的数据).
这个太简单了, 几乎没有什么有用的信息, 因为我们输入也很简单.
平时我们可能使用这样的日志格式在程序中
...
[2019-12-22 10:34:22.523] [INFO] [controller.Get:32] get request from client...
...
上面的日志格式是很常见的, 包括4个字段: 时间, 日志级别, 调用方法及所在行, 打印信息.
那我们来将这4个字段的正则写一下.
grok正则解析使用的是x, 具体在logstash中定义有两种方法:
- 一种是将正则写到某个文件中, 再使用
patterns_dir
设置 - 另一种是直接在logstash的配置文件()中用
pattern_definitions
来定义.
patterns_dir
新增pattern
$ tree .
.
├── config
│ └── logstash.yml
├── patterns ## (这个是新加的)
│ └── mylog
└── pipeline
└── logstash.conf
新增mylog:
$ cat patterns/mylog
# 可以引用已有的模式, 如YEAR
# ref: https://github.com/logstash-plugins/logstash-patterns-core/blob/master/patterns/grok-patterns
MY_TIME %{YEAR}-%{MONTHNUM2}-%{MONTHDAY} %{HOUR}:%{MINUTE}:(?:(?:[0-5][0-9]|60)\.\d+)
MY_LOG_LEVEL %{LOGLEVEL}
MY_FUNC \w[^:]*:\d+
MY_MSG .+
修改 logstash.conf:
$ cat pipeline/logstash.conf
input {
stdin {
}
}
# filter是新加的
filter {
grok {
patterns_dir => ["/opt/logstash/patterns"]
match => {
"message" => [
"^\[%{MY_TIME:time}\] \[%{MY_LOG_LEVEL:level}\] \[%{MY_FUNC:func}\] %{MY_MSG:msg}$"
]
}
}
}
output {
stdout {
codec => rubydebug
}
}
测试:
$ docker run --rm -it -v `pwd`/pipeline/logstash.conf:/usr/share/logstash/pipeline/logstash.conf -v `pwd`/config/logstash.yml:/usr/share/logstash/config/logstash.yml -v `pwd`/patterns:/opt/logstash/patterns/ logstash:7.5.0
......省略logstash的日志
{
"func" => "controller.Get:32",
"message" => "[2019-12-22 10:34:22.523] [INFO] [controller.Get:32] get request from client...",
"host" => "d551adf987fa",
"time" => "2019-12-22 10:34:22.523",
"level" => "INFO",
"@version" => "1",
"msg" => "get request from client...",
"@timestamp" => 2019-12-22T03:26:42.880Z
}
hello world
{
"tags" => [
[0] "_grokparsefailure"
],
"message" => "hello world",
"host" => "d551adf987fa",
"@timestamp" => 2019-12-22T03:26:58.301Z,
"@version" => "1"
}
看效果可以明白, 如果可以正确解析, 会多4个字段出来, 字段名是我们可以自己定义, 如:%{MY_TIME:time}
.
如果按已有模板, 解析不出来, 会多一个_grokparsefailure
的tag,
但是message还是保存着原始输入.
pattern_definitions
$ cat pipeline/logstash.conf
input {
stdin {
}
}
filter {
grok {
# patterns_dir => ["/opt/logstash/patterns"]
match => {
"message" => [
"^\[%{MY_TIME:time}\] \[%{MY_LOG_LEVEL:level}\] \[%{MY_FUNC:func}\] %{MY_MSG:msg}$"
]
}
pattern_definitions => {
"MY_TIME" => "%{YEAR}-%{MONTHNUM2}-%{MONTHDAY} %{HOUR}:%{MINUTE}:(?:(?:[0-5][0-9]|60)\.\d+)"
"MY_LOG_LEVEL" => "%{LOGLEVEL}"
"MY_FUNC" => "\w[^:]*:\d+"
"MY_MSG" => ".+"
}
}
}
output {
stdout {
codec => rubydebug
}
}
运行:
docker run --rm -it -v `pwd`/pipeline/logstash.conf:/usr/share/logstash/pipeline/logstash.conf -v `pwd`/config/logstash.yml:/usr/share/logstash/config/logstash.yml logstash:7.5.0
测试效果和使用patterns_dir
一样
总结:
- 使用
patterns_dir
时, 注意行尾部空格. - 注意logstash.conf中k-v分隔用的是"=>", 不是别的符号, 留意即可.
- 如果出现
_grokparsefailure
, 但是又不知道哪里不对时, 可调试grok语法- grokdebug 这个我没试成功
- Kibana -> Dev Tools -> Grok Debugger 我用这个调试的
- 还有其他的欢迎补充