← 返回文章列表
产品动态 4 分钟阅读 炬鲸团队

类 SQL 日志检索:从语法到性能,把日志排查成本降下来

详解炬鲸 OBSERVE 类 SQL 日志检索的语法、聚合函数、索引策略与三个常用查询模板,帮团队告别 Lucene 等专用查询语法,把日志排查成本降下来。

日志检索是排查线上问题最高频的操作,但很多团队其实一直没把这件事做好——要么查询慢,要么语法门槛高。这篇文章把炬鲸 OBSERVE 类 SQL 日志检索的设计讲清楚:支持什么、性能怎么保证、有哪些现成套路可以抄。

为什么放弃 Lucene 语法

查日志这件事,一半时间花在「想清楚要查什么」,另一半花在「回忆语法」。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:等值、范围、INLIKE、正则匹配
  • GROUP BY 与聚合函数:countavgmaxminpercentile
  • 时间函数:now()date_trunc、时间加减运算
  • ORDER BY / LIMIT:排序与分页

字段名与采集端约定的结构化字段对齐,levelservicetrace_idts 直接可查,不用写 Grok 规则解析。percentile 尤其好用:percentile(duration, 99) 一条语句出 P99 延迟,不用先导出数据再进电子表格算。写不来 SQL 也没关系,输入「查一下 order-service 最近半小时的报错」就能生成对应查询,而且会展示生成的 SQL,边用边学。

索引与性能取舍

日志量大时,索引策略直接决定查询速度和存储成本,二者相互拉扯:索引建太多,存储成本飙高;建太少,每条查询都退化成全表扫描。默认对 serviceleveltrace_idhost 这类高频过滤字段建索引,正文走全文检索,冷热数据分层存储——最近几天秒级返回,历史数据低成本归档。哪些字段该建索引,看实际查询习惯: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

把高频查询存成模板,出故障时点一下就能出结果,比每次现写快得多。模板可以共享给整个团队,也可以挂在告警上——告警触发时附带一条关联查询,值班的人点开就是现场。模板库慢慢就成了团队自己的排查手册,那些反复出现的排查套路,早就写好了放在那儿。