feat(opentelemetry-core,sdk-trace-base,sdk-logs): append exception.cause chain to ATTR_EXCEPTION_STACKTRACE#6634
Conversation
…use chain to ATTR_EXCEPTION_STACKTRACE
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| export function buildExceptionCauseChain(cause: unknown): string { |
There was a problem hiding this comment.
IIUC if we could pass the top error here. The only issue would be that the 1st stack will start with the string \nCaused by: producing something like
'\nCaused by: Error: top\n at top:1:1\nCaused by: Error: mid\n at mid:1:1\nCaused by: Error: root\n at root:1:1'
with a couple of changes this function could get the top error and return the whole chain.
I wonder if there is a case where we want to have only the cause chain 🤔
There was a problem hiding this comment.
Agreed, if this function takes an arbitrary error object directly, the call sites do not have to cast like (exceptionObj as { cause?: unknown }).cause either, which could be cleaner.
|
@abhisheksurve45 thanks for your contribution. I left a comment about the scope of the new function. Maybe other @open-telemetry/javascript-approvers want to give their view. In the meantime you may want to |
| let current = cause; | ||
| while (current && typeof current === 'object' && !visited.has(current)) { | ||
| visited.add(current); | ||
| const c = current as { stack?: string; cause?: unknown }; |
There was a problem hiding this comment.
It would be better to declare a named interface for this, like
interface ExceptionWithCause {
name?: string;
message?: string;
stack?: string;
cause?: unknown;
}The cause property could be added to api/src/common/Exception.ts as a follow-up, but this PR does not have to be blocked on it.
Which problem is this PR solving?
JavaScript's
Errorobject supports acauseoption since Node.js 16.9+, allowing errors to be chained (e.g.,new Error('outer', { cause: innerError })). Previously, OTel JS only captured the top-levelerror.stackinATTR_EXCEPTION_STACKTRACE, silently dropping all nested cause stacks.This PR appends the full cause chain to
ATTR_EXCEPTION_STACKTRACEin the format\nCaused by: <stack>, recursively walking the chain. This aligns with how OTel Java already handles cause chains viaThrowable.printStackTrace.Fixes #6423
Short description of the changes
buildExceptionCauseChain()utility in@opentelemetry/corethat walks thecausechain of an exception, appending each level's stack as\nCaused by: <stack>. Handles circular references via aSet.Span.recordException()insdk-trace-baseto use the utility.LogRecordImpl._setException()insdk-logsto use the utility.Type of change
How Has This Been Tested?
Unit tests added for all three packages:
packages/opentelemetry-core/test/common/exception.test.ts— tests for the shared utility covering: single cause, cause with no stack, multi-level chain, circular reference, and primitive/null cause.packages/opentelemetry-sdk-trace-base/test/common/Span.test.ts— tests for single and multi-level cause chain inrecordException().experimental/packages/sdk-logs/test/common/LogRecord.test.ts— tests for single and multi-level cause chain in_setException().Checklist: