详解炬鲸 OBSERVE 类 SQL 日志检索的语法、聚合函数、索引策略与三个常用查询模板,帮团队告别 Lucene 等专用查询语法,把日志排查成本降下来。
日志检索是排查线上问题最高频的操作,但很多团队其实一直没把这件事做好——要么查询慢,要么语法门槛高。这篇文章把炬鲸 OBSERVE 类 SQL 日志检索的设计讲清楚:支持什么、性能怎么保证、有哪些现成套路可以抄。
查日志这件事,一半时间花在「想清楚要查什么」,另一半花在「回忆语法」。Elasticsearch 的 Lucene 语法、Kibana 的查询 DSL、各家云厂商的专用查询语言,写法各不相同:同样是「查最近一小时的错误日志」,有人写 level:ERROR AND @timestamp:[now-1h TO now],有人得拼一段嵌套的 JSON bool 过滤。换个项目就得重新学一遍,新人入职还要专门培训,出了故障更没心思翻文档。
炬鲸 OBSERVE 的做法是把检索收敛到类 SQL:会写 SELECT ... WHERE ... 就能查日志。开发、测试、运维零学习成本,排查时不再被语法卡住。这条设计的出发点很朴素——日志查询应该是团队里人人都会用的工具,而不是少数人手里的手艺。
类 SQL 检索覆盖了 90% 以上的排查场景,核心子句如下:
SELECT level, count(*) AS cnt
FROM logs
WHERE service = 'order-service'
AND level IN ('ERROR', 'WARN')
AND ts > now() - 30m
GROUP BY level
ORDER BY cnt DESC
LIMIT 20
WHERE:等值、范围、IN、LIKE、正则匹配GROUP BY 与聚合函数:count、avg、max、min、percentilenow()、date_trunc、时间加减运算ORDER BY / LIMIT:排序与分页字段名与采集端约定的结构化字段对齐,level、service、trace_id、ts 直接可查,不用写 Grok 规则解析。percentile 尤其好用:percentile(duration, 99) 一条语句出 P99 延迟,不用先导出数据再进电子表格算。写不来 SQL 也没关系,输入「查一下 order-service 最近半小时的报错」就能生成对应查询,而且会展示生成的 SQL,边用边学。
日志量大时,索引策略直接决定查询速度和存储成本,二者相互拉扯:索引建太多,存储成本飙高;建太少,每条查询都退化成全表扫描。默认对 service、level、trace_id、host 这类高频过滤字段建索引,正文走全文检索,冷热数据分层存储——最近几天秒级返回,历史数据低成本归档。哪些字段该建索引,看实际查询习惯:WHERE 里反复出现的字段优先建,偶尔才用的字段留给全文检索兜底。
查询时的经验法则是:先用索引字段缩小范围,再用全文检索兜底。查 service = 'order-service' 走索引很快;全正文扫子串只在范围已经足够小的时候才做。一个具体建议:把 trace_id 建成高基数索引字段,链路排查时按 trace_id 过滤,能比全文扫描快一个数量级,因为索引直接把你带到属于同一次请求的那几行日志。
找错误高峰:
SELECT date_trunc('5m', ts) AS bucket, count(*) AS cnt
FROM logs WHERE level = 'ERROR' AND ts > now() - 1h
GROUP BY bucket ORDER BY bucket
慢请求 Top N:
SELECT path, avg(duration) AS avg_ms, count(*) AS cnt
FROM logs WHERE service = 'api-gateway' AND ts > now() - 1h
GROUP BY path ORDER BY avg_ms DESC LIMIT 10
按 trace_id 串日志:
SELECT * FROM logs WHERE trace_id = 'a1b2c3d4e5f6' ORDER BY ts
把高频查询存成模板,出故障时点一下就能出结果,比每次现写快得多。模板可以共享给整个团队,也可以挂在告警上——告警触发时附带一条关联查询,值班的人点开就是现场。模板库慢慢就成了团队自己的排查手册,那些反复出现的排查套路,早就写好了放在那儿。