TraceQL
TraceQL 受 PromQL 和 LogQL 的启发,是一种为在 Tempo 中选择追踪而设计的查询语言。目前,TraceQL 查询可以根据以下内容选择追踪
- Span 和资源属性、计时和持续时间
- 基本聚合:
count()
、avg()
、min()
、max()
和sum()
阅读博客文章 了解 TraceQL,以获得 TraceQL 及其功能的介绍。
这里应该有一个视频,但由于某种原因没有。要么是我们输入的 ID 错误(哎呀!),要么 Vimeo 宕机了。如果是后者,我们预计他们很快就会恢复运行。同时,查看我们的博客!
TraceQL 语言尽可能使用与 PromQL 和 LogQL 相似的语法和语义。
查看 Tempo 发行说明 以了解 TraceQL 的最新更新。
要求
TraceQL 需要 Parquet 列式格式,默认情况下启用。有关 Parquet 的信息,请参阅 Apache Parquet 后端 文档。
使用 TraceQL 查询
您可以在 Tempo 数据源中使用 TraceQL 查询编辑器和查询构建器来构建查询并深入研究结果集。编辑器和构建器在 Grafana Explore 的 Tempo 数据源 中可用。
此外,您可以使用 Explore Traces 来调查您的追踪数据,而无需编写 TraceQL 查询。有关更多信息,请参阅 Explore Traces 文档。
流式查询结果
通过将结果流式传输到客户端,您可以在整个查询完成之前开始查看与您的查询匹配的追踪。
查询前端中的 GRPC 流式 API 端点允许客户端从 Tempo 流式传输搜索结果。tempo-cli
也使用此流式端点。有关更多信息,请参阅 Tempo CLI 文档。
要在 Grafana 中使用流式传输,您必须在 Tempo 中启用 stream_over_http_enabled: true
。有关信息,请参阅 Tempo GRPC API。
构建 TraceQL 查询
在 TraceQL 中,查询是在一次一个追踪上评估的表达式。查询结构化为一组称为管道的链式表达式。管道中的每个表达式都会选择或丢弃 span 集,使其不包含在结果集中。例如
{ span.http.status_code >= 200 && span.http.status_code < 300 } | count() > 2
在此示例中,搜索将追踪缩小到以下 span:
http.status_code
在200
到299
的范围内,并且- 追踪中匹配 span 的数量大于 2。
查询选择 span 集并通过聚合器和条件的管道对其进行过滤。如果对于给定的追踪,此管道生成了一个 span 集,则它将包含在查询结果中。
有关 TraceQL 指标查询的示例,请参阅 TraceQL 指标查询。
查找特定操作的追踪
假设您要查找特定操作的追踪,则应指定操作名称(span 属性 name
)和保存此操作的服务名称(资源属性 service.name
)以进行正确的过滤。在下面的示例中,追踪按 resource.service.name
值 frontend
和 span name
值 POST /api/order
进行过滤
{resource.service.name = "frontend" && name = "POST /api/orders"}
当为多个环境(例如,production
和 staging
)使用相同的 Grafana 堆栈或具有共享相同名称但通过其命名空间区分的服务时,查询如下所示
{
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"}
查找经过 production
和 staging
实例的追踪
此示例查找经过 production
和 staging
实例的追踪。这是一个方便的请求,用于识别跨生产和非生产环境的错误配置和泄漏。
{ 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" }
查找 productcatalogservice
和 frontend
是否为同级。
{ resource.service.name = "productcatalogservice" } ~ { resource.service.name="frontend" }
其他示例
查找 http 状态为 200 的服务,并列出 span 所属的服务名称以及返回的追踪。
{ span.http.status_code = 200 } | select(resource.service.name)
查找任何具有设置为 production
的无作用域 deployment.environment
属性和设置为 200
的 http.status_code
属性的追踪
{ .deployment.environment = "production" && span.http.status_code = 200 }
查找任何追踪,其中其 span 具有设置为 production
的 deployment.environment
资源属性和设置为 200
的 span http.status_code
属性。在之前的示例中,所有条件都必须在一个 span 上为真。这些条件可以在不同的 span 或相同的 span 上为真。
{ resource.deployment.environment = "production" } && { span.http.status_code = 200 }
查找任何追踪,其中任何 span 具有设置为 GET
的 http.method
属性以及设置为 ok
的 status
属性,并且其中任何其他 span 具有设置为 DELETE
的 http.method
属性,但没有设置为 ok
的 status
属性
{ span.http.method = "GET" && status = ok } && { span.http.method = "DELETE" && status != ok }
查找任何具有与正则表达式 prod-.*
匹配的 deployment.environment
属性和设置为 200
的 http.status_code
属性的追踪
{ resource.deployment.environment =~ "prod-.*" && span.http.status_code = 200 }
选择 span
在 TraceQL 中,花括号 {}
始终从可用追踪中选择一组 span。花括号通常与条件配对以减少获取的 span。
TraceQL 区分两种类型的 span 数据:内在属性(span 的基本属性)和属性(可自定义的键值对)。您可以使用内在属性和属性来构建过滤器和选择 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 | 状态枚举 | 状态:错误、正常或未设置 | { span:status = ok } |
span:statusMessage | 字符串 | 伴随 span 状态的可选文本 | { span:statusMessage = "Forbidden" } |
span:duration | 持续时间 | span 的结束时间 - 开始时间 | { span:duration > 100ms } |
span:name | 字符串 | 操作或 span 名称 | { span:name = "HTTP POST" } |
span:kind | 类型枚举 | 类型:服务器、客户端、生产者、消费者、内部、未指定 | { span:kind = server } |
span:id | 字符串 | 使用十六进制字符串的 span ID | { span:id = "0000000000000001" } |
trace:duration | 持续时间 | 追踪中 span 的 max(end) - min(start) 时间 | { trace:duration > 100ms } |
trace:rootName | 字符串 | 如果存在,则追踪中根 span 的名称 | { trace:rootName = "HTTP GET" } |
trace:rootService | 字符串 | 如果存在,则追踪中根 span 的服务名称 | { trace:rootService = "gateway" } |
trace:id | 字符串 | 使用十六进制字符串的追踪 ID | { trace:id = "1234567890abcde" } |
event:name | 字符串 | 事件名称 | { event:name = "exception" } |
event:timeSinceStart | 持续时间 | 事件相对于 span 开始时间的时间 | { event:timeSinceStart > 2ms} |
link:spanID | 字符串 | 使用十六进制字符串的链接 span ID | { link:spanID = "0000000000000001" } |
link:traceID | 字符串 | 使用十六进制字符串的链接追踪 ID | { link:traceID = "1234567890abcde" } |
instrumentation:name | 字符串 | Instrumentation 作用域名称 | { instrumentation:name = "grpc" } |
instrumentation:version | 字符串 | Instrumentation 作用域版本 | { instrumentation:version = "1.0.0" } |
追踪级别的内在属性 trace:duration
、trace:rootName
和 trace: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 属性、资源属性、事件属性、链接属性和 Instrumentation 作用域属性。
通过在 Grafana UI 中展开 span,您可以看到其 span 属性(屏幕截图中的 1)和资源属性(屏幕截图中的 2)。
属性字段源自 span 并且可以自定义。进程和 span 属性类型 由属性本身定义,而内在字段具有内置类型。您可以引用 span 或 span 资源上的动态属性(也称为标签)。
查询中的属性以 span、resource、event 或 link 作用域开头。例如,您可以根据要查询的内容使用 span.http
或 resource.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 是一种偶然关系。有关 span 链接的更多信息,请参阅 Open Telemetry 项目中的 Span Links 文档。
您可以在链接中搜索属性
{ link.opentracing.ref_type = "child_of" }
Instrumentation 作用域允许您查询 Instrumentation 作用域 字段,以便您可以根据追踪的 Instrumentation 位置和方式来过滤和探索追踪。此作用域的主要用途是根据生成数据的各种库和客户端来查询您的追踪数据。
查找 Instrumentation 作用域编程语言
{ instrumentation.language = "java" }
查找为给定服务生成 Instrumentation 的库
{ resource.service.name = "foo" } | rate() by (instrumentation:name)
Tempo 2.7 发行视频 演示并解释了 instrumentation
作用域,从 30 秒开始。
无作用域属性字段
如果您不确定请求的属性是否存在于 span 或资源上,则属性可以是无作用域的。如果可能,请使用作用域属性而不是无作用域属性。作用域属性提供更快的查询结果。
例如,要查找具有设置为 critical
的 sla
属性的追踪
{ .sla = "critical" }
带引号的属性名称
属性名称可以包含终端字符,例如句点 (.
)。要搜索具有终端字符的 span 属性,您可以使用带引号的属性语法。将带引号的属性括在双引号内,例如 "example one"
。引号之间的所有字符都被视为属性名称的一部分。
示例
要查找具有属性名称 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
属性为 GET
或 DELETE
的所有追踪
{ span.http.method =~ "DELETE|GET" }
查找 any_attribute
不为 nil
或 any_attribute
存在于 span 中的所有追踪
{ .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 上为真。一对 {}
内的整个表达式必须在一个 span 上评估为真,才能将其包含在结果集中。
在上面的示例中,如果一个 span 包含设置为 DELETE
的 .http.method
属性,而该 span 也包含设置为 ok
的 status
属性,则该追踪将不包含在返回的结果中。
组合 spanset
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}
- 后代运算符 (>>
) 查找与{condB}
匹配的 span,这些 span 是与{condA}
匹配的 span 的后代{condA} << {condB}
- 祖先运算符 (<<
) 查找与{condB}
匹配的 span,这些 span 是与{condA}
匹配的 span 的祖先{condA} > {condB}
- 子运算符 (>
) 查找与{condB}
匹配的 span,这些 span 是与{condA}
匹配的父 span 的直接子 span{condA} < {condB}
- 父运算符 (<
) 查找与{condB}
匹配的 span,这些 span 是与{condA}
匹配的子 span 的直接父 span{condA} ~ {condB}
- 同级运算符 (~
) 查看与{condB}
匹配的 span,这些 span 至少有一个与{condA}
匹配的同级 span。
例如,查找特定 HTTP API 与特定数据库交互的追踪
{ span.http.url = "/path/of/api" } >> { span.db.name = "db-shard-001" }
联合结构
这些 spanset 运算符查看追踪的结构以及 span 之间的关系。这些运算符的独特之处在于它们返回在运算符两侧都匹配的 span。
{condA} &>> {condB}
- 后代运算符 (>>
) 查找与{condB}
匹配的 span,这些 span 是与{condA}
匹配的 span 的后代。{condA} &<< {condB}
- 祖先运算符 (<<
) 查找与{condB}
匹配的 span,这些 span 是与{condA}
匹配的 span 的祖先。{condA} &> {condB}
- 子运算符 (>
) 查找与{condB}
匹配的 span,这些 span 是与{condA}
匹配的父 span 的直接子 span。{condA} &< {condB}
- 父运算符 (<
) 查找与{condB}
匹配的 span,这些 span 是与{condA}
匹配的子 span 的直接父 span。{condA} &~ {condB}
- 同级运算符 (~
) 查看与{condB}
匹配的 span,这些 span 至少有一个与{condA}
匹配的同级 span。
例如,在一个查询中获取失败的端点和所有后代失败的 span
{ span.http.url = "/path/of/api" && status = error } &>> { status = error }
实验性结构
这些 spanset 运算符查看追踪的结构以及 span 之间的关系。这些运算符被标记为实验性,因为有时会返回误报。但是,这些运算符可能非常有用(请参阅下面的示例)。
{condA} !>> {condB}
- 非后代运算符 (!>>
) 查找与{condB}
匹配的 span,这些 span 不是与{condA}
匹配的父 span 的后代 span{condA} !<< {condB}
- 非祖先运算符 (!<<
) 查找与{condB}
匹配的 span,这些 span 不是与{condA}
匹配的子 span 的祖先 span{condA} !> {condB}
- 非子运算符 (!>
) 查找与{condB}
匹配的 span,这些 span 不是与{condA}
匹配的父 span 的直接子 span{condA} !< {condB}
- 非父运算符 (!<
) 查找与{condB}
匹配的 span,这些 span 不是与{condA}
匹配的子 span 的直接父 span{condA} !~ {condB}
- 非同级运算符 (!~
) 查看与{condB}
匹配的 span,这些 span 没有至少一个与{condA}
匹配的同级 span。
阅读 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 个 span 且属性 http.status_code
值为 200
的追踪
{ span.http.status_code = 200 } | count() > 3
查找总计由虚构属性 bytesProcessed
超过 1 GB 的 span
{ } | sum(span.bytesProcessed) > 1000000000
分组
TraceQL 支持分组管道运算符,该运算符可用于按任意属性分组。这对于查找具有超过 1 个错误的单个服务之类的东西很有用
{ 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 指标查询。