2. Loki基础回顾:LogQL核心语法、标签匹配、时间范围与聚合操作

LogQL 是 Loki 的查询语言,本质上是将 PromQL 的标签选择与日志行过滤、解析、聚合能力相结合。在变更窗口场景中,LogQL 用于从海量日志中快速定位特定变更事件、统计错误率、计算持续时间。本节从核心语法出发,逐步覆盖标签匹配、时间范围与聚合操作,为后续告警路由模板打下语法基础。

2.1 LogQL 核心语法结构

LogQL 查询由两个主要阶段组成:日志流选择器(Log Stream Selector)和管道表达式(Pipeline Expression)。流选择器通过标签匹配确定要查询的日志源;管道表达式对选中的日志行进行过滤、解析、计算。

阶段 作用 示例
日志流选择器 基于标签键值对筛选日志流 {app="nginx", env="prod"}
行过滤器 对日志内容进行包含/排除匹配 |= "ERROR"、!= "timeout"
解析器 从日志行中提取结构化字段 | json、| logfmt、| regexp
标签/行格式化 修改或新增标签、行内容 | label_format、| line_format
聚合函数 对提取的指标进行数学聚合 sum by(host) (rate(...))
变更窗口关键点: 流选择器中的标签应包含 service、version、deploy_id 等变更标识,便于在告警路由中按变更维度聚合。

2.2 标签匹配:精确、正则与多条件组合

标签匹配是 LogQL 查询的入口。Loki 支持四种匹配操作符,用于在流选择器中筛选日志流:

  • 精确匹配(=): 标签值必须完全等于给定字符串。{app="api-gateway"}
  • 精确不匹配(!=): 排除标签值等于给定字符串的日志流。{app!="debug"}
  • 正则匹配(=~): 标签值匹配给定的 RE2 正则表达式。{app=~"api-.*"}
  • 正则不匹配(!~): 排除标签值匹配给定正则的日志流。{app!~"test-.*"}

多个标签条件使用逗号分隔,逻辑关系为 AND。例如:

{app="order-service", env="staging", deploy_id=~"v2\\..*"}

该查询只选择 app=order-service、env=staging 且 deploy_id 以 v2. 开头的日志流。

性能提示: 标签匹配是 Loki 索引查询的核心。优先使用精确匹配(=),避免高基数标签(如 user_id、request_id)作为流选择器条件。正则匹配会降低查询性能,在告警查询中应谨慎使用。

2.3 时间范围:时间与相对时间

LogQL 查询必须指定时间范围。Loki 支持两种方式:

方式 语法 示例 适用场景
相对时间 HTTP API 参数 start/end 或 Grafana 时间选择器 最近 15 分钟、昨天 10:00-11:00 实时告警、临时排查
时间 HTTP API 参数 start/end 使用 Unix 时间戳(纳秒) start=1718000000000000000 历史回放、变更审计

在变更窗口场景中,时间范围通常与变更开始/结束时间对齐。例如,查询变更窗口内(2024-06-10 14:00:00 至 14:30:00)的错误日志:

{app="checkout", env="prod"}
  |= "ERROR"
  | json

配合 Grafana 或 API 设置 start=1718013600000000000、end=1718015400000000000。

2.4 聚合操作:从日志到指标

聚合操作将日志行转换为时间序列指标,是告警规则的核心。LogQL 提供两类聚合:基于日志计数的聚合和基于提取字段的聚合。

2.4.1 常用聚合函数

函数 作用 示例
rate 计算日志行每秒出现速率 rate({app="nginx"} |= "5\\d{2}" [5m])
count_over_time 计算指定时间窗口内的日志行总数 count_over_time({app="api"} |= "timeout" [1h])
sum by 按标签分组求和 sum by(host) (rate({app="web"} |= "4\\d{2}" [5m]))
avg by 按标签分组求平均值 avg by(service) (rate({job="worker"} |= "retry" [10m]))
max by 按标签分组求最大值 max by(region) (count_over_time({app="db"} |= "slow" [5m]))
quantile_over_time 计算提取字段的分位数 quantile_over_time(0.99, {app="api"} | json | unwrap duration [5m])

2.4.2 聚合流程示例

以下查询统计变更窗口内每个服务的 5xx 错误速率,并按 service 和 version 分组:

sum by(service, version) (
  rate(
    {app="microservice", env="prod"}
      |= "5\\d{2}"
      | json
      [5m]
  )
)

该查询的管道执行顺序:

  1. 流选择器匹配 app=microservice 且 env=prod 的日志流。
  2. 行过滤器保留包含 5xx 状态码的日志行。
  3. | json 解析器将 JSON 格式的日志行转为结构化字段。
  4. rate(... [5m]) 计算每 5 分钟窗口内的每秒速率。
  5. sum by(service, version) 按服务名和版本号分组求和。
变更窗口最佳实践: 在聚合查询中始终包含 version 或 deploy_id 标签作为分组维度,便于在告警路由中将异常流量精确关联到特定变更版本。

2.5 LogQL 查询执行流程

下图展示了 LogQL 查询从标签匹配到聚合输出的完整执行链路:

LogQL 查询执行流程 日志流选择器 {app="nginx"} 行过滤器 |= "ERROR" 解析器 | json 时间窗口 [5m] 聚合函数 rate / sum by 时间序列输出 Grafana / 告警 说明 每个阶段可选 可组合多个 解析器与格式化 聚合必须配合 时间窗口

2.6 变更窗口场景中的 LogQL 模式

在变更窗口告警中,以下三种 LogQL 模式最为常用:

模式 查询示例 告警用途
错误速率突增 sum by(service) (rate({app="myapp"} |= "5\\d{2}" [5m])) > 0.1 检测变更后 5xx 错误率超过阈值
日志量异常 sum by(host) (count_over_time({app="myapp"} [5m])) > 10000 检测日志暴增,可能为死循环或异常流量
延迟分位数 quantile_over_time(0.99, {app="myapp"} | json | unwrap response_time [5m]) > 2000 检测 p99 响应时间超过 2 秒