opentelemetry 中应使用 recordexception() 方法记录自定义异常及异常链,它自动提取类型、消息、堆栈并遵循语义约定,递归处理 cause 和 suppressed 异常,主异常标记 exception.escaped = true,无需手动构造 event。

OpenTelemetry 中,将自定义异常和异常链记录到 Span 的 Event 中,核心是使用 recordException() 方法 —— 它会自动提取异常类型、消息、堆栈,并将完整异常链(包括 cause 和 suppressed exceptions)作为 Span Event 记录,同时设置标准语义约定属性。
使用 recordException() 正确记录异常
这是最推荐的方式,无需手动构造 Event。它内置遵循 OpenTelemetry 语义约定(OTel Exception Conventions),自动处理嵌套异常:
- 调用
span.recordException(throwable),传入任意Throwable(包括自定义异常) - 底层会递归遍历
getCause()和getSuppressed(),为每层异常生成带exception.type、exception.message、exception.stacktrace属性的 Event - 主异常标记为
exception.escaped = true(若发生在当前 Span 内且未被捕获),其他链式异常标记为false
确保自定义异常信息可被正确提取
自定义异常类无需特殊继承,但需保证 getMessage() 和 printStackTrace()(或 getStackTrace())能提供有意义内容:
- 避免在
getMessage()中返回空或泛化字符串(如 "Error occurred"),应包含关键上下文(如 "Failed to parse JSON for user ID=123") - 若重写了
fillInStackTrace()并禁用了堆栈(如某些高性能场景),recordException()将无法获取 stacktrace —— 建议仅在明确需要时关闭,否则保持默认行为 - 若异常携带业务字段(如 error code、request ID),可通过额外属性补充:
span.setAttribute("custom.error.code", myEx.getErrorCode());
手动添加 Event 的适用场景与注意事项
仅当需补充 recordException() 之外的上下文(如捕获前的日志、重试动作)时,才手动创建 Event:
- 不要用
addEvent("exception", attributes)替代recordException()—— 这会丢失语义、堆栈解析和链式展开能力 - 若必须手动记录,至少设置标准属性:
span.addEvent("exception", Attributes.builder()<br> .put("exception.type", ex.getClass().getName())<br> .put("exception.message", ex.getMessage())<br> .put("exception.stacktrace", Arrays.toString(ex.getStackTrace()))<br> .build());
⚠️ 注意:这不会自动处理 cause 链,需自行递归添加 - 更推荐的做法:先调用
recordException(),再用addEvent("retry_attempt", Attributes.of("attempt", 2))补充业务事件
验证是否生效
在 Jaeger / Zipkin / OTLP 后端查看 Span 时,应看到:
- Events 列表中出现一个或多个名为
exception的事件 - 每个事件含
exception.type(如com.example.MyValidationException)、exception.message、exception.stacktrace(完整堆栈文本) - 若存在 cause(如
MyValidationException包裹JsonParseException),会看到两个独立的exceptionEvent,后者带exception.escaped = false - Span 自身可能标记
status.code = ERROR(取决于 SDK 配置,默认通常开启)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











