ELK架构Logstash的相关插件:grok、multiline、mutate、date的详细介绍

文章目录

  • [1. grok (正则捕获插件)](#1. grok (正则捕获插件))
    • [1.1 作用](#1.1 作用)
    • [1.2 正则表达式的类型](#1.2 正则表达式的类型)
      • [1.2.1 内置正则表达式](#1.2.1 内置正则表达式)
      • [1.2.2 自定义正则表达式](#1.2.2 自定义正则表达式)
  • [2. mutate (数据修改插件)](#2. mutate (数据修改插件))
    • [2.1 作用](#2.1 作用)
    • [2.2 常见配置选项](#2.2 常见配置选项)
    • [2.3 应用实例](#2.3 应用实例)
  • [3. multiline (多行合并插件)](#3. multiline (多行合并插件))
    • [3.1 作用](#3.1 作用)
    • [3.2 常用配置项及示例](#3.2 常用配置项及示例)
      • [3.2.1 pattern](#3.2.1 pattern)
      • [3.2.2 negate](#3.2.2 negate)
      • [3.2.3 what](#3.2.3 what)
    • [3.3 插件的安装及应用](#3.3 插件的安装及应用)
      • [3.3.1 插件的安装](#3.3.1 插件的安装)
    • [3.4 插件的使用过程](#3.4 插件的使用过程)
  • [4. date (时间处理插件)](#4. date (时间处理插件))
    • [4.1 作用](#4.1 作用)
    • [4.2 常用的配置项](#4.2 常用的配置项)
      • [4.2.1 match](#4.2.1 match)
      • [4.2.2 target](#4.2.2 target)
      • [4.2.3 timezone](#4.2.3 timezone)
    • [4.3 应用实例](#4.3 应用实例)

1. grok (正则捕获插件)

1.1 作用

使用文本片段切分的方式来切分日志事件

即:将大文本字段分片成若干个小字段。

1.2 正则表达式的类型

  • 内置正则表达式
  • 自定义正则表达式

1.2.1 内置正则表达式

bash 复制代码
#基本格式
%{内置正则表达式:小字段名}

%{SYNTAX:SEMANTIC}

●SYNTAX代表匹配值的类型,例如,0.11可以NUMBER类型所匹配,10.222.22.25可以使用IP匹配。

●SEMANTIC表示存储该值的一个变量声明,它会存储在elasticsearch当中方便kibana做字段搜索和统计,你可以将一个IP定义为客户端IP地址client_ip_address,如%{IP:client_ip_address},所匹配到的值就会存储到client_ip_address这个字段里边,类似数据库的列名,也可以把 event log 中的数字当成数字类型存储在一个指定的变量当中,比如响应时间http_response_time,假设event log record如下:
bash 复制代码
#示例
#用内置正则匹配消息记录

192.168.67.100 GET /index.html 15824 0.043

%{IP:client_id_address} %{WORD:method} %{URIPATHPARAM:request} %{NUMBER:bytes} %{NUMBER:http_response_time}
bash 复制代码
登录kibana,进入Grok Debugger界面
bash 复制代码
#官方网址
https://github.com/logstash-plugins/logstash-patterns-core/blob/main/patterns/ecs-v1/grok-patterns
bash 复制代码
#官方提供的一些常量
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

POSINT \b(?:[1-9][0-9]*)\b
NONNEGINT \b(?:[0-9]+)\b
WORD \b\w+\b
NOTSPACE \S+
SPACE \s*
DATA .*?
GREEDYDATA .*
QUOTEDSTRING (?>(?<!\\)(?>"(?>\\.|[^\\"]+)+"|""|(?>'(?>\\.|[^\\']+)+')|''|(?>(?>\\.|[^\\]+)+)|))
UUID [A-Fa-f0-9]{8}-(?:[A-Fa-f0-9]{4}-){3}[A-Fa-f0-9]{12}
# URN, allowing use of RFC 2141 section 2.3 reserved characters
URN urn:[0-9A-Za-z][0-9A-Za-z-]{0,31}:(?:%[0-9a-fA-F]{2}|[0-9A-Za-z()+,.:=@;$_!*'/?#-])+

# Networking
MAC (?:%{CISCOMAC}|%{WINDOWSMAC}|%{COMMONMAC})
CISCOMAC (?:(?:[A-Fa-f0-9]{4}\.){2}[A-Fa-f0-9]{4})
WINDOWSMAC (?:(?:[A-Fa-f0-9]{2}-){5}[A-Fa-f0-9]{2})
COMMONMAC (?:(?:[A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2})
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}))|:)))(%.+)?
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])
IP (?:%{IPV6}|%{IPV4})
HOSTNAME \b(?:[0-9A-Za-z][0-9A-Za-z-]{0,62})(?:\.(?:[0-9A-Za-z][0-9A-Za-z-]{0,62}))*(\.?|\b)
IPORHOST (?:%{IP}|%{HOSTNAME})
HOSTPORT %{IPORHOST}:%{POSINT}

# paths
PATH (?:%{UNIXPATH}|%{WINPATH})
UNIXPATH (/([\w_%!$@:.,+~-]+|\\.)*)+
TTY (?:/dev/(pts|tty([pq])?)(\w+)?/?(?:[0-9]+))
WINPATH (?>[A-Za-z]+:|\\)(?:\\[^\\?*]*)+
URIPROTO [A-Za-z]([A-Za-z0-9+\-.]+)+
URIHOST %{IPORHOST}(?::%{POSINT:port})?
# uripath comes loosely from RFC1738, but mostly from what Firefox
# doesn't turn into %XX
URIPATH (?:/[A-Za-z0-9$.+!*'(){},~:;=@#%&_\-]*)+
#URIPARAM \?(?:[A-Za-z0-9]+(?:=(?:[^&]*))?(?:&(?:[A-Za-z0-9]+(?:=(?:[^&]*))?)?)*)?
URIPARAM \?[A-Za-z0-9$.+!*'|(){},~@#%&/=:;_?\-\[\]<>]*
URIPATHPARAM %{URIPATH}(?:%{URIPARAM})?
URI %{URIPROTO}://(?:%{USER}(?::[^@]*)?@)?(?:%{URIHOST})?(?:%{URIPATHPARAM})?

# Months: January, Feb, 3, 03, 12, December
MONTH \b(?:[Jj]an(?:uary|uar)?|[Ff]eb(?:ruary|ruar)?|[Mm](?:a|ä)?r(?:ch|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
MONTHNUM (?:0?[1-9]|1[0-2])
MONTHNUM2 (?:0[1-9]|1[0-2])
MONTHDAY (?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9])

# Days: Monday, Tue, Thu, etc...
DAY (?:Mon(?:day)?|Tue(?:sday)?|Wed(?:nesday)?|Thu(?:rsday)?|Fri(?:day)?|Sat(?:urday)?|Sun(?:day)?)

# Years?
YEAR (?>\d\d){1,2}
HOUR (?:2[0123]|[01]?[0-9])
MINUTE (?:[0-5][0-9])
# '60' is a leap second in most time standards and thus is valid.
SECOND (?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?)
TIME (?!<[0-9])%{HOUR}:%{MINUTE}(?::%{SECOND})(?![0-9])
# datestamp is YYYY/MM/DD-HH:MM:SS.UUUU (or something like it)
DATE_US %{MONTHNUM}[/-]%{MONTHDAY}[/-]%{YEAR}
DATE_EU %{MONTHDAY}[./-]%{MONTHNUM}[./-]%{YEAR}
ISO8601_TIMEZONE (?:Z|[+-]%{HOUR}(?::?%{MINUTE}))
ISO8601_SECOND (?:%{SECOND}|60)
TIMESTAMP_ISO8601 %{YEAR}-%{MONTHNUM}-%{MONTHDAY}[T ]%{HOUR}:?%{MINUTE}(?::?%{SECOND})?%{ISO8601_TIMEZONE}?
DATE %{DATE_US}|%{DATE_EU}
DATESTAMP %{DATE}[- ]%{TIME}
TZ (?:[APMCE][SD]T|UTC)
DATESTAMP_RFC822 %{DAY} %{MONTH} %{MONTHDAY} %{YEAR} %{TIME} %{TZ}
DATESTAMP_RFC2822 %{DAY}, %{MONTHDAY} %{MONTH} %{YEAR} %{TIME} %{ISO8601_TIMEZONE}
DATESTAMP_OTHER %{DAY} %{MONTH} %{MONTHDAY} %{TIME} %{TZ} %{YEAR}
DATESTAMP_EVENTLOG %{YEAR}%{MONTHNUM2}%{MONTHDAY}%{HOUR}%{MINUTE}%{SECOND}

# Syslog Dates: Month Day HH:MM:SS
SYSLOGTIMESTAMP %{MONTH} +%{MONTHDAY} %{TIME}
PROG [\x21-\x5a\x5c\x5e-\x7e]+
SYSLOGPROG %{PROG:program}(?:\[%{POSINT:pid}\])?
SYSLOGHOST %{IPORHOST}
SYSLOGFACILITY <%{NONNEGINT:facility}.%{NONNEGINT:priority}>
HTTPDATE %{MONTHDAY}/%{MONTH}/%{YEAR}:%{TIME} %{INT}

# Shortcuts
QS %{QUOTEDSTRING}

# Log formats
SYSLOGBASE %{SYSLOGTIMESTAMP:timestamp} (?:%{SYSLOGFACILITY} )?%{SYSLOGHOST:logsource} %{SYSLOGPROG}:

# Log Levels
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)?)

1.2.2 自定义正则表达式

bash 复制代码
#自定义正则格式:
(?<小字段名>自定义正则表达式)
bash 复制代码
#示例
#目标消息记录
192.168.67.100 - - [14/Oct/2023:11:53:02 +0800] "GET /jxl.html HTTP/1.1" 200 17 "-" "curl/7.29.0" "-"

#按照以下格式显示
  "remote_addr": 
  "response_code": 
  "http_method": 
  "refer_url": 
  "http_version": 
  "request_uri": 
  "user_agent": 
  "access_time": 


#使用的正则表达式
%{IP:remote_addr} - - \[(?<access_time>.+)\] \"%{WORD:http_method} %{URIPATHPARAM:request_uri} (?<http_version>.+)\" %{NUMBER:response_code} [0-9]+ \"(?<refer_url>.+)\" \"(?<user_agent>.+)\" .*

2. mutate (数据修改插件)

2.1 作用

对Logstash收集的日志事件字段进行格式化处理。

2.2 常见配置选项

配置选项 功能
rename 重命名字段名
add_field 添加字段
remove_field 删除字段
replace 替换字段的值
gsub 修改字段值的字符
convert 修改字段值的数据类型

2.3 应用实例

bash 复制代码
#将字段old_field重命名为new_field
filter {
    mutate {
	    #写法1,使用中括号括起来
        rename => ["old_field" => "new_field"]

        #写法2,使用大括号{}括起来
	    rename => { "old_field" => "new_field" }		
    }
}
bash 复制代码
#添加字段
filter {
    mutate {
        add_field => {
        	"f1" => "field1"
        	"f2" => "field2"
        }
    }
}
bash 复制代码
#将字段删除
filter {
    mutate {
        remove_field  =>  ["message", "@version", "tags"]
    }
}
bash 复制代码
#将filedName1字段数据类型转换成string类型,filedName2字段数据类型转换成float类型
filter {
    mutate {
        #写法1,使用中括号括起来
        convert  =>  ["filedName1", "string"]
		
        #写法2,使用大括号{}括起来
		convert => { "filedName2" => "float" }
    }
}

~~~bash
#将filedName字段中所有"/"字符替换为"_"
filter {
    mutate {
        gsub => ["filedName", "/" , "_"]
    }
}
bash 复制代码
#将filedName字段中所有","字符后面添加空格
filter {
    mutate {
        gsub => ["filedName", "," , ", "]
    }
}
bash 复制代码
#将filedName字段以"|"为分割符拆分数据成为数组
filter {
    mutate {
        split => ["filedName", "|"]
    }
}
~~~bash

#合并 "filedName1" 和 " filedName2" 两个字段
filter {
    merge  { "filedName2" => "filedName1" }
}
bash 复制代码
#用新值替换filedName字段的值
filter {
    mutate {
        replace => { "filedName" => "new_value" }
    }
}
bash 复制代码
#添加字段first,值为message数组的第一个元素的值
filter {
    mutate {
        split => ["message", "|"]
        add_field => {
            "first" => "%{[message][0]}"    
        } 
    }
}
bash 复制代码
#有条件的添加标签
filter {
    #在日志文件路径包含 access 的条件下添加标签内容
    if [path] =~ "access" {
        mutate {
            add_tag => ["Nginx Access Log"]
        }
    }
bash 复制代码
    #在日志文件路径是 /var/log/nginx/error.log 的条件下添加标签内容
    if [path] == "/var/log/nginx/error.log" {
        mutate {
            add_tag => ["Nginx Error Log"]
        }
    }
}

3. multiline (多行合并插件)

3.1 作用

将多行日志内容合并成一整行。

3.2 常用配置项及示例

3.2.1 pattern

通过正则表达式匹配行内容

bash 复制代码
#示例
pattern => "^\d{4}-\d{1,2}-\d{1,2}\s\d{1,2}:\d{1,2}:\d{1,2}.\d{3}"

3.2.2 negate

false:不取反,表示正则匹配的行做合并操作。

true:取反,表示正则不匹配的行做合并操作。

bash 复制代码
#示例
negate => true
表示取反

negate => false
表示不取反

3.2.3 what

previous表示向上合并。

next表示向下合并。

bash 复制代码
#示例
what => "previous"
向上合并

what => "next"
向下合并

3.3 插件的安装及应用

3.3.1 插件的安装

bash 复制代码
#方式1:在线安装

cd /usr/share/logstash

bin/logstash-plugin install logstash-filter-multiline
bash 复制代码
#方式2:离线安装
#注:要先在有网的机器上在线安装插件,然后打包,拷贝到服务器,执行安装命令。

bin/logstash-plugin prepare-offline-pack --overwrite --output logstash-filter-multiline.zip logstash-filter-multiline

bin/logstash-plugin install file:///usr/share/logstash/logstash-filter-multiline.zip

3.4 插件的使用过程

  1. 每一条日志的第一行开头都是一个时间,可以用时间的正则表达式匹配到第一行;

  2. 然后将后面每一行的日志与第一行合并;

  3. 当遇到某一行的开头是可以匹配正则表达式的时间的,就停止第一条日志的合并,开始合并第二条日志;

  4. 重复第二步和第三步。

bash 复制代码
filter {
  multiline {
    pattern => "^\d{4}-\d{1,2}-\d{1,2}\s\d{1,2}:\d{1,2}:\d{1,2}.\d{3}"
    negate => true
    what => "previous"
  }
}

4. date (时间处理插件)

4.1 作用

将Logstash收集的日志事件时间@timestamp与日志实际的时间进行格式统一。

需要先配置grok插件模块获取日志时间的小字段。

4.2 常用的配置项

4.2.1 match

bash 复制代码
#示例
match => ["access_time", "dd/MMM/YYYY:HH:mm:ss Z", "UNIX", "yyyy-MM-dd HH:mm:ss", "dd-MMM-yyyy HH:mm:ss"]

用于配置具体的匹配内容规则。

前半部分内容表示匹配实际日志当中的时间戳的名称,后半部分则用于匹配实际日志当中的时间戳格式。

这个地方是整条配置的核心内容,如果此处规则匹配是无效的,则生成后的日志时间戳将会被input插件读取的时间替代。

如果时间格式匹配失败,会生成一个tags字段,字段值为 _dateparsefailure,需要重新检查上边的match配置解析是否正确。

4.2.2 target

将匹配的时间戳存储到给定的目标字段中。

如果未提供,则默认更新事件的@timestamp字段。

bash 复制代码
#示例
target => "@timestamp"

4.2.3 timezone

当需要配置的date里面没有时区信息,而且不是UTC时间,需要设置timezone参数

bash 复制代码
timezone => "Asia/Shanghai"
设置时区为上海

4.3 应用实例

bash 复制代码
#新建子配置文件,用于测试
vim  /etc/logstash/conf.d/test.conf

#在filter块中,启用date插件
filter {
    date {
        match => ["access_time", "dd/MMM/YYYY:HH:mm:ss Z", "UNIX", "yyyy-MM-dd HH:mm:ss", "dd-MMM-yyyy HH:mm:ss"]
                target => "@timestamp"
                timezone => "Asia/Shanghai"
    }
bash 复制代码
#运行配置文件
#还需要启动filebeat收集日志,这里不再赘述
logstash -f test.conf

然后登录到kibana,查看视图的变化
相关推荐
Lee川9 小时前
深度拆解:基于面向对象思维的“就地编辑”组件全模块解析
javascript·架构
勤劳打代码9 小时前
Flutter 架构日记 — 状态管理
flutter·架构·前端框架
子兮曰15 小时前
后端字段又改了?我撸了一个 BFF 数据适配器,从此再也不怕接口“屎山”!
前端·javascript·架构
卓卓不是桌桌17 小时前
如何优雅地处理 iframe 跨域通信?这是我的开源方案
javascript·架构
Qlly17 小时前
DDD 架构为什么适合 MCP Server 开发?
人工智能·后端·架构
用户881586910912 天前
AI Agent 协作系统架构设计与实践
架构
鹏北海2 天前
Qiankun 微前端实战踩坑历程
前端·架构
货拉拉技术2 天前
货拉拉海豚平台-大模型推理加速工程化实践
人工智能·后端·架构
RoyLin2 天前
libkrun 深度解析:架构设计、模块实现与 Windows WHPX 后端
架构
CoovallyAIHub3 天前
实时视觉AI智能体框架来了!Vision Agents 狂揽7K Star,延迟低至30ms,YOLO+Gemini实时联动!
算法·架构·github