文章目录
- [Logstash Filter 模块详解](#Logstash Filter 模块详解)
-
- [一、常用 Filter 插件总览](#一、常用 Filter 插件总览)
- 二、多行日志合并(Multiline)
-
- 基本配置
- 正则解析:`^\d{4}-\d{2}-\d{2}`
- 两个关键参数
- 完整逻辑解读
- [业务场景:Java 异常堆栈](#业务场景:Java 异常堆栈)
- [两种 Multiline 版本对比](#两种 Multiline 版本对比)
-
- [codec multiline(内置、推荐)](#codec multiline(内置、推荐))
- [filter multiline(需安装)](#filter multiline(需安装))
- 插件安装(内网离线方案)
- 内置插件清单
- 面试要点
- [三、Logstash Pipeline 执行流程](#三、Logstash Pipeline 执行流程)
- [四、Grok 过滤器详解](#四、Grok 过滤器详解)
- [五、Date 过滤器详解](#五、Date 过滤器详解)
- [六、Mutate 过滤器详解](#六、Mutate 过滤器详解)
-
- 常用配置项
-
- [1. add_field --- 新增字段](#1. add_field — 新增字段)
- [2. remove_field --- 删除字段](#2. remove_field — 删除字段)
- [3. rename --- 重命名字段](#3. rename — 重命名字段)
- [4. convert --- 类型转换](#4. convert — 类型转换)
- [5. gsub --- 正则替换](#5. gsub — 正则替换)
- [6. split --- 字符串转数组](#6. split — 字符串转数组)
- [7. copy --- 复制字段](#7. copy — 复制字段)
- [8. merge --- 合并字段](#8. merge — 合并字段)
- 配置项速查表
- 完整示例
- 执行顺序
- 面试要点
Logstash Filter 模块详解
核心定位:Filter 是 Logstash 的数据处理核心,位于 Input 之后、Output 之前,负责数据的过滤、解析、修改和丢弃。这是 ELK 面试的高频考点,重点关注 grok、mutate、date 三大核心过滤器。
一、常用 Filter 插件总览
面试重点用 ★ 标记,★ 越多越重要。
| 优先级 | 插件 | 核心作用 |
|---|---|---|
| ★★★★★ | grok | 非结构化日志 → 结构化字段(nginx、系统、应用日志) |
| ★★★★★ | mutate | 字段增删改、类型转换、字符串处理(最通用的过滤器) |
| ★★★★☆ | date | 将日志时间赋值给 @timestamp(时间轴准确性的关键) |
| ★★★★ | json | 解析 JSON 字符串字段,展开为 event 字段 |
| ★★★ | dissect | 简单分割文本,性能优于 grok(无正则,适合格式规整日志) |
| ★★★ | drop | 丢弃满足条件的事件 |
| ★★★ | geoip | IP 解析:国家、城市、经纬度(Kibana 地图可视化必备) |
| ★★ | useragent | 解析 User-Agent → 浏览器、操作系统、设备 |
| ★★ | clone | 复制事件,一条日志生成多条副本 |
| ★ | csv | 解析 CSV 格式日志 |
| ★ | prune | 批量保留/删除指定字段 |
各插件详解
1. grok ★★★★★
将非结构化日志解析为结构化字段,使用预定义 pattern 或自定义正则。
ruby
# 示例:解析 nginx 访问日志
grok { match => { "message" => "%{COMBINEDAPACHELOG}" } }
面试要点 :grok 调试工具、_grokparsefailure 标记、自定义 pattern。
2. mutate ★★★★★
字段增删改、类型转换、字符串处理,是使用频率最高的通用过滤器。
| 配置项 | 作用 |
|---|---|
add_field / remove_field |
新增 / 删除字段 |
rename |
重命名字段 |
convert |
类型转换(string → int/float) |
gsub |
正则替换字符串 |
split |
字符串 → 数组 |
merge |
合并数组字段 |
copy |
复制字段 |
mutate 几乎总是和 grok 搭配使用,是 filter 阶段的主力。
3. date ★★★★☆
将日志中的时间字段赋值给 @timestamp,是保证 Kibana 时间轴正确的关键。
- 默认
@timestamp= Logstash 接收时间 ≠ 日志产生时间 - 不配置 date → Kibana 时间轴错乱
4. json ★★★★
解析 JSON 字符串字段,展开为 event 字段。
区分 :
codec => json(input 阶段解码原始输入)vsfilter { json {} }(处理 event 内某个 JSON 字段)。
5. dissect ★★★
简单分割文本,比 grok 性能高,不需要正则,适合格式固定的日志。
grok vs dissect:grok 用正则、灵活但性能稍差;dissect 无正则、性能好但只能处理固定格式。
6. drop ★★★
丢弃满足条件的事件,常用于过滤 debug 日志。
ruby
filter {
if [level] == "debug" {
drop {}
}
}
7. geoip ★★★
根据 IP 解析国家、城市、经纬度,Kibana 地图可视化必备。
注意:新版 Logstash 需自行下载 geoip 数据库文件。
8. 其他插件
- useragent ★★:解析 HTTP User-Agent → 浏览器、OS、设备
- clone ★★:复制事件,一份日志输出到多个目标
- csv ★:解析 CSV 格式日志
- prune ★:批量保留/删除字段
面试总结
必背三大件:grok、mutate、date
高频对比题:
- grok vs dissect 区别
- json codec vs filter json 区别
- date 插件的作用、
@timestamp的含义 _grokparsefailure的原因与排查
记忆口诀:grok 做解析,mutate 改字段,date 校时间,json 解 JSON,dissect 高速分割,geoip 解 IP。
二、多行日志合并(Multiline)
Java 异常堆栈等多行日志需要合并为一条事件,否则每行会被切割成独立日志。
基本配置
ruby
multiline {
pattern => "^\d{4}-\d{2}-\d{2}"
negate => true
what => "previous"
}
正则解析:^\d{4}-\d{2}-\d{2}
| 部分 | 含义 |
|---|---|
^ |
行首锚点(不能漏,否则 multiline 失效) |
\d{4} |
4 位数字 → 年份 |
- |
分隔符 |
\d{2} |
2 位数字 → 月份 |
- |
分隔符 |
\d{2} |
2 位数字 → 日期 |
整体含义 :匹配以 yyyy-MM-dd 日期格式开头的行(如 2026-08-17)。
两个关键参数
negate(取反开关)
| 值 | 行为 |
|---|---|
false(默认) |
匹配上 pattern 的行触发规则 |
true |
未匹配上 pattern 的行触发规则 |
what(合并方向)
| 值 | 行为 |
|---|---|
previous |
当前行合并到上一条事件(Java 堆栈常用) |
next |
当前行合并到下一条事件(很少用) |
完整逻辑解读
ruby
multiline {
pattern => "^\d{4}-\d{2}-\d{2}" # 匹配:以日期开头的行
negate => true # 取反:不以日期开头的行
what => "previous" # 合并到上一条事件
}
业务场景:Java 异常堆栈
text
2026-08-17 10:00:00 [INFO] 发生异常 ← 日期开头 → 新日志起始行
java.lang.NullPointerException ← 非日期开头 → 合并到上一行
at com.xxx.Abc.xxx(Abc.java:22) ← 非日期开头 → 合并到上一行
...
没有 multiline → 堆栈每行被切割成独立日志,一条异常变成 N 条。
两种 Multiline 版本对比
核心区别:multiline 有两个完全不同的版本,这是最常见的混淆点。
| 对比项 | codec multiline(推荐) | filter multiline |
|---|---|---|
| 位置 | input { codec => multiline {} } |
filter { multiline {} } |
| 是否内置 | ✅ 内置,无需安装 | ❌ 需手动安装 logstash-filter-multiline |
| 工作阶段 | 读取日志时(字节层面合并) | filter 阶段(event 层面合并) |
| 性能 | 高,内存压力小 | 低,需缓存多条 event |
| 适用场景 | file input 读取本地日志 | beats/kafka 输入,日志已被拆分为独立 event |
codec multiline(内置、推荐)
ruby
input {
file {
path => "/xxx/app.log"
codec => multiline {
pattern => "^\d{4}-\d{2}-\d{2}"
negate => true
what => "previous"
}
}
}
- Logstash 内置,无需安装
- 在读取阶段完成合并,性能最佳
- 生产环境首选
filter multiline(需安装)
ruby
filter {
multiline {
pattern => "^\d{4}-\d{2}-\d{2}"
negate => true
what => "previous"
}
}
- 需手动安装:
bin/logstash-plugin install logstash-filter-multiline - 仅在 input 阶段无法合并时使用(如 beats/kafka 输入)
- 需缓存 event,内存开销较大
插件安装(内网离线方案)
Logstash 插件是 Ruby gem 包,不能用 yum/apt 安装 ,只能用
logstash-plugin工具。
离线安装步骤:
bash
# 1. 有网机器生成离线包
/usr/share/logstash/bin/logstash-plugin prepare-offline-pack \
--output multiline.zip logstash-filter-multiline
# 2. 拷贝到内网服务器后安装
/usr/share/logstash/bin/logstash-plugin install file:///root/multiline.zip
# 3. 验证安装
/usr/share/logstash/bin/logstash-plugin list | grep multiline
# 4. 重启 Logstash 使插件生效
内置插件清单
grok、mutate、date、json、geoip、drop、csv 等主流 filter 全部内置,无需安装。仅少数冷门插件(如 filter-multiline)需额外安装。
面试要点
- 绝大多数场景用 input codec multiline,内置无需安装
- filter-multiline 是独立插件,需手动安装,不要混淆
- 性能:codec 在字节层面合并 > filter 在 event 层面合并
^行首锚点不能漏,否则 multiline 失效
三、Logstash Pipeline 执行流程
标准流程
Input → Codec → Filter → Output
关键点 :Codec 隶属于 Input/Output,不属于 Filter,这是最常见的混淆点。
各阶段详解
1. Input 阶段
负责读取数据源(file、kafka、beats、tcp、redis 等),获取原始字节流。
ruby
input {
file {
path => "/var/log/app.log"
codec => multiline { ... } # codec 挂载在 input 内部
}
}
- Input 只负责接收数据,不做解析
- 可挂载
codec对原始字节做解码
2. Codec 编解码阶段
Codec = Coder-Decoder,负责 原始字节流 ↔ Logstash Event 的转换。
| 位置 | 作用 | 方向 |
|---|---|---|
| Input 上的 codec | 解码 | 原始字符串 → Event 对象 |
| Output 上的 codec | 编码 | Event 对象 → 输出字节 |
常见 Codec:
| Codec | 说明 |
|---|---|
plain |
默认,一行一个 event |
multiline |
多行合并为一个 event(内置) |
json |
原始输入为 JSON,直接解析为 event |
json_lines |
每行一条 JSON |
json codec vs filter json 对比:
| 对比项 | codec => json |
filter { json {} } |
|---|---|---|
| 位置 | input 阶段 | filter 阶段 |
| 处理对象 | 原始输入流 | event 内的 JSON 字段 |
| 场景 | 整条输入就是 JSON | message 字段存了 JSON 字符串 |
3. Filter 阶段
处理已成型的 Event 对象,对字段做增删改查、解析、条件判断。
Filter 只能操作 event 字段,不能修改原始字节流。
ruby
filter {
grok { match => { "message" => "%{COMBINEDAPACHELOG}" } }
date { match => [ "timestamp", "dd/MMM/yyyy:HH:mm:ss Z" ] }
mutate { remove_field => ["message"] }
}
- Filter 从上到下依次执行
- 可用
if条件控制是否执行某个过滤器
4. Output 阶段
将处理完的 event 输出到 ES、Kafka、file、stdout 等。
ruby
output {
elasticsearch { hosts => ["127.0.0.1:9200"] }
stdout { codec => rubydebug } # 仅用于调试
}
完整数据流示例
原始日志:
text
2026-08-17 11:00:00 error something
java.lang.NullPoint
at xxx.java:100
处理流程:
| 阶段 | 操作 | 结果 |
|---|---|---|
| Input (file) | 读取文件 | 3 行原始字符串 |
| Codec (multiline) | 多行合并 | 1 个 event,message 包含全部 3 行 |
| Filter | grok 解析 + date 校正 + mutate 清理 | 结构化字段 |
| Output | 写入 Elasticsearch | 完整 event |
如果用 beats 采集,日志已被拆分为 3 条独立 event,此时只能用
filter { multiline {} }在 filter 层合并。
面试要点
- Pipeline 顺序:
Input → Codec → Filter → Output - Codec 不属于 Filter,写在 input/output 块内
- codec multiline 在字节层面合并(高性能),filter multiline 在 event 层面合并(高内存)
- Filter 只能操作 event 字段,不能修改原始字节流
四、Grok 过滤器详解
Grok 是 Logstash 最核心的过滤器,将非结构化日志解析为结构化字段。
基本语法
ruby
filter {
grok {
match => {
"message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{WORD:service} %{IP:client_ip} %{WORD:method} %{URIPATH:path} %{INT:status}"
}
}
}
语法格式 :%{模式名:目标字段名}
%{PATTERN_NAME}:内置预定义正则模式:字段名:将捕获内容存入该字段
匹配示例
原始日志:
text
2026-08-17T14:30:00 INFO order-service 192.168.1.100 GET /api/user 200
解析结果:
| 字段 | 值 |
|---|---|
| timestamp | 2026-08-17T14:30:00 |
| level | INFO |
| service | order-service |
| client_ip | 192.168.1.100 |
| method | GET |
| path | /api/user |
| status | 200 |
类型转换
默认捕获结果为字符串,可用第三参数直接转换类型:
text
%{INT:status:int} # 转为整数
%{NUMBER:rate:float} # 转为浮点数
支持类型:int、float。
匹配失败处理
匹配失败时不会丢弃日志 ,而是打上 _grokparsefailure 标签:
ruby
# 将失败日志单独输出,便于排查
if "_grokparsefailure" in [tags] {
file { path => "/tmp/grok_fail.log" }
}
多模式匹配
match 支持数组,依次尝试,匹配成功即停止:
ruby
grok {
match => { "message" => [
"%{TIMESTAMP_ISO8601:ts} %{LOGLEVEL:lev} ...",
"%{SYSLOGTIMESTAMP:ts} %{WORD:lev} ..."
]}
}
适合多种日志格式混杂的场景。
两种捕获方式
方式一:预定义 Pattern
text
%{PATTERN:field}
- ✅ 简洁,复用官方正则
- ❌ 内置 pattern 有限
- 适合:时间、IP、数字、URI 等通用格式
方式二:原生命名捕获组
text
(?<字段名>正则表达式)
ruby
filter {
grok {
match => {
"message" => "(?<log_time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) %{LOGLEVEL:level} (?<request_url>/api/.*)"
}
}
}
- ✅ 完全自定义
- ❌ 正则需手写,复杂时可读性差
- 适合:业务特殊格式,无现成 pattern
混合使用
两种方式可以在同一表达式中混用:
text
"%{TIMESTAMP_ISO8601:ts} (?<biz_id>biz-[0-9a-f]{8}) %{INT:code:int}"
常用内置 Pattern
| Pattern | 匹配内容 |
|---|---|
TIMESTAMP_ISO8601 |
ISO8601 时间格式 |
LOGLEVEL |
日志级别(INFO/WARN/ERROR...) |
IP / IPV4 / IPV6 |
IP 地址 |
INT |
整数 |
NUMBER |
数字(整数/浮点) |
WORD |
单词(不含空格) |
URIPATH |
URI 路径 |
COMBINEDAPACHELOG |
Nginx/Apache 组合日志格式 |
调试推荐工具:grokdebug,在线测试 grok 表达式,无需重启 Logstash。
常见陷阱
| 问题 | 说明 |
|---|---|
| 空格不对齐 | grok 表达式空格必须与日志严格一致 |
%{WORD} 限制 |
只能匹配不含空格的单词,遇空格截断 |
普通括号 () |
仅分组,不生成字段;必须用 (?<name>...) |
| 部分匹配 | grok 需完整匹配整条 message,否则触发 _grokparsefailure |
部分匹配技巧 :用 .* 吞掉无关字符
text
".* (?<user_id>u[0-9]+) .*"
自定义 Pattern 文件
当正则复杂且多处复用,可写入外部 pattern 文件:
# patterns/custom.patterns
MY_TIMESTAMP \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}
然后在 grok 中引用:
ruby
grok {
patterns_dir => ["/path/to/patterns"]
match => { "message" => "%{MY_TIMESTAMP:ts} ..." }
}
面试要点
- 语法:
%{PATTERN:字段名},支持第三参数类型转换 - 匹配失败打
_grokparsefailure标签,不丢弃日志 - 两种捕获方式可混用:
%{PATTERN:field}和(?<name>regex) - 普通括号
()不生成字段,必须用(?<name>...) - grok 是 filter 插件,不能写在 input codec
五、Date 过滤器详解
Date 过滤器将日志中的时间字段解析后赋值给 @timestamp,是保证 Kibana 时间轴正确的关键。
基本配置
ruby
date {
match => [ "timestamp", "yyyy-MM-dd HH:mm:ss" ]
target => "@timestamp"
}
参数解析
match 参数
格式:[源字段名, 时间格式字符串]
| 参数 | 说明 |
|---|---|
timestamp |
源字段(grok 解析出的时间字符串字段) |
yyyy-MM-dd HH:mm:ss |
时间格式模板 |
支持多格式兜底,依次尝试:
ruby
match => [ "timestamp", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd'T'HH:mm:ss" ]
target 参数
- 指定解析后写入的目标字段
- 默认为
@timestamp,可省略
简写形式(等价):
ruby
date {
match => [ "timestamp", "yyyy-MM-dd HH:mm:ss" ]
}
为什么必须配置 date
@timestamp是 ES/Kibana 识别的事件时间,直接影响时间轴展示。
场景 :日志打印时间 02:00:00,网络延迟导致 Logstash 10:00:00 才收到。
| 配置 | @timestamp 值 | Kibana 显示 |
|---|---|---|
| 不配置 date | 10:00:00(接收时间) | ❌ 时间错乱 |
| 配置 date | 02:00:00(日志时间) | ✅ 时间正确 |
时间格式符号
| 符号 | 含义 | 示例 |
|---|---|---|
yyyy |
4 位年份 | 2026 |
MM |
2 位月份 | 01-12 |
dd |
2 位日期 | 01-31 |
HH |
24 小时制 | 00-23 |
mm |
分钟 | 00-59 |
ss |
秒 | 00-59 |
SSS |
毫秒 | 000-999 |
Z |
时区 | +0800 |
ISO8601 示例 :2026-08-17T16:30:00.123Z → yyyy-MM-dd'T'HH:mm:ss.SSSZ
解析失败处理
格式不匹配时打 _dateparsefailure 标签,不丢弃日志 ,@timestamp 保持接收时间。
ruby
if "_dateparsefailure" in [tags] {
# 处理时间解析失败的日志
}
标准流水线
grok 解析出 timestamp 字段 → date 解析 timestamp 覆盖 @timestamp
面试要点
- date 作用:将日志时间赋值给
@timestamp - 不配置 →
@timestamp= 接收时间 → Kibana 时间轴错乱 - match 支持多格式兜底
- 解析失败打
_dateparsefailure,不丢弃日志
六、Mutate 过滤器详解
Mutate 是 Logstash 最常用的通用字段处理插件,用于对 event 字段进行增删改、类型转换、字符串处理等操作。
常用配置项
1. add_field --- 新增字段
支持引用已有字段 %{字段名} 进行拼接:
ruby
mutate {
add_field => {
"app_name" => "order-service"
"full_info" => "%{level}-%{service}"
}
}
2. remove_field --- 删除字段
清理不再需要的字段,减少 ES 存储:
ruby
mutate {
remove_field => ["message", "timestamp"]
}
grok 解析后通常删除原始 message 字段。
3. rename --- 重命名字段
ruby
mutate {
rename => { "client_ip" => "remote_ip" }
}
4. convert --- 类型转换
将字符串转为 integer/float/string:
ruby
mutate {
convert => {
"status" => "integer"
"response_time" => "float"
}
}
转换失败不丢弃日志,保留原字符串。
5. gsub --- 正则替换
语法:字段 => [正则, 替换内容]
ruby
mutate {
gsub => [
"url", "\?", "#", # ? → #
"content", "\n", "" # 删除换行符
]
}
特殊字符需转义:
\? \n \t
6. split --- 字符串转数组
ruby
# 原值:"info,warn,error"
mutate {
split => { "tags" => "," }
}
# 结果:["info", "warn", "error"]
7. copy --- 复制字段
ruby
mutate {
copy => { "remote_ip" => "client_ip" }
}
8. merge --- 合并字段
ruby
mutate {
merge => { "tag_list" => ["tag1", "tag2"] }
}
注意:gsub、split 只能操作字符串类型。
配置项速查表
| 配置项 | 作用 | 示例 |
|---|---|---|
add_field |
新增字段 | { "key" => "value" } |
remove_field |
删除字段 | ["field1", "field2"] |
rename |
重命名 | { "old" => "new" } |
convert |
类型转换 | { "field" => "integer" } |
gsub |
正则替换 | ["field", "regex", "replace"] |
split |
字符串→数组 | { "field" => "," } |
copy |
复制字段 | { "src" => "dst" } |
merge |
合并数组 | { "field" => ["a","b"] } |
完整示例
ruby
filter {
# 1. grok 解析日志
grok {
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{WORD:service} %{IP:client_ip} %{WORD:method} %{URIPATH:path} %{INT:status}" }
}
# 2. date 校正时间
date {
match => [ "timestamp", "yyyy-MM-dd'T'HH:mm:ss" ]
}
# 3. mutate 字段处理
mutate {
convert => { "status" => "integer" }
rename => { "client_ip" => "src_ip" }
add_field => { "log_source" => "business-log" }
remove_field => ["message", "timestamp"]
}
}
执行顺序
重要 :mutate 内部配置从上到下顺序执行,顺序错误会导致 bug。
典型错误 :先 remove_field 删除字段,再 rename 该字段 → rename 失效。
推荐顺序:
add_field--- 先新增rename--- 再重命名convert--- 类型转换gsub/split--- 字符串处理remove_field--- 最后清理
面试要点
- mutate 是最高频的 filter,几乎必用
- 配置按顺序执行,顺序影响结果
- grok 捕获的都是字符串,常需 convert 转换
- convert 失败不报错,保留原值,需留意
- gsub/split 只能处理字符串类型