第七章:查询语言

深入学习 LogQL 日志查询语言,包括日志查询和指标查询。

最后更新: 2024-01-21
页面目录

LogQL 查询语言

LogQL 是 Loki 的日志查询语言,类似于 Prometheus 的 PromQL。

LogQL 概述

┌─────────────────────────────────────────────────────────────────┐
│                      LogQL 查询类型                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   LogQL                                                            │
│   ├── Log Queries (日志查询)                                       │
│   │   ├── Log stream selectors                                    │
│   │   ├── Line filters                                            │
│   │   ├── Label filters                                           │
│   │   └── Line format                                             │
│   │                                                              │
│   └── Metric Queries (指标查询)                                    │
│       ├── Range vector aggregation                                │
│       ├── Instant vector aggregation                             │
│       └── Operations                                              │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

日志查询语法

基本结构

{job="nginx"} |= "error" | json | line_format "{{.status}} {{.message}}"
├── Stream selector (日志流选择器)
├── Line filter (行过滤器)
├── Parser (解析器)
└── Line format (格式化)

日志流选择器

基本语法

# 基本标签选择
{job="nginx"}
{job="nginx", namespace="production"}
{job=~"api-.*", env=~"prod|staging"}

# 组合条件
{job="nginx", instance=~"web-.*", env="production"}

标签匹配运算符

运算符 说明 示例
= 精确匹配 job="nginx"
!= 不等于 job!="nginx"
=~ 正则匹配 job=~"api-.*"
!~ 正则不匹配 job!~".*test"

行过滤器

过滤器语法

{job="nginx"} |= "error"
{job="nginx"} != "debug"
{job="nginx"} |~ "timeout.*connection"
{job="nginx"} |~! "info.*debug"

过滤器类型

过滤器 说明
` =`
!= 不包含字符串
` ~`
` ~!`

组合过滤器

# 多个过滤器
{job="nginx"} |= "error" != "timeout" |~ "connection.*failed"

# 顺序很重要
{job="nginx"} |= "error" |= "database"

标签过滤器

JSON 字段过滤

{job="api"} | json | status_code >= 500
{job="api"} | json | level != "debug"
{job="api"} | json | user_id != ""

常用操作符

操作符 说明
== 等于
!= 不等于
> 大于
>= 大于等于
< 小于
<= 小于等于
=~ 正则匹配
!~ 正则不匹配
==~ 大小写敏感正则

示例

# JSON 日志过滤
{job="api"} | json | status >= 500
{job="api"} | json | duration > 1000
{job="api"} | json | method == "POST"
{job="api"} | json | path =~ "/api/.*"

# 复杂条件
{job="api"} | json | status >= 500 and duration > 1000
{job="api"} | json | level in ("error", "fatal")
{job="api"} | json | user_id notin ("", "anonymous")

日志解析

JSON 解析

{job="api"} | json
{job="api"} | json | status_code
{job="api"} | json | level="error"

Logfmt 解析

{job="api"} | logfmt
{job="api"} | logfmt | level="error"
{job="api"} | logfmt | latency > 100

正则解析

{job="api"} | regex "(?P<method>\\w+) (?P<path>\\w+)"
{job="api"} | regex "(?P<ip>\\d+\\.\\d+\\.\\d+\\.\\d+)"

Unpack 解析

{job="api"} | unpack
{job="api"} | unpack | _pkg="github.com/app/api"

日志格式化

line_format

{job="api"} | json | line_format "{{.status}} {{.message}}"
{job="api"} | json | line_format "{{.timestamp}} [{{.level}}] {{.message}}"
{job="api"} | json | line_format "[{{.status}}] {{.ip}} - {{.user}}"

格式化函数

函数 说明 示例
{{.field}} 字段替换 {{.status}}
"text" 文本输出 "Error:"
\n 换行 \n
{{.field | json}} JSON 编码 {{.data | json}}

示例

# 基本格式化
{job="api"} | json | line_format "[{{.status}}] {{.message}}"

# 复杂格式化
{job="api"} | json | line_format "{{.ts}} {{.level | upper}} {{.service}} {{.msg}}"

# 条件格式化
{job="api"} | json | line_format "{{if gt .status 500}}ERROR{{else}}OK{{end}} {{.msg}}"

标签操作

label_format

{job="api"} | label_format dst="{{.src}}"
{job="api"} | json | label_format service="{{.app}}-{{.env}}"
{job="api"} | label_format duration_ms="{{.duration}}ms"

指标查询

概述

┌─────────────────────────────────────────────────────────────────┐
│                      指标查询类型                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   Metric Query                                                    │
│   ├── Range Vector                                                │
│   │   └── rate, increase, count_over_time                        │
│   │                                                              │
│   └── Instant Vector                                              │
│       └── sum, avg, count, topk, bottomk                         │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

基本语法

# 速率计算
rate({job="nginx"}[5m])

# 计数
count_over_time({job="nginx"}[5m])

# 聚合
sum(rate({job="nginx"}[5m]))

向量聚合函数

Range Vector 函数

# 速率计算
rate({job="api"}[5m])           # 每秒平均速率
increase({job="api"}[5m])      # 总增量
irate({job="api"}[5m])         # 即时速率

# 计数
count_over_time({job="api"}[5m])  # 时间窗口内日志数
bytes_rate({job="api"}[5m])        # 字节速率
bytes_over_time({job="api"}[5m])   # 时间窗口内字节数

Instant Vector 函数

# 聚合
sum(rate({job="api"}[5m]))
avg(rate({job="api"}[5m]))
max(rate({job="api"}[5m]))
min(rate({job="api"}[5m]))
count(rate({job="api"}[5m]))

# 排序
topk(5, rate({job="api"}[5m]))
bottomk(5, rate({job="api"}[5m]))

二元运算

# 运算
sum(rate({job="api"}[5m])) / sum(rate({job="total"}[5m])) * 100

# 比较
sum(rate({job="api", status=~"5.."}[5m])) > 10

聚合操作

sum_by

# 按标签聚合
sum by (status) (rate({job="api"}[5m]))
sum by (namespace, pod) (rate({job="nginx"}[5m]))

# 不按标签聚合(全局)
sum without (pod) (rate({job="nginx"}[5m]))

聚合运算符

运算符 说明
sum 求和
min 最小值
max 最大值
avg 平均值
stdvar 标准方差
stddev 标准差
count 计数
bottomk 最小 k 个
topk 最大 k 个

实用查询示例

错误率

# 错误日志速率
sum(rate({job="api"} | json | status >= 500 [5m]))

请求延迟

# P99 延迟
quantile_over_time(0.99, {job="api"} | json | latency [5m])

流量统计

# 每秒请求数
sum(rate({job="api"}[1m]))

# 按服务分组
sum by (service) (rate({job="api"}[1m]))

日志分布

# 按状态码分布
sum by (status) (rate({job="api"}[5m]))

# 按 IP 分布
topk(10, sum by (client_ip) (rate({job="api"} | json [5m])))

告警规则查询

# 错误率告警
sum(rate({job="api"} | json | status >= 500 [5m])) > 0.01

# 错误数量告警
sum(increase({job="api"} | json | status >= 500 [5m])) > 100

# 无日志告警(服务离线)
sum(rate({job="api"}[5m])) == 0

常用查询模板

1. 错误日志查询

{job="myapp"} |= "error" | json | line_format "{{.timestamp}} [{{.level}}] {{.message}}"

2. 性能监控

# 请求延迟 P99
quantile_over_time(0.99, {job="api"} | json | unwrap latency [5m]) by (service)

# 吞吐量
sum by (service) (rate({job="api"}[1m]))

3. 安全审计

# 失败登录
{job="auth"} |= "login failed" | json | line_format "{{.user}} from {{.ip}}"

# 可疑 IP
topk(10, sum by (ip) (rate({job="auth"} |= "failed" [5m])))

4. 应用调试

# 特定请求追踪
{job="api"} |= "trace_id=abc123" | json

# 异常堆栈
{job="api"} |= "panic" | json | line_format "{{.stack}}"

Grafana 中的使用

Explore 面板

# 在 Grafana Explore 中使用
{job="nginx"} |= "error" | json

仪表板变量

# 变量查询
label_values({job="nginx"}, namespace)

# 查询
{job="nginx", namespace="$namespace"}

性能优化

1. 使用具体的选择器

# ✅ 推荐:具体的选择器
{job="api", service="user", namespace="production"}

# ❌ 避免:过于宽泛
{job=~".*"}

2. 早过滤

# ✅ 推荐:尽早过滤
{job="api"} |= "error" | json | status >= 500

# ❌ 避免:晚过滤
{job="api"} | json | status >= 500 |= "error"

3. 使用正则优化

# ✅ 推荐:简单匹配
{job="api"} |~ "error.*timeout"

# ❌ 避免:复杂正则
{job="api"} |~ "(.*)error(.*)"

下一步

接下来让我们学习告警规则配置。

👉 告警规则