【ELK】-8 logstash的filter模块详解

文章目录


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 阶段解码原始输入)vs filter { 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)需额外安装。

面试要点

  1. 绝大多数场景用 input codec multiline,内置无需安装
  2. filter-multiline 是独立插件,需手动安装,不要混淆
  3. 性能:codec 在字节层面合并 > filter 在 event 层面合并
  4. ^ 行首锚点不能漏,否则 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 层合并。

面试要点

  1. Pipeline 顺序:Input → Codec → Filter → Output
  2. Codec 不属于 Filter,写在 input/output 块内
  3. codec multiline 在字节层面合并(高性能),filter multiline 在 event 层面合并(高内存)
  4. 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}   # 转为浮点数

支持类型:intfloat

匹配失败处理

匹配失败时不会丢弃日志 ,而是打上 _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} ..." }
}

面试要点

  1. 语法:%{PATTERN:字段名},支持第三参数类型转换
  2. 匹配失败打 _grokparsefailure 标签,不丢弃日志
  3. 两种捕获方式可混用:%{PATTERN:field}(?<name>regex)
  4. 普通括号 () 不生成字段,必须用 (?<name>...)
  5. 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.123Zyyyy-MM-dd'T'HH:mm:ss.SSSZ

解析失败处理

格式不匹配时打 _dateparsefailure 标签,不丢弃日志@timestamp 保持接收时间。

ruby 复制代码
if "_dateparsefailure" in [tags] {
  # 处理时间解析失败的日志
}

标准流水线

复制代码
grok 解析出 timestamp 字段 → date 解析 timestamp 覆盖 @timestamp

面试要点

  1. date 作用:将日志时间赋值给 @timestamp
  2. 不配置 → @timestamp = 接收时间 → Kibana 时间轴错乱
  3. match 支持多格式兜底
  4. 解析失败打 _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 失效。

推荐顺序

  1. add_field --- 先新增
  2. rename --- 再重命名
  3. convert --- 类型转换
  4. gsub / split --- 字符串处理
  5. remove_field --- 最后清理

面试要点

  1. mutate 是最高频的 filter,几乎必用
  2. 配置按顺序执行,顺序影响结果
  3. grok 捕获的都是字符串,常需 convert 转换
  4. convert 失败不报错,保留原值,需留意
  5. gsub/split 只能处理字符串类型
相关推荐
躺不平的理查德1 小时前
OpenSSL 的异步 TLS 1.3 加密
linux·运维·服务器
楷哥爱开发1 小时前
IPFoxy爬虫代理配置指南:从0搭建Crawl4AI网页爬虫教程
大数据·运维·人工智能·爬虫
A15362551 小时前
WMS 智能仓情系统推荐:如何实现仓库全局可视与数字化管控
运维·数据库·人工智能
shujudang2 小时前
从数据闭环到 Agent 协同:企业营销自动化如何演进为智能运营?
大数据·运维·人工智能·数据分析·自动化
小白说大模型2 小时前
Codex 实战:用 AI 写运维脚本
大数据·运维·网络·人工智能·机器学习·prompt
数字护盾(和中)3 小时前
和中科技剖析 EDR 绕过全链路,AMSI、ETW 规避技术与防御对策
运维·网络·人工智能·科技·安全·web安全
天远Date Lab4 小时前
零信任架构实战:基于天远普通维保查询构建自动化车辆收车评估网关
运维·人工智能·架构·自动化
流星白龙4 小时前
【Docker】9.Docker 镜像仓库实战
运维·docker·容器
张洛闻Eren4 小时前
云原生k8s【第六课】:K8s 访问控制
运维·docker·云原生·容器·kubernetes·k8s