Recording errors

状态开发中

本文档为语义约定和仪器作者提供了关于如何在 Span 和指标上记录错误的建议。

鼓励单独的语义约定提供其他指导。

什么构成错误

如果以下任何一项成立,则操作应被视为失败:

  • 被仪器化的方法(API、代码块或其他被仪器化的单元)抛出异常

  • 被仪器化的方法以其他方式返回错误,例如通过错误代码

    定义领域特定状态码的语义约定应指定哪些状态码应被通用仪器报告为错误。

注意

将状态码分类为错误取决于上下文。例如,HTTP 404“Not Found”状态码如果应用程序期望该资源可用,则表示错误。但是,当应用程序只是检查资源是否存在时,它就不是错误。

对于特定请求有额外上下文的仪器可能会使用此上下文更精确地设置 Span 状态。

已重试或已处理的错误(允许操作顺利完成)不应记录在描述此操作的 Span 或指标上。

在 Span 上记录错误

如果被仪器化的操作在没有任何错误的情况下结束,则 Span 状态码必须保持未设置。

当操作以错误结束时,仪器

  • 应将 Span 状态码设置为 Error

  • 应设置 error.type 属性

  • 当有关于错误的额外信息时,应设置 Span 状态描述,这些信息不应包含敏感细节,并且符合 Span Status Description 的定义。

    不建议在 Span 状态描述中复制状态码或 error.type

    当操作因异常失败时,Span 状态描述应设置为异常消息。

有关捕获异常详细信息,请参阅 记录异常

在指标上记录错误

操作的语义约定通常定义操作持续时间直方图指标。此指标应包含 error.type 属性。这使用户能够得出吞吐量和错误率。

成功完成的操作不应包含 error.type 属性,允许用户过滤掉错误。

语义约定应在适用时在其他指标上包含 error.type。例如,messaging.client.sent.messages 指标衡量消息吞吐量(一次消息传递操作可能涉及发送多条消息)并包含 error.type

建议报告一个包含成功和失败的指标,而不是报告两个(或更多)指标,具体取决于操作状态。

当同时报告 Span 和指标时,仪器应确保 error.type 在两者之间一致应用。对于单个操作的 Span 及其对应的指标,如果操作失败,应具有相同的 error.type 值;如果操作成功,则不应包含它。

记录异常

当被仪器化的操作因异常失败时,仪器应将此异常记录为 Span 事件日志记录

建议使用 Span.recordException API 或接受异常实例的日志记录库 API,而不是提供单独的属性。这使得 OpenTelemetry SDK 能够根据应用程序配置控制记录哪些信息。

不建议多次记录相同的异常。不建议记录已被仪器化库处理的异常。

例如,在此代码片段中,ResourceAlreadyExistsException 已被处理,相应的本地仪器不应记录它。应一次记录(或日志记录)传播给调用者的异常。

public boolean createIfNotExists(String resourceId) throws IOException {
  Span span = startSpan();
  try {
    create(resourceId);
    return true;
  } catch (ResourceAlreadyExistsException e) {
    // not recording exception and not setting span status to error - exception is handled
    // but we can set attributes that capture additional details
    span.setAttribute(AttributeKey.stringKey("acme.resource.create.status"), "already_exists");
    return false;
  } catch (IOException e) {
    // recording exception here (assuming it was not recorded inside `create` method)
    span.recordException(e);
    // or
    // logger.warn(e);

    span.setAttribute(AttributeKey.stringKey("error.type"), e.getClass().getCanonicalName())
    span.setStatus(StatusCode.ERROR, e.getMessage());
    throw e;
  }
}