4. Tempo查询语言基础:TraceQL语法入门、Span选择器、属性过滤、时间范围

TraceQL 是 Grafana Tempo 原生的结构化查询语言,专为 Trace 数据设计。与 PromQL(指标)或 LogQL(日志)不同,TraceQL 直接操作 Span 的结构化属性,允许你通过 Span 选择器、属性过滤和时间范围精确锁定目标 Trace,从而大幅缩短 MTTR 复盘口径的查询时间。

4.1 TraceQL 核心语法结构

TraceQL 的查询由三个基本组件构成:Span 选择器、属性过滤器和管道操作。其基础语法模式如下:

{ span.selector } | attribute_filter | pipeline_operation
组件 说明 示例
Span 选择器 用花括号 {} 包裹,定义要匹配的 Span 集合 { span.http.method = "GET" }
属性过滤器 在管道符 | 后使用,进一步缩小结果范围 | span.http.status_code >= 500
管道操作 对结果进行聚合、计数或取最新 Trace | count() 或 | latest(10)
MTTR 复盘提示:在定位 SLO 违约根因时,优先使用 {} 选择器缩小到错误 Span,再通过管道过滤出高延迟或异常状态码的 Trace,避免扫描全量数据。

4.2 Span 选择器详解

Span 选择器是 TraceQL 的入口,决定了查询的起点。它支持按 Span 名称、服务名称、Span 状态和资源属性进行匹配。

4.2.1 基础选择器语法

{ span.service.name = "checkout-service" }
{ span.name = "HTTP POST /api/order" }
{ span.status = error }

4.2.2 选择器操作符

操作符 含义 示例
= 精确匹配 { span.http.method = "POST" }
!= 不等于 { span.http.method != "GET" }
=~ 正则匹配 { span.name =~ ".*/order.*" }
!~ 正则不匹配 { span.name !~ "health.*" }
> / < 数值比较 { span.duration > 2s }
性能注意:正则匹配 =~ 和 !~ 会显著增加查询开销。在 MTTR 复盘场景中,尽量使用精确匹配 = 或数值范围过滤,避免在大量 Span 上执行正则。

4.3 属性过滤与管道操作

属性过滤在管道符 | 之后使用,可以对选择器结果进行二次筛选。管道操作则用于聚合和排序。

4.3.1 常用属性过滤

{ span.service.name = "payment-service" }
| span.http.status_code >= 500
| span.duration > 1s

上述查询的含义:先选择 payment-service 的所有 Span,再过滤出 HTTP 状态码 >= 500 且持续时间超过 1 秒的 Span。

4.3.2 管道聚合操作

操作 说明 MTTR 场景用途
count() 统计匹配的 Span 数量 快速评估错误 Span 的爆发量
avg() 计算数值属性的平均值 计算错误 Span 的平均延迟
latest(N) 返回最近的 N 条 Trace 获取最新违约 Trace 用于复盘
by() 按属性分组聚合 按服务或状态码分组统计错误

4.3.3 分组聚合示例

{ span.status = error }
| count() by(span.service.name)

该查询返回每个服务中错误 Span 的数量,帮助快速定位哪个服务是 SLO 违约的“重灾区”。

4.4 时间范围与 TraceQL 结合

TraceQL 查询必须与时间范围配合使用。Tempo 支持两种时间范围指定方式:查询参数和相对时间语法。

4.4.1 查询参数方式(Grafana UI)

在 Grafana Explore 中,通过顶部时间选择器设置时间范围,TraceQL 查询会自动应用该范围。例如选择 Last 15 minutes,则查询只扫描最近 15 分钟的 Span 数据。

4.4.2 相对时间语法(API / 脚本)

在 Tempo API 或自动化脚本中,使用 start 和 end 参数指定 Unix 时间戳(纳秒精度):

start=1728000000000000
end=1728086400000000

4.4.3 MTTR 复盘中的时间范围策略

复盘阶段 推荐时间范围 说明
实时告警确认 Last 5 minutes 快速确认当前是否正在发生违约
根因定位 Last 1 hour 覆盖告警触发前后的完整上下文
MTTR 复盘 违约时间点 ± 30 min 精确聚焦违约窗口,减少无关数据干扰
趋势分析 Last 24 hours 观察错误模式的周期性或渐进性变化
最佳实践:在 MTTR 复盘口径中,始终将时间范围缩小到违约窗口的 ±30 分钟。过大的时间范围会引入噪声,增加查询延迟;过小则可能遗漏前置依赖 Span。

4.5 TraceQL 查询流程架构

下图展示了从 TraceQL 查询输入到最终 Trace 结果返回的完整数据流,帮助理解各组件在查询链路中的角色。

TraceQL 查询执行流程 TraceQL 查询 语法解析器 Span 选择器 属性过滤器 时间范围过滤 Tempo 存储 结果聚合 Trace / Span 结果集 说明:时间范围过滤在属性过滤之后执行,确保只扫描违约窗口内的 Span 数据,降低查询延迟

4.6 实战:MTTR 复盘口径查询示例

假设某 SLO 违约发生在 2025-06-01 14:30 UTC,目标服务为 order-service,错误类型为 HTTP 500。以下 TraceQL 查询用于快速定位根因 Trace:

{ span.service.name = "order-service" && span.http.status_code >= 500 }
| span.duration > 2s
| latest(20)

该查询的含义:

  • 选择器:匹配 order-service 中所有 HTTP 状态码 >= 500 的 Span
  • 过滤:只保留持续时间超过 2 秒的 Span(排除瞬时错误)
  • 管道:返回最近的 20 条完整 Trace,用于人工复盘
复盘技巧:在得到 Trace 结果后,使用 Tempo 的 Span 时间线视图观察各 Span 的调用顺序和耗时分布。通常根因 Span 会表现出异常的高延迟或错误状态码,且其子 Span 会呈现连锁失败模式。

4.7 常见错误与避坑指南

错误模式 错误示例 正确写法 说明
选择器内缺少花括号 span.service.name = "x" { span.service.name = "x" } 选择器必须用 {} 包裹
属性名拼写错误 { span.http.method = "POST" } { span.http.method = "POST" } 注意属性名区分大小写
时间范围过大 查询未指定时间范围 设置 ±30 分钟窗口 全量扫描会导致超时或高成本
管道顺序错误 | count() | span.duration > 1s | span.duration > 1s | count() 过滤必须在聚合之前

4.8 TraceQL 与 PromQL 对比

理解 TraceQL 与 PromQL 的差异,有助于 SRE 团队在指标和 Trace 之间建立统一的排查思维。

TraceQL vs PromQL 查询对比 PromQL(指标) 查询对象:时间序列(指标) 粒度:聚合后的指标值 示例: rate(http_requests_total{status="500"}[5m]) 输出:数值 / 时间序列 TraceQL(Trace) 查询对象:Span / Trace 粒度:单个请求的完整调用链 示例: { span.http.status_code >= 500 } | latest(10) 输出:Trace / Span 列表
核心差异:PromQL 告诉你“错误率上升了”,TraceQL 告诉你“是哪个请求、哪个服务、哪个代码路径导致的错误”。在 MTTR 复盘口径中,两者配合使用:先用 PromQL 发现异常,再用 TraceQL 定位根因。