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}}"
上述查询的执行流程:
- 日志流选择器:只查询
job="gateway"的日志流。 - 行过滤器:无(此处省略,但可前置添加
|= "ERROR"加速)。 - JSON 解析器:将每行 JSON 日志解析为结构化标签。
- 标签过滤器:只保留
status >= 400的日志行。 - 行格式化:将日志行内容重写为更简洁的格式。
- 标签格式化:将
method标签转为大写并重命名。
优化建议:管道阶段的顺序直接影响性能。将行过滤器放在最前面,其次是解析器,最后是标签过滤器和格式化。避免在解析前做复杂的正则匹配。
3.5 LogQL 查询结构总览
下图展示了 LogQL 查询的完整结构,从日志流选择到最终输出,每个阶段都可以按需组合。
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,再用行过滤器,最后解析)