日志行字段提取正则
日志提取的效果取决于日志格式的稳定性。设计模式前先采样几十行,确认字段分隔是空格还是引号包裹、空值怎么写、字段本身会不会含分隔符。引号包裹的字段用互斥字符类(例如不含双引号的任意字符)比用非贪婪点星更快也更准,因为前者天然不会越过引号边界。
基本信息
| 设计顺序 | 先确定整体分隔结构,再逐个字段命名,最后加行级过滤条件 |
|---|---|
| 核心技巧 | 引号内用排除引号的字符类,方括号内用排除右方括号的字符类 |
| 空值表示 | 常见为单个连字符,转换类型前必须单独判断 |
| 性能要点 | 先用字面量前缀或长度粗略过滤,再对候选行跑完整模式 |
典型使用场景
- 访问日志分析:拆出客户端地址、时间、请求行、状态码与响应体大小
- 错误日志聚合:从带堆栈的文本里抽出时间、级别与异常类名做聚类
- 审计留痕:把分散的字段整理成结构化记录再入库,便于检索
- 实时告警:先用简单模式匹配关键行,再对命中行做完整字段提取
- 格式迁移:把旧格式日志转成结构化格式,为后续改用解析器铺路
组合格式日志的提取
组合格式日志的提取
# 逐段说明:地址、两个占位字段、方括号时间、引号请求行、状态码、字节数、引号来源、引号客户端
^(?<ip>\S+) \S+ \S+ \[(?<ts>[^\]]+)\] "(?<req>[^"]*)" (?<status>\d{3}) (?<bytes>\S+) "(?<ref>[^"]*)" "(?<ua>[^"]*)"$
# 提取请求行内部的方法与路径:方法到第一个空格,路径到空格或查询串
(?<method>[A-Z]+) (?<path>[^ ?]*)(?:\?(?<query>[^ ]*))?
# 时间字段内部再拆分:方括号内按冒号与空格分段
(?<day>[0-9]{2})/(?<mon>[A-Za-z]{3})/(?<year>[0-9]{4}):(?<hh>[0-9]{2}):(?<mm>[0-9]{2}):(?<ss>[0-9]{2})
# 字段为空时不要直接转数字:先判断是否为单个连字符
if raw == '-': value = None字段写法与说明
| 字段 | 推荐写法 | 说明 |
|---|---|---|
| 客户端地址 | 非空白字符类 | 含端口时会带冒号,需要再拆一次 |
| 时间 | 排除右方括号的字符类 | 格式随日志中间件不同而不同 |
| 请求行 | 排除双引号的字符类 | 内部含空格,不能按空格切分 |
| 状态码 | 三位数字 | 限定三位可提前发现格式漂移 |
| 字节数 | 非空白字符类加空值判断 | 取值为连字符表示未返回长度 |
| 来源与客户端 | 排除双引号的字符类 | 内容中可能含转义形式,注意还原 |
如果日志本身是结构化格式(例如按行输出的 JSON),直接使用 JSON 解析器按字段取值,比正则更稳更快;正则的定位应是「从非结构化文本里抽取」,不是重新实现解析器。
不匹配的行一定要计数并保留样本:日志格式会随中间件升级、代理改写、客户端行为变化,静默跳过会让统计口径悄悄失真,等到发现指标异常时已经很难回溯。