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

LogQL 是 Loki 的专用查询语言,语法上受 PromQL 和 SQL 启发,但专为日志数据设计。理解 LogQL 的四个核心构成——日志流选择器、行过滤器、标签过滤器和管道阶段——是编写高效查询、降低查询延迟和资源消耗的基础。

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

日志流选择器是 LogQL 查询的第一段,用于从 Loki 中筛选出特定的日志流。它通过花括号 {} 包裹一组标签键值对来定义,语法与 PromQL 的标签匹配器完全一致。

匹配器类型 符号 示例 说明
精确匹配 = {app="nginx"} 标签值完全等于指定字符串
精确不匹配 != {app!="mysql"} 排除标签值等于指定字符串的流
正则匹配 =~ {app=~"web-.*"} 标签值匹配正则表达式
正则不匹配 !~ {app!~"test-.*"} 排除标签值匹配正则表达式的流
优化要点:日志流选择器是查询的第一步,也是影响性能的关键。尽量使用高基数标签(如 job、namespace)而非低基数标签(如 trace_id)进行筛选,避免 Loki 扫描过多无用的索引。

3.2 行过滤器(Line Filter)

行过滤器紧跟在日志流选择器之后,使用管道符 | 连接,用于对日志行内容进行快速文本匹配。行过滤器不解析日志结构,只做子串或正则匹配,是 LogQL 中最高效的过滤手段。

{job="nginx"} |= "ERROR"          // 包含子串 "ERROR"
{job="nginx"} != "healthcheck"     // 不包含子串 "healthcheck"
{job="nginx"} |~ "5[0-9][0-9]"    // 正则匹配 5xx 状态码
{job="nginx"} !~ "GET /static/"   // 正则排除静态资源请求
性能对比:行过滤器在日志数据被读取到内存之前就进行过滤,能大幅减少后续管道阶段处理的数据量。建议将最严格的过滤条件放在最前面。

3.3 标签过滤器(Label Filter)

标签过滤器用于对日志流中已提取的标签进行数值或字符串比较。它通常出现在管道阶段中,使用 | 连接,语法类似 PromQL 的比较操作。

操作符 示例 说明
== | status == 200 标签值等于
!= | method != "POST" 标签值不等于
> / < | duration > 1.5 数值大于/小于
>= / <= | bytes_sent >= 1024 数值大于等于/小于等于
|~ / !~ | user_agent |~ "Chrome" 标签值正则匹配/不匹配
{job="api-server"} | logfmt | status >= 500 | duration > 2.0
注意:标签过滤器只能作用于已经通过解析器(如 logfmt、json、regexp)提取出来的标签字段。如果字段尚未提取,标签过滤器会报错或返回空结果。

3.4 管道阶段(Pipeline Stage)

管道阶段是 LogQL 中最灵活、最强大的部分,允许对日志行进行解析、提取、转换、过滤和聚合。每个阶段通过 | 串联,形成一条处理流水线。

3.4.1 常用管道阶段一览

阶段类型 语法 作用 示例
解析器 | logfmt 解析 key=value 格式的日志行 | logfmt
解析器 | json 解析 JSON 格式的日志行 | json
解析器 | regexp 使用正则表达式提取字段 | regexp "(?P<ip>\S+)"
解析器 | unpack 解包内嵌的 JSON 或 protobuf | unpack
标签过滤 | label_filter 对提取的标签做比较过滤 | duration > 1.0
行格式化 | line_format 重写日志行内容(模板语法) | line_format "{{.status}}"
标签格式化 | label_format 重命名或修改标签值 | label_format status_code="status"
速率计算 | rate 计算日志行速率(用于指标查询) | rate

3.4.2 管道阶段串联示例

{job="gateway"} 
| json 
| status >= 400 
| line_format "{{.method}} {{.path}} -> {{.status}}" 
| label_format method_upper="{{.method | upper}}"

上述查询的执行流程:

  1. 日志流选择器:只查询 job="gateway" 的日志流。
  2. 行过滤器:无(此处省略,但可前置添加 |= "ERROR" 加速)。
  3. JSON 解析器:将每行 JSON 日志解析为结构化标签。
  4. 标签过滤器:只保留 status >= 400 的日志行。
  5. 行格式化:将日志行内容重写为更简洁的格式。
  6. 标签格式化:将 method 标签转为大写并重命名。
优化建议:管道阶段的顺序直接影响性能。将行过滤器放在最前面,其次是解析器,最后是标签过滤器和格式化。避免在解析前做复杂的正则匹配。

3.5 LogQL 查询结构总览

下图展示了 LogQL 查询的完整结构,从日志流选择到最终输出,每个阶段都可以按需组合。

LogQL 查询结构总览 日志流选择器 {job="nginx"} 行过滤器 |= "ERROR" 解析器 | json / logfmt 标签过滤器 | status >= 500 格式化 | line_format 聚合 / 输出 rate / count_over_time 说明: • 日志流选择器是查询的起点,必须存在。 • 行过滤器应尽量前置,减少后续阶段处理的数据量。 • 解析器、标签过滤器、格式化可按需组合,顺序影响性能。

3.6 查询优化黄金法则

  • 先窄后宽:先用日志流选择器缩小范围,再用行过滤器快速排除无关行,最后用解析器和标签过滤器做精细处理。
  • 避免过度解析:如果只需要简单的子串匹配,不要使用 | json 或 | regexp,行过滤器效率高得多。
  • 标签基数控制:不要在管道阶段中动态创建高基数标签(如 trace_id、user_ip),会导致索引膨胀和查询变慢。
  • 使用 rate 而非 count_over_time:在指标查询中,rate 能自动处理计数器重置,且计算效率更高。
实战案例:优化前:{job=~".+"} | json | level="error"(扫描所有 job,效率极低)
优化后:{job="api-server"} |= "error" | json | level="error"(先限定 job,再用行过滤器,最后解析)