3、LogQL入门:日志查询语法、标签匹配、管道操作、度量查询

LogQL 是 Loki 的专属查询语言,受 PromQL 和 SQL 启发,专为日志数据设计。理解 LogQL 是构建 SLI 口径和进行故障排查的基础。本章将系统讲解 LogQL 的核心概念:日志流选择器、行过滤器、管道操作以及度量查询。

3.1 核心概念:日志流与标签

在 LogQL 中,查询的第一步是选择日志流。日志流由一组标签(Labels)唯一标识,这些标签通常来自日志采集器(如 Promtail)或 Loki 的配置。标签是键值对,例如 job="api-server"、env="production"、service="payment"。

关键理解: 标签是 Loki 的索引。查询时,Loki 首先通过标签匹配缩小搜索范围,然后才扫描日志内容。合理设计标签是提升查询性能的关键。

3.2 日志流选择器

日志流选择器用于指定要查询的日志流集合。它使用花括号 {} 包裹标签匹配表达式。

匹配操作符 含义 示例
= 精确匹配 {job="api-server"}
!= 不等于 {job!="cron-job"}
=~ 正则匹配 {job=~"api-.*"}
!~ 正则排除 {job!~"debug-.*"}

组合示例:

{env="production", service=~"auth|payment", job!="batch"}

该查询选择所有 env="production" 且 service 以 "auth" 或 "payment" 开头,且 job 不是 "batch" 的日志流。

3.3 行过滤器

在选定日志流后,可以使用行过滤器对日志行内容进行文本搜索。行过滤器使用管道符 | 连接。

过滤器 语法 说明
包含 |= "error" 日志行包含 "error"
不包含 != "debug" 日志行不包含 "debug"
正则包含 |~ "5[0-9]{2}" 日志行匹配正则(如 5xx 状态码)
正则排除 !~ "health" 日志行不匹配正则

完整查询示例:

{env="production", service="api"} |= "error" |~ "5[0-9]{2}"

该查询从生产环境的 api 服务中,筛选出包含 "error" 且匹配 5xx 状态码的日志行。

3.4 管道操作:解析与提取

管道操作允许对日志行进行解析、提取字段、格式化输出等。这是构建结构化日志查询的核心能力。

3.4.1 常用管道操作符

操作符 作用 示例
logfmt 解析 logfmt 格式日志 | logfmt
json 解析 JSON 格式日志 | json
regexp 使用正则提取字段 | regexp "(?P<status>\d{3})"
pattern 使用模式匹配提取 | pattern "<ip> - - <method>"
unpack 解包已打包的日志 | unpack
line_format 格式化输出行内容 | line_format "{{.status}}"
label_format 格式化标签值 | label_format new_status="{{.status}}"

JSON 解析示例:

{job="api-server"} |= "error" | json | line_format "{{.message}} - {{.status}}"

该查询解析 JSON 日志,提取 message 和 status 字段,并重新格式化输出。

3.4.2 管道操作流程

最佳实践: 管道操作按顺序执行。先过滤日志行,再解析字段,最后格式化输出。这能有效减少后续处理的数据量。
LogQL 管道操作流程 日志流选择器 行过滤器 管道解析 格式化输出 说明:管道操作按顺序执行,先过滤再解析,最后格式化。 每个步骤都可以使用 | 连接,形成完整的查询链。

3.5 度量查询:从日志到指标

LogQL 最强大的特性之一是将日志转换为度量指标。度量查询使用函数包装日志查询,返回时间序列数据,可直接用于 Grafana 面板或告警。

3.5.1 核心度量函数

函数 作用 返回类型
rate 计算日志行速率(每秒) Gauge
count_over_time 计算时间窗口内的日志行数 Gauge
sum_over_time 计算时间窗口内数值字段的总和 Gauge
avg_over_time 计算时间窗口内数值字段的平均值 Gauge
max_over_time 计算时间窗口内数值字段的最大值 Gauge
min_over_time 计算时间窗口内数值字段的最小值 Gauge
stdvar_over_time 计算时间窗口内数值字段的方差 Gauge
stddev_over_time 计算时间窗口内数值字段的标准差 Gauge
quantile_over_time 计算时间窗口内数值字段的分位数 Gauge
first_over_time 返回时间窗口内第一个值 Gauge
last_over_time 返回时间窗口内最后一个值 Gauge

3.5.2 常用度量查询模式

1. 错误率计算(SLI 核心)

sum(rate({job="api-server"} |= "error" [5m])) / sum(rate({job="api-server"} [5m]))

该查询计算 5 分钟内 API 服务器的错误日志占比,是构建错误率 SLI 的基础。

2. 请求延迟分析

quantile_over_time({job="api-server"} | json | unwrap duration [5m])

该查询计算 5 分钟内请求延迟的 P99 分位数,需要日志中包含 duration 字段。

3. 特定状态码计数

count_over_time({job="api-server"} |~ "5[0-9]{2}" [5m])

该查询统计 5 分钟内 5xx 状态码的出现次数。

3.6 度量查询中的 unwrap 与 by

unwrap 用于从日志行中提取数值字段,供度量函数使用。by 用于按标签分组聚合。

示例:按服务分组计算平均延迟

avg_over_time({env="production"} | json | unwrap duration [5m]) by (service)

该查询按 service 标签分组,计算每个服务在 5 分钟内的平均请求延迟。

3.7 完整查询示例:构建 SLI 口径

以下是一个完整的 LogQL 查询,用于计算 CI/CD 流水线中部署阶段的错误率 SLI:

sum(rate({env="production", job="deploy"} |= "error" [5m])) 
/ 
sum(rate({env="production", job="deploy"} [5m])) 
* 100
注意: 当分母为 0 时,查询会返回 NaN。建议在 Grafana 面板中使用 null as zero 或 transform 处理空值情况。

3.8 查询性能优化建议

  • 优先使用标签匹配:在 {} 中尽可能精确地选择日志流,减少扫描范围。
  • 行过滤器前置:将 |=、!= 等行过滤器放在管道最前面,尽早过滤无关日志。
  • 避免过度使用正则:正则匹配性能低于精确匹配,尽量使用 = 或 |=。
  • 合理设置时间范围:度量查询中的时间窗口(如 [5m])应与查询范围匹配,避免过大窗口导致性能下降。
  • 使用 by 控制基数:分组标签的基数(唯一值数量)不宜过高,否则会导致内存压力。
LogQL 查询性能优化策略 LogQL 查询 精确标签匹配 行过滤器前置 避免过度正则 控制分组基数 提示:优化策略按优先级排序,精确标签匹配是性能提升最显著的手段。

3.9 本章小结