3. LogQL 基础语法:日志流选择器、行过滤器与 PromQL 对比

LogQL 是 Loki 的查询语言,语法上受 PromQL 启发,但面向日志数据而非时序指标。理解 LogQL 的核心在于掌握两个基本构件:日志流选择器(Log Stream Selector)和行过滤器(Line Filter)。本章将拆解这两个概念,并与 PromQL 进行对比,帮助你快速建立 LogQL 的思维模型。

3.1 日志流选择器:{job=~"..."}

日志流选择器用于从 Loki 中筛选出特定的日志流。它的语法与 PromQL 的标签匹配器完全一致,使用花括号 {} 包裹标签键值对。所有 LogQL 查询都必须以日志流选择器开头。

匹配器类型 符号 示例 说明
精确匹配 = {job="api-server"} 标签值完全等于 api-server
精确否定 != {job!="debug"} 排除标签值为 debug 的流
正则匹配 =~ {job=~"api-.*"} 匹配正则表达式 api-.*
正则否定 !~ {job!~"staging|dev"} 排除匹配正则的流
实战建议:在生产环境中,建议至少使用 {job=~"..."} 或 {namespace=~"..."} 作为选择器,避免全量扫描所有日志流。选择器越精确,查询性能越高。

多个标签条件可以组合使用,用逗号分隔,相当于逻辑 AND:

{job=~"api-.*", namespace="production", env!~"staging|dev"}

3.2 行过滤器:|=、!=、|~

行过滤器在日志流选择器筛选出的日志行基础上,进一步对日志内容进行过滤。它使用管道符 | 连接,作用于日志行的文本内容。

过滤器类型 符号 示例 说明
包含 |= {job="api"} |= "ERROR" 日志行包含子串 ERROR
不包含 != {job="api"} != "DEBUG" 日志行不包含子串 DEBUG
正则匹配 |~ {job="api"} |~ "5[0-9]{2}" 日志行匹配正则(如 HTTP 5xx)
正则不匹配 !~ {job="api"} !~ "health|metrics" 日志行不匹配正则
性能注意:|= 和 != 是子串匹配,性能优于正则。只有在需要复杂模式匹配时才使用 |~ 和 !~。正则表达式应尽量简洁,避免回溯爆炸。

行过滤器可以串联使用,形成过滤链:

{job="api-server"} |= "ERROR" |~ "5[0-9]{2}" != "timeout"

上述查询的含义:选择 job="api-server" 的日志流 → 包含 ERROR → 匹配 HTTP 5xx 状态码 → 排除包含 timeout 的行。

LogQL 查询管道结构 日志流选择器 {job=~"api-.*"} 行过滤器 1 |= "ERROR" 行过滤器 2 |~ "5[0-9]{2}" 结果 关键理解: • 选择器决定从哪些日志流中读取数据(标签层面) • 行过滤器在日志内容层面逐级缩小结果集 • 管道顺序影响性能:高过滤性的条件应尽量靠前

3.3 LogQL 与 PromQL 语法对比

LogQL 的设计借鉴了 PromQL,但两者面向的数据类型不同。下表从核心概念到语法细节进行对比:

对比维度 PromQL(指标) LogQL(日志)
数据对象 时间序列(指标值 + 标签) 日志流(日志行 + 标签)
选择器语法 {job="api"} {job="api"}(完全相同)
过滤方式 标签匹配 + 值范围(如 > 0.5) 标签匹配 + 行内容过滤(|=、|~)
聚合函数 rate()、sum()、avg() 等 rate()、sum()、avg()(语法一致)
管道操作 无管道概念 管道 | 串联过滤、解析、格式化
日志解析 不支持 | json、| logfmt、| regexp
返回类型 数值向量或标量 日志行(LogQL 查询)或指标向量(LogQL 指标查询)
核心差异总结:PromQL 操作的是数值,LogQL 操作的是文本。LogQL 的管道机制是其独有的强大特性,允许在查询过程中对日志行进行解析、提取和转换,这是 PromQL 无法做到的。

3.4 从 PromQL 到 LogQL 的思维转换

如果你已经熟悉 PromQL,以下对照表可以帮助你快速迁移:

PromQL 场景 对应的 LogQL 写法 说明
{job="api"} {job="api"} 选择器语法完全一致
rate({job="api"}[5m]) rate({job="api"} |= "ERROR" [5m]) LogQL 的 rate() 计算日志行出现速率
sum by(host) (rate(...)) sum by(host) (rate({job="api"} |= "ERROR" [5m])) 聚合语法完全一致
无对应 {job="api"} |= "ERROR" | json LogQL 独有:解析 JSON 日志行
无对应 {job="api"} | logfmt | duration > 1s LogQL 独有:解析 logfmt 并过滤字段
PromQL vs LogQL 数据流对比 PromQL 数据流 时序指标(数值 + 标签) cpu_usage{host="web-1"} 标签选择器 + 值过滤 {host=~"web-.*"} > 0.9 聚合 → 数值结果 avg(rate(...[5m])) LogQL 数据流 日志行(文本 + 标签) "2025-01-01 ERROR ..." {job="api"} 选择器 + 行过滤器 {job="api"} |= "ERROR" |~ "5xx" 管道解析 → 日志行 / 指标 | json | rate()

3.5 实战案例:从日志中提取 Golden Signals 指标

以下是一个完整的 LogQL 查询示例,展示如何从 API 日志中提取错误率指标:

# 步骤 1:选择日志流 + 过滤错误行
{job="api-server", namespace="production"}
  |= "ERROR"
  |~ "5[0-9]{2}"

# 步骤 2:解析 JSON 日志体,提取 status_code 和 duration
  | json
  | status_code >= 500

# 步骤 3:计算 5 分钟内的错误速率
  | rate($__interval)

# 完整查询(Grafana 中使用):
rate(
  {job="api-server", namespace="production"}
    |= "ERROR"
    |~ "5[0-9]{2}"
    | json
    | status_code >= 500
  [5m]
)
Golden Signals 映射:上述查询直接对应 错误率(Error Rate)信号。类似地,你可以用 | json | duration > 1s 提取 延迟(Latency),用 rate({job="api-server"}[5m]) 提取 流量(Traffic)。

3.6 常见错误与避坑指南

  • 选择器遗漏:LogQL 查询必须以 {...} 开头,不能直接写 |= "ERROR"。
  • 正则性能陷阱:|~ ".*ERROR.*" 等价于 |= "ERROR",但正则版本性能差 10 倍以上。能用子串匹配就不要用正则。
  • 管道顺序:高过滤性的条件(如 |= "ERROR")应放在管道前面,尽早减少数据量。
  • 标签基数爆炸:不要将高基数标签(如 user_id、request_id)作为 Loki 标签,应放在日志行内通过 | json 解析。
  • PromQL 思维惯性:不要试图在 LogQL 中做数值运算(如 a + b),LogQL 的数值运算能力有限,复杂计算应使用 PromQL 或 Grafana 的 Transform。
生产环境检查清单:
  1. 每个查询是否都有明确的日志流选择器?
  2. 行过滤器是否优先使用 |= 而非 |~?
  3. 是否避免了在标签中使用高基数属性?
  4. 管道顺序是否按过滤强度从高到低排列?