4. LogQL v2 新特性:unwrap、label_format与向量聚合增强
LogQL v2 是 Loki 查询语言的一次重要演进,它不再局限于简单的日志行过滤与标签匹配,而是引入了对日志内容中结构化字段的深度处理能力。本章聚焦于三个核心新特性:unwrap 表达式、label_format 管道函数以及向量聚合的增强。掌握这些特性,是应对日志平台版本漂移、确保查询接口兼容性的关键一步。
4.1 unwrap 表达式:从日志行中提取指标
在 LogQL v1 中,指标查询只能基于日志流的标签(如 {job="api-server"})进行计数或速率计算。v2 引入的 unwrap 表达式允许你从日志行的 JSON、logfmt 或正则表达式捕获组中提取数值字段,并将其作为指标值参与聚合运算。
4.1.1 unwrap 语法与示例
unwrap 通常与 rate、avg_over_time、sum 等聚合函数配合使用。基本语法如下:
# 提取 JSON 字段 "duration" 作为指标值
rate({job="api-server"} | json | unwrap duration [5m])
# 提取 logfmt 字段 "status_code"
avg_over_time({app="nginx"} | logfmt | unwrap status_code [1h])
# 使用正则表达式捕获组提取数值
sum by (host) (
rate({job="web"} | regexp "response_time=(?P<resp_time>\\d+)" | unwrap resp_time [5m])
)
4.1.2 unwrap 与标签过滤的对比
| 特性 | 标签过滤(v1) | unwrap 表达式(v2) |
|---|---|---|
| 数据来源 | 日志流标签(如 job、namespace) |
日志行内容中的数值字段 |
| 指标类型 | 仅支持计数、速率(如 rate、count_over_time) |
支持求和、平均值、分位数、直方图等 |
| 字段提取 | 无需提取,标签已存在 | 需通过 json、logfmt、regexp 解析 |
| 典型场景 | 请求量、错误率(基于标签分组) | 请求延迟 P99、CPU 使用率、业务金额 |
unwrap 表达式的行为可能因日志解析器(如 json、logfmt)的兼容性调整而产生差异。建议在升级后使用 loki-canary 或自定义查询验证 unwrap 结果是否一致。
4.2 label_format 管道:动态重塑标签
label_format 是 LogQL v2 中新增的管道函数,允许你在查询过程中对标签名和标签值进行格式化、重命名或删除。这对于统一来自不同微服务、不同版本的日志标签命名规范至关重要。
4.2.1 标签重命名与值格式化
label_format 支持两种操作:重命名标签和格式化标签值。语法如下:
# 重命名标签:将 "old_name" 改为 "new_name"
{job="api"} | label_format new_name=old_name
# 格式化标签值:将 "level" 标签的值转换为小写
{app="web"} | label_format level=lowercase(level)
# 组合使用:重命名并格式化
{namespace="prod"} | label_format service_name=uppercase(service), env=lowercase(environment)
4.2.2 支持的格式化函数
| 函数 | 说明 | 示例 |
|---|---|---|
lowercase |
将标签值转换为小写 | lowercase(level) → "INFO" → "info" |
uppercase |
将标签值转换为大写 | uppercase(env) → "prod" → "PROD" |
titlecase |
将标签值转换为首字母大写 | titlecase(service) → "api-gateway" → "Api-Gateway" |
trim |
去除标签值前后的空白字符 | trim(host) → " host-1 " → "host-1" |
4.2.3 版本漂移场景:标签命名不一致
在微服务架构中,不同团队可能使用不同的标签命名风格(如 service_name vs serviceName vs svc)。使用 label_format 可以在查询时统一标签名,避免因标签名不匹配导致的查询结果缺失。
# 统一三个不同来源的标签名
{job=~"api|web|worker"} | label_format service=service_name
# 或
{job=~"api|web|worker"} | label_format service=serviceName
# 或
{job=~"api|web|worker"} | label_format service=svc
label_format。但作为版本漂移的应急手段,label_format 是保持查询兼容性的有力工具。
4.3 向量聚合增强:更灵活的指标计算
LogQL v2 对向量聚合进行了显著增强,引入了 sum by、avg by、max by、min by、stddev by、stdvar by 等聚合操作,并支持 without 子句来排除特定标签。这使得日志指标查询可以像 PromQL 一样灵活。
4.3.1 聚合语法对比
| 操作 | LogQL v1 | LogQL v2(增强) |
|---|---|---|
| 按标签分组求和 | 不支持 | sum by (host, path) (rate(...)) |
| 排除特定标签 | 不支持 | sum without (instance) (rate(...)) |
| 计算平均值 | 仅 avg_over_time |
avg by (region) (unwrap latency) |
| 分位数计算 | 不支持 | quantile_over_time(0.99, unwrap duration [5m]) |
4.3.2 向量聚合与 unwrap 的协同
向量聚合增强与 unwrap 结合,可以实现复杂的业务指标计算。例如,计算每个 API 端点的请求延迟 P99:
# 按 path 分组,计算 5 分钟内请求延迟的 P99
quantile_over_time(0.99,
{job="api-server"} | json | unwrap duration [5m]
) by (path)
或者计算每个主机的平均 CPU 使用率:
# 按 host 分组,计算 1 小时内的平均 CPU 使用率
avg by (host) (
avg_over_time(
{job="node-exporter"} | logfmt | unwrap cpu_usage [1h]
)
)
4.4 版本漂移适配清单
当从 LogQL v1 迁移到 v2,或在不同 Loki 版本间切换时,请对照以下清单检查查询兼容性:
- unwrap 表达式:确认日志解析器(json/logfmt/regexp)在目标版本中行为一致,特别是对嵌套 JSON 和转义字符的处理。
- label_format 函数:检查
lowercase、uppercase等函数是否支持 Unicode 字符,避免因国际化日志导致格式化失败。 - 向量聚合:验证
without子句在目标版本中是否支持排除多个标签(如without (instance, pod))。 - 分位数函数:确认
quantile_over_time的精度参数(如 0.99)在目标版本中是否支持浮点数。
loki-logql-verify --version-diff(社区工具)或手动运行一组代表性查询,对比结果集是否一致。
4.5 实战案例:统一多版本日志查询
假设你管理的集群中同时运行着 Loki v2.0 和 v2.8 实例,且日志格式存在差异。以下查询展示了如何使用 LogQL v2 特性实现跨版本兼容:
# 兼容 v2.0(无 unwrap)和 v2.8(有 unwrap)的查询
# 方案:使用 label_format 统一标签,再通过 count_over_time 兜底
{job="payment-service"} | logfmt
| label_format service=lowercase(service_name)
| unwrap amount
| quantile_over_time(0.95, unwrap amount [10m]) by (service)
# 如果目标版本不支持 unwrap,降级为基于标签的计数
# {job="payment-service"} | logfmt
# | label_format service=lowercase(service_name)
# | count_over_time [10m] by (service)