Logstash 处理日志中可有可无的可选字段?
Logstash grok 处理可选字段:用括号加问号 (模式)? 把字段段标记为可选;或用多个模式备选。本文给出具体写法和示例。
核心语法:在 grok 模式中把可选部分用圆括号包起来再加问号——(可选段)?。正则的 ? 让整个分组"出现 0 次或 1 次",字段不存在时该字段留空,整条日志仍能正常匹配。
示例:可选字段
日志有两种格式(有的带用户 ID,有的不带):
2024-01-15 10:30:00 INFO User logged in
2024-01-15 10:30:01 INFO User 42 logged in
grok 模式:
filter {
grok {
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} User( %{NUMBER:user_id})? logged in" }
}
}
( %{NUMBER:user_id})? 表示"空格+数字"这一段是可选的:匹配到时提取 user_id 字段,没匹配到时整个事件照常解析、user_id 字段不存在。
多个可选段
match => { "message" => "%{IP:ip}( - %{WORD:user})? \"%{WORD:method} %{URIPATH:path}\" %{NUMBER:status}( %{NUMBER:duration})?" }
后续处理时判断字段是否存在
if [user_id] {
mutate { convert => { "user_id" => "integer" } }
}
备选方案:多模式匹配
格式差异大时,与其堆叠可选段不如写多个模式:
grok {
match => { "message" => [
"%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} User %{NUMBER:user_id} %{GREEDYDATA:msg}",
"%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} User %{GREEDYDATA:msg}"
] }
}
观测云对照
观测云 Pipeline 的 grok 函数同样支持正则可选分组语法,且提供在线调试:粘贴两种格式的样本日志即可验证模式,比"改配置-重启-看效果"的循环快得多。
常见问题(FAQ)
Q:可选段没匹配时字段是什么值?
A:字段不会出现在事件中(不是 null,是不存在)。用 if [field] 条件判断。
Q:可选段用非贪婪匹配 (??) 有必要吗?
A:一般不需要。(...)? 已足够;?? 是非贪婪量词,用于不同的场景。
Q:给可选字段设默认值?
A:if ![user_id] { mutate { add_field => { "user_id" => "anonymous" } } }。