菜单
开源 RSS

TraceQL

TraceQL 受 PromQL 和 LogQL 的启发,是一种为 Tempo 中选择追踪而设计的查询语言。目前,TraceQL 查询可以基于以下内容选择追踪:

  • Span 和资源属性、时间以及时长
  • 基本聚合:count()avg()min()max()sum()

阅读博文 认识 TraceQL,了解 TraceQL 及其功能的简介。

在可能的情况下,TraceQL 语言使用与 PromQLLogQL 类似的语法和语义。

查看 Tempo 发布说明,了解 TraceQL 的最新更新。

要求

TraceQL 需要 Parquet 列式格式,该格式默认启用。有关 Parquet 的信息,请参阅 Apache Parquet 后端文档。

使用 TraceQL 查询

您可以在 Tempo 数据源中使用 TraceQL 查询编辑器和查询构建器来构建查询并下钻到结果集。编辑器和构建器可在 Grafana Explore 的 Tempo 数据源中使用。

Query editor showing request for http.method

此外,您可以使用 Traces Drilldown 来调查您的追踪数据,而无需编写 TraceQL 查询。有关更多信息,请参阅 Traces Drilldown 文档。

流式查询结果

通过将结果流式传输到客户端,您可以在整个查询完成之前开始查看与查询匹配的追踪。

查询前端的 GRPC 流式 API 端点允许客户端从 Tempo 流式传输搜索结果。tempo-cli 也使用此流式端点。有关更多信息,请参阅 Tempo CLI 文档

要在 Grafana 中使用流式传输,必须在 Tempo 中启用 stream_over_http_enabled: true。有关信息,请参阅 Tempo GRPC API

构造 TraceQL 查询

在 TraceQL 中,查询是一个表达式,它一次对一个追踪进行求值。查询被构造为一组链式表达式,称为管道。管道中的每个表达式选择或丢弃要包含在结果集中的 spanset。例如:

{ span.http.status_code >= 200 && span.http.status_code < 300 } | count() > 2

在此示例中,搜索将追踪范围缩小到以下 span:

  • http.status_code200299 的范围内,并且
  • 一个追踪中匹配的 span 数量大于 2。

查询选择 span 集,并通过聚合器和条件的管道对其进行过滤。如果对于给定的追踪,此管道生成一个 spanset,则将其包含在查询结果中。

有关 TraceQL 指标查询的示例,请参阅 TraceQL 指标查询

查找特定操作的追踪

假设您想查找特定操作的追踪,则应指定操作名称(span 属性 name)和包含此操作的服务名称(资源属性 service.name)以进行适当过滤。在下面的示例中,追踪是根据 resource.service.namefrontend 和 span namePOST /api/order 进行过滤的。

{resource.service.name = "frontend" && name = "POST /api/orders"}

当将相同的 Grafana stack 用于多个环境(例如,productionstaging)或具有共享相同名称但通过其命名空间区分的服务时,查询如下所示:

{
  resource.service.namespace = "ecommerce" &&
  resource.service.name = "frontend" &&
  resource.deployment.environment = "production" &&
  name = "POST /api/orders"
}

查找具有特定结果的追踪

此示例查找操作 POST /api/orders 上所有包含出错 span 的追踪:

{
  resource.service.name="frontend" &&
  name = "POST /api/orders" &&
  status = error
}

此示例查找操作 POST /api/orders 上所有返回 HTTP 5xx 错误的追踪:

{
  resource.service.name="frontend" &&
  name = "POST /api/orders" &&
  span.http.status_code >= 500
}

查找具有特定行为的追踪

您可以使用查询对追踪的多个 span 进行过滤。此示例查找访问数据库的 GET /api/products/{id} 操作的所有追踪。这是一项方便的请求,用于识别缓存问题引起的数据库异常访问率。

{span.service.name="frontend" && name = "GET /api/products/{id}"} && {.db.system="postgresql"}

查找经过 productionstaging 实例的追踪

此示例查找经过 productionstaging 实例的追踪。这是一项方便的请求,用于识别跨生产和非生产环境的配置错误和泄露。

{ resource.deployment.environment = "production" } && { resource.deployment.environment = "staging" }

查找带有数组的追踪

TraceQL 自动查询数组中包含的数据。vParquet4 及更高版本支持数组。

如果 span.foo 是一个数组且包含值 bar,则此查询将找到它。

{ span.foo = "bar" }

您可以使用正则表达式匹配数组的多个值 {span.http.request.header.Accept=~"application.*"},并使用 .* 正则表达式获取数组的所有值。

{span.http.request.header.Accept=~".*"}

使用结构运算符

查找包含 frontend 服务,且该服务或下游服务包含设置了错误的 span 的追踪。

{ resource.service.name="frontend" } >> { status = error }

查找所有以 productcatalogservice 结尾的叶子 span。

{ } !< { resource.service.name = "productcatalogservice" }

查找 productcatalogservicefrontend 是否为兄弟。

{ resource.service.name = "productcatalogservice" } ~ { resource.service.name="frontend" }

其他示例

查找 http 状态为 200 的服务,并列出 span 所属的服务名称以及返回的追踪。

{ span.http.status_code = 200 } | select(resource.service.name)

查找任何设置了未指定范围的 deployment.environment 属性为 productionhttp.status_code 属性为 200 的追踪。

{ .deployment.environment = "production" && span.http.status_code = 200 }

查找任何追踪,其中 span 设置了 deployment.environment 资源属性为 production,并且 span 具有 http.status_code 属性为 200。在前面的示例中,所有条件都必须在同一个 span 上为 true。这些条件可以在不同的 span 或同一个 span 上为 true。

{ resource.deployment.environment = "production" } && { span.http.status_code = 200 }

查找任何追踪,其中任何 span 设置了 http.method 属性为 GETstatus 属性为 ok,并且任何其他 span 设置了 http.method 属性为 DELETE,但没有设置 status 属性为 ok

{ span.http.method = "GET" && status = ok } && { span.http.method = "DELETE" && status != ok }

查找任何具有匹配正则表达式 prod-.*deployment.environment 属性和设置了 http.status_code 属性为 200 的追踪。

{ resource.deployment.environment =~ "prod-.*" && span.http.status_code = 200 }

选择 Span

在 TraceQL 中,花括号 {} 总是从可用的追踪中选择一组 span。花括号通常与条件配对,以减少获取的 span 数量。

TraceQL 区分两种类型的 span 数据:内在属性 (intrinsics),它们是 span 的基础;以及属性 (attributes),它们是可定制的键值对。您可以使用内在属性和属性来构建过滤器和选择 span。

内在字段对于范围来说是基础性的。内在字段是固有存在的,与开发者添加的其他键值对(属性)不同。

内在属性总是使用 <scope>: 表示。请参阅 内在属性表 了解所有当前的内在属性。

内在属性示例

{ span:name = "foo" }
{ event:name = "foo" }
{ trace:id = "1234" }
{ link:traceID = "1234" }

自定义属性以 <scope>. 为前缀,例如 span.resource.link.event。资源没有内在值。它只有自定义属性。

属性用点号 (.) 分隔,而内在字段使用冒号 (:)。trace 范围只是一个内在属性,在追踪级别没有任何自定义属性。

属性示例

{ span.foo = "bar" }
{ resource.foo = "bar" }
{ link.foo = "bar" }
{ event.foo = "bar" }

内在字段

下表显示了当前可用的范围内在字段

字段类型定义示例
span:status状态枚举状态:error, ok, 或 unset{ span:status = ok }
span:statusMessagestringspan 状态的可选文本描述{ span:statusMessage = "Forbidden" }
span:duration时长span 的结束时间 - 开始时间{ span:duration > 100ms }
span:namestring操作或 span 名称{ span:name = "HTTP POST" }
span:kind种类枚举种类:server, client, producer, consumer, internal, unspecified{ span:kind = server }
span:idstring使用十六进制字符串表示的 span ID{ span:id = "0000000000000001" }
trace:duration时长追踪中 span 的最大结束时间 - 最小开始时间{ trace:duration > 100ms }
trace:rootNamestring如果存在,追踪中根 span 的名称{ trace:rootName = "HTTP GET" }
trace:rootServicestring如果存在,追踪中根 span 的服务名称{ trace:rootService = "gateway" }
trace:idstring使用十六进制字符串表示的追踪 ID{ trace:id = "1234567890abcde" }
event:namestring事件名称{ event:name = "exception" }
event:timeSinceStart时长事件相对于 span 开始时间的时间{ event:timeSinceStart > 2ms}
link:spanIDstring使用十六进制字符串表示的链接 span ID{ link:spanID = "0000000000000001" }
link:traceIDstring使用十六进制字符串表示的链接追踪 ID{ link:traceID = "1234567890abcde" }
instrumentation:namestring仪表化范围名称{ instrumentation:name = "grpc" }
instrumentation:versionstring仪表化范围版本{ instrumentation:version = "1.0.0" }

追踪级别内在属性 trace:durationtrace:rootNametrace:rootService 对于同一追踪中的所有 span 都是相同的。此外,这些内在属性性能显著更高,因为它们检查的数据比 span 级别内在属性少得多。应尽可能优先使用它们而非 span 级别内在属性。

有时您可能希望按追踪级别内在属性进行搜索。例如,使用 span:name 会查找追踪中 span 的名称。如果您希望按追踪名称 perf 进行搜索,请使用 trace:rootName 进行匹配。

此示例搜索所有名为 service-name 的 Kubernetes 集群,这些集群包含根名称包含 perf 的 span。

{ resource.k8s.cluster.name="service-name" && trace:rootName !~ ".*perf.*"}

属性字段

TraceQL 支持这些不同的属性范围:span 属性、资源属性、事件属性、链接属性和仪表化范围属性。

通过在 Grafana UI 中展开 span,您可以看到其 span 属性(屏幕截图中的 1)和资源属性(屏幕截图中的 2)。

Example of span and resource  attributes.

属性字段派生自 span 并且可以定制。进程和 span 属性类型 由属性本身定义,而内在字段具有内置类型。您可以引用 span 或 span 资源的动态属性(也称为标签)。

查询中的属性以 span、resource、event 或 link 范围开头。例如,根据您想要查询的内容,可以使用 span.httpresource.namespace。这提供了显著的性能优势,因为 Tempo 只扫描您感兴趣的数据。

要查找使用 GET HTTP 方法的追踪,您的查询可以如下所示

{ span.http.method = "GET" }

有关属性和资源的更多信息,请参阅 OpenTelemetry Resource SDK

示例

查找经过 production 环境的追踪

{ resource.deployment.environment = "production" }

查找连接到 Postgres 或 MySQL 数据库的任何数据库连接字符串

{ span.db.system =~ "postgresql|mysql" }

您可以使用 event 范围来查询 span 中发生的事件。span 事件是 span 持续期间的一个独特时间点。虽然 span 有助于构建服务的结构层级,但 span 事件可以提供更深层次的粒度,帮助您更快地调试应用程序并保持最佳性能。要了解如何使用 span 事件,请阅读 什么是 Span 事件? 博文。

您可以在 span 事件中查询异常

{ event.exception.message =~ ".*something went wrong.*" }

如果您已为 span 链接对追踪进行仪表化,则可以使用 link 范围查询链接数据。span 链接将一个 span 与一个或多个具有因果关系的其他 span 相关联。有关 span 链接的更多信息,请参阅 Open Telemetry 项目中的 Span 链接文档。

您可以在链接中搜索属性

{ link.opentracing.ref_type = "child_of" }

仪表化范围允许您查询 仪表化范围 字段,以便您可以根据追踪的仪表化位置和方式进行过滤和探索。此范围的主要用途是根据生成数据的各种库和客户端查询追踪数据。

查找仪表化范围编程语言

{ instrumentation.language = "java" }

查找为给定服务生成仪表化的库

{ resource.service.name = "foo" } | rate() by (instrumentation:name)

Tempo 2.7 发布视频 从 30 秒开始演示和解释了 instrumentation 范围。

无范围属性字段

如果您不确定请求的属性是否存在于 span 或资源上,则属性可以没有范围。如果可能,请使用范围属性而不是无范围属性。范围属性提供更快的查询结果。

例如,查找设置为 criticalsla 属性的追踪:

{ .sla = "critical" }

带引号的属性名称

属性名称可能包含终端字符,例如点号 (.)。要搜索包含终端字符的 span 属性,可以使用带引号的属性语法。将带引号的属性用双引号括起来,例如,"示例一"。双引号之间的所有字符都被视为属性名称的一部分。

示例

要查找属性名称为 attribute name with space 的 span,请使用以下查询:

{ ."attribute name with space" = "value" }

您可以将带引号的属性语法与非带引号的属性语法一起使用,以下是有效的 TraceQL 查询:

{ span.attribute."attribute name with space" = "value" }

注意

目前,仅支持 \"\\ 转义序列。

比较运算符

比较运算符用于测试表达式中的值。

已实现的比较运算符包括:

  • = (等于)
  • != (不等于)
  • > (大于)
  • >= (大于或等于)
  • < (小于)
  • <= (小于或等于)
  • =~ (正则表达式匹配)
  • !~ (正则表达式不匹配)

TraceQL 使用 Golang 正则表达式。像 https://regex101.com/ 这样的在线正则表达式测试网站方便用于验证 TraceQL 查询中使用的正则表达式。所有正则表达式都被视为完全锚定的。

正则表达式在两端都被锚定。这种锚定使查询更快,并与 PromQL 的行为相匹配,PromQL 中的正则表达式也是完全锚定的。

未锚定的查询,例如:{ span.foo =~ “bar” } 现在被视为:{ span.foo =~ “^bar$” }。

如果您在 Grafana 仪表盘中使用带有正则表达式的 TraceQL,并且希望获得未锚定的行为,请更新查询以使用未锚定版本,例如 { span.foo =~ “.bar.”}。

例如,查找 span 中 http.status_code 属性大于 400 但小于等于 500 的所有追踪:

{ span.http.status_code >= 400 && span.http.status_code < 500 }

这对于字符串类型的 http.status_code 值也同样适用,使用词典排序:

{ span.http.status_code >= "400" }

查找 http.method 属性为 GETDELETE 的所有追踪:

{ span.http.method =~ "DELETE|GET" }

查找 any_attribute 不为 nil 或 span 中存在 any_attribute 的所有追踪:

{ .any_attribute != nil }

字段表达式

字段还可以以各种方式组合,以允许更灵活的搜索条件。字段表达式是多个字段的组合,它们定义了必须匹配的所有条件才能返回结果。

示例

查找具有 success http.status_code 代码的追踪

{ span.http.status_code >= 200 && span.http.status_code < 300 }

查找使用了 DELETE HTTP 方法且内在 span 状态不是 OK 的追踪:

{ span.http.method = "DELETE" && status != ok }

两个表达式都要求在同一个 span 上所有条件都为 true。一对 {} 内的整个表达式必须在单个 span 上计算为 true,才能将其包含在结果集中。

在上面的示例中,如果一个 span 包含设置为 DELETE.http.method 属性,并且该 span 也包含设置为 okstatus 属性,则该追踪将不包含在返回结果中。

组合 Spansets

Spanset 运算符允许您从追踪中选择不同的 span 集,然后在它们之间进行判断。

逻辑

这些 spanset 运算符在 span 集之间执行逻辑检查。

  • {condA} && {condB} - 与运算符 (&&) 检查两个条件是否都找到了匹配项。
  • {condA} || {condB} - 或运算符 (||) 检查任一条件是否找到了匹配项。

例如,查找经过两个特定 cloud.region 的追踪:

{ resource.cloud.region = "us-east-1" } && { resource.cloud.region = "us-west-1" }

注意上一个示例与此示例之间的区别:

{ resource.cloud.region = "us-east-1" && resource.cloud.region = "us-west-1" }

第二个表达式不返回任何追踪,因为单个 span 不可能同时将 resource.cloud.region 属性设置为两个区域值。

结构

这些 spanset 运算符查看追踪的结构以及 span 之间的关系。结构运算符总是返回运算符右侧的匹配项。

  • {condA} >> {condB} - 后代运算符 (>>) 查找与 {condA} 匹配的 span 的后代 span 中与 {condB} 匹配的 span。
  • {condA} << {condB} - 祖先运算符 (<<) 查找与 {condA} 匹配的 span 的祖先 span 中与 {condB} 匹配的 span。
  • {condA} > {condB} - 子运算符 (>) 查找与 {condA} 匹配的父 span 的直接子 span 中与 {condB} 匹配的 span。
  • {condA} < {condB} - 父运算符 (<) 查找与 {condA} 匹配的子 span 的直接父 span 中与 {condB} 匹配的 span。
  • {condA} ~ {condB} - 兄弟运算符 (~) 查看与 {condB} 匹配的 span,这些 span 至少有一个与 {condA} 匹配的兄弟。

例如,查找特定 HTTP API 与特定数据库交互的追踪:

{ span.http.url = "/path/of/api" } >> { span.db.name = "db-shard-001" }

联合结构

这些 spanset 运算符查看追踪的结构以及 span 之间的关系。这些运算符的独特之处在于它们返回与运算符两侧都匹配的 span。

  • {condA} &>> {condB} - 后代运算符 (>>) 查找与 {condA} 匹配的 span 的后代 span 中与 {condB} 匹配的 span。
  • {condA} &<< {condB} - 祖先运算符 (<<) 查找与 {condA} 匹配的 span 的祖先 span 中与 {condB} 匹配的 span。
  • {condA} &> {condB} - 子运算符 (>) 查找与 {condA} 匹配的父 span 的直接子 span 中与 {condB} 匹配的 span。
  • {condA} &< {condB} - 父运算符 (<) 查找与 {condA} 匹配的子 span 的直接父 span 中与 {condB} 匹配的 span。
  • {condA} &~ {condB} - 兄弟运算符 (~) 查看与 {condB} 匹配的 span,这些 span 至少有一个与 {condA} 匹配的兄弟。

例如,在一个查询中获取失败的端点 AND 所有后代失败的 span:

{ span.http.url = "/path/of/api" && status = error } &>> { status = error }

实验性结构

这些 spanset 运算符查看追踪的结构以及 span 之间的关系。这些运算符被标记为实验性,因为有时会返回误报。但是,这些运算符可能非常有用(请参阅以下示例)。

  • {condA} !>> {condB} - 非后代运算符 (!>>) 查找与 {condA} 匹配的父 span 的非后代 span 中与 {condB} 匹配的 span。
  • {condA} !<< {condB} - 非祖先运算符 (!<<) 查找与 {condA} 匹配的子 span 的非祖先 span 中与 {condB} 匹配的 span。
  • {condA} !> {condB} - 非子运算符 (!>) 查找与 {condA} 匹配的父 span 的非直接子 span 中与 {condB} 匹配的 span。
  • {condA} !< {condB} - 非父运算符 (!<) 查找与 {condA} 匹配的子 span 的非直接父 span 中与 {condB} 匹配的 span。
  • {condA} !~ {condB} - 非兄弟运算符 (!~) 查看与 {condB} 匹配的 span,这些 span 没有至少一个与 {condA} 匹配的兄弟。

阅读 Tempo 2.3 博客文章 获取更多示例和详细信息。

例如,查找服务“foo”中包含叶子 span 的追踪:

{ } !< { resource.service.name = "foo" }

查找一系列级联错误中最后一个错误的 span:

{ status = error } !< { status = error }

聚合器

到目前为止,所有示例查询表达式都涉及单个 span。您可以使用聚合函数来询问有关一组 span 的问题。目前包括:

  • count - spanset 中 span 的数量。
  • avg - spanset 中给定数字属性或内在属性的平均值。
  • max - spanset 中给定数字属性或内在属性的最大值。
  • min - spanset 中给定数字属性或内在属性的最小值。
  • sum - spanset 中给定数字属性或内在属性的总和。

聚合函数允许您对匹配的结果执行操作,以进一步优化返回的追踪。有关未来计划工作的更多信息,请参阅TraceQL 工作原理

例如,查找总 span 数量大于 10 的追踪:

count() > 10

查找追踪中 span 的平均时长大于 20ms 的追踪:

avg(duration) > 20ms

例如,查找具有 3 个以上 http.status_code 属性值为 200 的 span 的追踪:

{ span.http.status_code = 200 } | count() > 3

查找制造的属性 bytesProcessed 总计超过 1 GB 的 span:

{ } | sum(span.bytesProcessed) > 1000000000

分组

TraceQL 支持分组管道运算符,可用于按任意属性进行分组。这对于查找具有多个错误的服务非常有用:

{ status = error } | by(resource.service.name) | count() > 1

算术运算

TraceQL 支持在您的查询中进行任意算术运算。这对于使查询更易于理解很有用:

{ span.http.request_content_length > 10 * 1024 * 1024 }

或您想到的任何其他内容。

选择

TraceQL 可以从 span 中选择任意字段。这种性能尤其高,因为只有在满足所有其他条件后才检索选定的字段。

{ status=error } | select(span.http.status_code, span.http.url)

实验性 TraceQL 指标

TraceQL 指标是实验性的,但很容易上手。有关更多信息,请参阅TraceQL 指标文档。

您还可以使用 TraceQL 指标查询。有关详细信息,请参阅TraceQL 指标查询