菜单
Enterprise 开源

使用追踪诊断错误

追踪允许您快速诊断应用程序中的错误,确保您可以对请求失败执行根源分析 (RCA)。追踪可视化有助于您确定发生错误的 Span,以及这些错误背后的上下文,从而缩短平均修复时间。

认识 Handy Site 公司

Handy Site 公司,一家虚构的网站公司,运行着一个电子商务应用程序,其中包括用户认证、产品目录、订单管理、支付处理等服务。

Handy Site 的运营团队收到了几个关于其服务中监控端点的错误服务水平目标 (SLO) 警报。他们使用 Grafana 仪表盘注意到存在几个问题。仪表盘提供了错误率

Dashboard showing errors in services

用户请求中有超过 5% 在多个端点(例如 `/beholder`、`/owlbear` 和 `/illithid`)上出现错误,这导致性能和可用性下降。对于 Handy Site 的运营团队来说,快速排除故障至关重要。错误率升高表明 Handy Site 无法向用户请求提供有效的响应,这不仅威胁到运营团队的 SLO 错误预算,还会影响 Handy Site 的整体盈利能力。

使用 TraceQL 查询数据

Tempo 提供了一种追踪优先的查询语言 TraceQL,它为选择和搜索追踪数据提供了独特的工具集。TraceQL 可以基于 Span 和资源属性、持续时间以及祖先<>后代关系匹配追踪。该语言还可以计算聚合统计信息,例如一组 Span 的速率。

Handy Site 已对其服务和应用程序进行了追踪插桩,因此他们可以将 TraceQL 作为调试工具。通过使用三个 TraceQL 查询,团队识别并验证了问题的根源。

查找 HTTP 错误

顶层服务 `mythical-requester` 接收用户的请求并返回响应。当它接收到请求时,它会调用许多下游服务,并依赖这些服务的响应来向用户请求发送响应。使用 Grafana Explore,运营团队从一个简单的 TraceQL 查询开始,查找来自此顶层服务的所有追踪,其中发送给用户的 HTTP 响应代码为 400 或更高。此范围内的状态码包括 `Forbidden`、`Not found`、`Unauthorized` 以及其他客户端和服务器错误。

traceql
{ resource.service.name = "mythical-requester" && span.http.status_code >= 400 } | select(span.http.target)

在此查询中(在 `|` 之后)添加 `select` 语句可确保查询响应不仅包含匹配的 Span 集,还包含每个 Span 的 `http.target` 属性(例如,SaaS 服务的端点)。

Query results showing http.target attribute

精确定位错误

查看返回的 Span 集,最令人担忧的是状态码为 `HTTP 500` 的 Span。这些是内部服务器错误。

团队决定使用结构化运算符来跟踪从顶层 `mythical-requester` 服务到任何具有错误状态的后代 Span 的错误链。后代 Span 可以是任何从父 Span 派生的 Span,例如任何深度的子 Span 或更下一级的子 Span。使用此查询,团队可以精确定位可能导致问题的下游服务。下面的查询表示“查找状态为 `error` 且是来自 `mythical-requester` 服务且状态码为 500 的 Span 的后代的 Span。”

traceql
{ resource.service.name = "mythical-requester" && span.http.status_code = 500 } >> { status = error }

TraceQL results showing expanded span

展开作为 `mythical-server` 服务 Span 后代的错误 Span 显示,插入到数据库中的数据存在问题。具体来说,该服务正在为数据库表中不允许 `null` 值的列传递 `null` 值。

Error span for INSERT

验证根源

在确定此内部服务器错误的具体原因后,团队想知道是否存在除上述 `null` `INSERT` 错误之外的其他数据库操作错误。他们更新的查询使用否定正则表达式来查找数据库语句不存在或不以 `INSERT` 子句开头的任何 Span。这应该会暴露导致内部服务器错误的其他问题,并过滤掉他们已经诊断出的问题类型。

traceql
{ resource.service.name = "mythical-requester" && span.http.status_code = 500 } >> { status = error && span.db.statement !~ "INSERT.*" }

此查询没有结果,表明运营团队看到的问题的根源完全是由于失败的数据库 `INSERT` 语句。此时,他们可以回滚到已知的工作版本,或者部署一个修复程序以确保服务正确拒绝 `null` 数据。完成后,团队将问题标记为已解决。Handy 团队的错误率 SLI 应该会恢复到可接受的水平。

Empty query results