3. LogQL 基础语法:日志流选择器、行过滤器、标签过滤器、管道阶段

LogQL 是 Grafana Loki 的查询语言,语法上受 PromQL 和 SQL 启发,但专门针对日志数据设计。理解 LogQL 的核心语法是构建蓝绿发布门禁日志查询接口的基础。本章将系统讲解 LogQL 的四大核心组件:日志流选择器、行过滤器、标签过滤器以及管道阶段(Parser, Line Format, Unwrap, Label Filter)。

核心概念:LogQL 查询由两部分组成——日志流选择器(决定从哪些日志流中查询)和可选的管道表达式(对匹配的日志行进行过滤、解析、格式化或计算)。管道表达式可以串联多个阶段,形成强大的日志处理流水线。

3.1 日志流选择器(Log Stream Selector)

日志流选择器是 LogQL 查询的起点,用于从 Loki 中筛选出特定的日志流。它使用花括号 {} 包裹,内部包含一组键值对标签(Label)匹配条件,语法与 PromQL 的标签选择器完全一致。

操作符 含义 示例
= 精确匹配 {app="gateway"}
!= 不等于 {app!="sidecar"}
=~ 正则匹配 {app=~"gateway|api"}
!~ 正则排除 {app!~"debug.*"}

在蓝绿发布场景中,通常使用 deploy_env 或 version 标签来区分蓝绿环境:

{app="order-service", deploy_env="blue"}
{app="order-service", deploy_env="green", version="v2.1.0"}
性能建议:日志流选择器应尽量精确。Loki 会先根据标签匹配缩小搜索范围,再执行后续的过滤和解析。避免使用过于宽泛的选择器(如 {app=~".*"}),否则会导致全量扫描,严重影响查询性能。
日志流选择器匹配流程 原始日志流 日志流选择器 {app="order", env="blue"} 匹配的日志流 标签匹配规则 • app="order" → 精确匹配 • env="blue" → 精确匹配 • 多个标签为 AND 关系 • 不匹配的流被丢弃

3.2 行过滤器(Line Filter)

行过滤器用于在日志流选择器的基础上,对日志行内容进行文本级别的快速过滤。它使用管道符 | 连接,支持四种操作符:

操作符 含义 示例
|= 包含字符串 {app="gateway"} |= "ERROR"
!= 不包含字符串 {app="gateway"} != "health"
|~ 正则匹配 {app="gateway"} |~ "5[0-9]{2}"
!~ 正则排除 {app="gateway"} !~ "debug|trace"
性能关键:行过滤器是 LogQL 中最快的过滤方式,因为它直接在日志行的原始文本上执行子串或正则匹配,无需解析结构化字段。在蓝绿发布门禁场景中,应优先使用行过滤器快速排除无关日志,再使用后续的管道阶段进行精细化处理。
// 查询蓝色环境订单服务的所有 5xx 错误日志
{app="order-service", deploy_env="blue"} |= "ERROR" |~ "5[0-9]{2}"

// 排除健康检查日志后的所有日志
{app="api-gateway"} != "/healthz"

3.3 标签过滤器(Label Filter)

标签过滤器作用于日志流中已有的标签(包括原始标签和通过管道阶段提取的标签),支持数值和字符串的比较操作。它使用 | 连接,语法为 标签名 操作符 值。

操作符 支持类型 示例
== 字符串、数值 | status_code == 200
!= 字符串、数值 | method != "POST"
>, >= 数值 | duration >= 1.5
<, <= 数值 | response_size < 1024
=~ 字符串(正则) | user_agent =~ "Mozilla.*"
!~ 字符串(正则) | path !~ "/static/.*"
蓝绿发布门禁场景:标签过滤器常用于门禁判断。例如,筛选出绿色环境响应时间超过 2 秒的慢请求,或统计蓝色环境 5xx 错误率是否超过阈值。
// 查询绿色环境响应时间超过 2 秒的请求
{app="order-service", deploy_env="green"} | json | duration > 2.0

// 查询蓝色环境非 200 状态码的请求
{app="order-service", deploy_env="blue"} | json | status_code != 200

3.4 管道阶段(Pipeline Stages)

管道阶段是 LogQL 最强大的特性,允许对匹配的日志行进行解析、格式化、提取和计算。每个阶段通过 | 串联,形成处理流水线。本节重点介绍四种核心管道阶段:Parser、Line Format、Unwrap 和 Label Filter。

LogQL 管道阶段处理流水线 原始日志行 Parser json / logfmt / regexp Line Format 模板化输出 Unwrap 提取数值 Label Filter 管道阶段执行顺序与作用 ① Parser:将非结构化日志解析为结构化标签(如 JSON 字段 → 标签) ② Line Format:使用模板重新格式化日志行内容(常用于日志脱敏或简化) ③ Unwrap:从标签中提取数值字段,用于后续的数学运算或聚合 ④ Label Filter:基于标签值进行过滤(支持数值比较和正则匹配) ⑤ 各阶段可任意组合,顺序影响最终结果

3.4.1 Parser 阶段

Parser 阶段将非结构化的日志行解析为结构化的标签(Label),使得后续阶段可以按字段名引用。Loki 内置了多种解析器:

解析器 适用格式 示例日志 提取的标签
| json JSON 格式 {"level":"error","status":500} level="error", status=500
| logfmt key=value 格式 level=error status=500 level="error", status=500
| regexp 自定义正则 2024-01-01 ERROR [gateway] 按命名分组提取
| unpack packed 格式 Loki 内部打包格式 解包后的原始标签
// JSON 解析示例
{app="order-service"} |= "ERROR" | json
// 原始日志: {"level":"error","status":500,"path":"/api/order","duration":1.23}
// 提取标签: level="error", status=500, path="/api/order", duration=1.23

// 正则解析示例
{app="gateway"} | regexp "(?P<method>\\w+) (?P<path>[\\w/]+) (?P<status>\\d+)"
// 原始日志: POST /api/order 200
// 提取标签: method="POST", path="/api/order", status="200"
正则解析技巧:使用 (?P<name>pattern) 语法定义命名分组,分组名即为标签名。正则解析灵活但性能较低,建议优先使用 | json 或 | logfmt。

3.4.2 Line Format 阶段

Line Format 阶段用于重新格式化日志行的输出内容,常用于日志脱敏、简化显示或添加上下文信息。它使用 Go 模板语法,通过 __line__ 引用原始行,通过标签名引用解析后的字段。

// 只保留关键字段,脱敏敏感信息
{app="order-service"} | json | line_format "{{.level}} | {{.path}} | status={{.status}}"

// 原始日志: {"level":"error","status":500,"path":"/api/order","user":"john"}
// 输出: error | /api/order | status=500

// 添加固定前缀
{app="gateway"} | line_format "[BLUE-DEPLOY] {{.__line__}}"

3.4.3 Unwrap 阶段

Unwrap 阶段从标签中提取数值字段,使其可用于后续的数学运算、聚合函数(如 rate、avg、sum)或标签过滤中的数值比较。Unwrap 是连接日志查询与指标计算的桥梁。

语法 说明 示例
| unwrap <字段名> 提取数值字段 | unwrap duration
| unwrap <字段名> [<转换函数>] 提取并转换 | unwrap duration_seconds
// 计算绿色环境最近 5 分钟的平均响应时间
avg_over_time(
  {app="order-service", deploy_env="green"} | json | unwrap duration [5m]
)

// 统计蓝色环境 5xx 错误率
rate(
  {app="order-service", deploy_env="blue"} | json | status_code >= 500 [1m]
)
Unwrap 注意事项:Unwrap 只能提取数值类型的标签(整数或浮点数)。如果字段值为字符串或缺失,该日志行会被跳过。建议在 Unwrap 前使用 | json 或 | logfmt 确保字段类型正确。

3.4.4 Label Filter 阶段(管道内)

在管道阶段中,Label Filter 可以基于解析后的标签值进行过滤,支持数值比较和字符串正则匹配。与日志流选择器中的标签过滤不同,管道内的 Label Filter 可以引用通过 Parser 阶段动态提取的标签。

// 管道内标签过滤完整示例
{app="order-service", deploy_env="green"}
  | json
  | status_code != 200                          // 过滤非 200 状态码
  | duration > 2.0                              // 过滤慢请求
  | line_format "{{.status_code}} | {{.duration}}s | {{.__line__}}"

3.5 综合示例:蓝绿发布门禁日志查询

将上述语法组合,构建一个完整的蓝绿发布门禁日志查询:

// 查询绿色环境最近 10 分钟的 5xx 错误率
sum(
  rate(
    {app="order-service", deploy_env="green"}
      | json
      | status_code >= 500
      | unwrap status_code
      [10m]
  )
) / sum(
  rate(
    {app="order-service", deploy_env="green"}
      | json
      | unwrap status_code
      [10m]
  )
) * 100 > 1.0

// 如果结果 > 1.0,表示错误率超过 1%,门禁应阻止流量切换
门禁逻辑:上述查询计算绿色环境最近 10 分钟的 5xx 错误率。如果结果大于 1.0%,则门禁系统判定绿色环境不稳定,阻止蓝绿流量切换。通过调整时间窗口和阈值,可以灵活适配不同服务的稳定性要求。

3.6 本章小结

组件 作用 性能影响 蓝绿发布场景用途
日志流选择器 按标签筛选日志流 低(索引查询) 区分蓝绿环境、服务、版本
行过滤器 按文本内容快速过滤 低(子串匹配) 快速定位 ERROR、5xx 等关键词
标签过滤器 按标签值精确过滤 中(需解析后过滤) 筛选特定状态码、响应时间范围
Parser 阶段 解析非结构化日志 中(解析开销) 提取 JSON/logfmt 字段用于门禁判断
Line Format 阶段 格式化日志输出 低 日志脱敏、简化显示
Unwrap 阶段 提取数值用于计算 低 计算错误率、平均响应时间等指标