记录一下那天晚上的排查过程。把 Nginx 日志推进 Loki 做查询,label 只设了 app 和 status。想按 UA 筛 Baiduspider 的请求,用 line filter 扫了 30 天数据,查询超时也出不来结果。

刚开始盯着「日志里 UA 字段在最后,被 Caddy 的 JSON 结构包了一层」,折腾了半个多小时,排掉了。

真正麻烦的地方在于,几个原因的现象几乎一样。label 是索引维度,UA 放在日志行里只能全量扫描。另一种情况是正则过滤写成 "Baiduspider" 没转义引号,查询直接语法报错。

少数情况下是保留期只有 7 天,想查上月抓取趋势已经没有数据。

上来先用 label 之外的字段做结构化解析

logcli query '{app="nginx"} | json | user_agent=~"Baiduspider"' --since=24h --limit=50

给管道加 UA 归一化后的 label

pipeline_stages: - json: expressions: {ua: user_agent} - labels: {ua_class: ua}

接着确认保留期与查询窗口匹配

logcli series '{app="nginx"}' --since=720h | head

等前面都确认过,再把常用查询固化成脚本降低扫描量

python loki_bot_stat.py --ua Baiduspider --days 3

改完先别撤,确认这几项。同一时间段按 UA 查询能在十几秒返回,统计结果与本地 access.log 抽样比对一致,常用报表不再依赖全量扫描。

这里还有个坑。高基数标签会把 Loki 的索引撑爆,UA 这类字段应该先归一化成 bot 分类再进 label,原始值留在日志行里。改动前把原配置备份一份,出问题能马上回滚,这比任何技巧都实用。

作者 9823189