feat(gax): differentiate between server side and client side errors - #9451
Conversation
There was a problem hiding this comment.
Code Review
This pull request enhances the observability and tracing capabilities of google-gax by implementing a robust 5-tier hierarchy for resolving the OpenTelemetry error.type attribute, extracting and reporting server.address and server.port from settings and environment variables, and improving exception event recording to include server-side status details and metadata. The review feedback is highly constructive, pointing out critical compatibility issues such as potential runtime crashes in browser environments due to direct Buffer references, and unnecessary parsing calls caused by truthy empty arrays returned from gRPC metadata lookups. Additionally, the feedback offers valuable performance optimizations by suggesting the migration of local arrays to module-level Set constants to prevent redundant allocations, and recommends validating environment-provided port numbers for robustness.
| const serverPort = env.GOOGLE_SDK_NODE_SERVER_PORT || env.SERVER_PORT; | ||
| if (serverPort && !isNaN(Number(serverPort))) { | ||
| result.serverPort = Number(serverPort); | ||
| } |
There was a problem hiding this comment.
If serverPort is an empty string or whitespace, parsing it directly might result in unexpected behavior or NaN. We should safely parse it to a number and validate that it is a valid port range (1-65535) before assigning it.
| const serverPort = env.GOOGLE_SDK_NODE_SERVER_PORT || env.SERVER_PORT; | |
| if (serverPort && !isNaN(Number(serverPort))) { | |
| result.serverPort = Number(serverPort); | |
| } | |
| const serverPort = env.GOOGLE_SDK_NODE_SERVER_PORT || env.SERVER_PORT; | |
| const parsedPort = serverPort ? Number(serverPort) : NaN; | |
| if (!isNaN(parsedPort) && parsedPort > 0 && parsedPort <= 65535) { | |
| result.serverPort = parsedPort; | |
| } |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request enhances OpenTelemetry tracing in google-gax by implementing a 5-tier error type resolution hierarchy and recording server-side error details (such as status details and metadata) within the exception stack trace. It also adds support for extracting and recording server.address and server.port attributes from settings and environment variables. Feedback on the changes highlights potential classification issues where plain error objects might be misidentified as pre-connection failures or client-side errors due to overly strict type checks. Additionally, a performance optimization was suggested to check the length of the returned gRPC metadata array to avoid redundant parsing of status details.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request implements a 5-tier error type resolution hierarchy for OpenTelemetry tracing in google-gax, aligning with semantic conventions. It introduces robust client-side and server-side error classification, extracts and records server address and port attributes, and captures detailed server-side exception metadata (such as status details and GFE metadata) within the exception stack trace. The feedback highlights opportunities to improve robustness in the telemetry path, specifically by wrapping JSON.stringify calls in try-catch blocks to prevent crashes from non-serializable properties, refactoring the recursive isPreConnectionFailure function into a loop to avoid stack overflows, and ensuring Buffer.isBuffer is a function before invocation in non-Node environments.
| function isBuffer(val: unknown): val is Buffer { | ||
| return typeof Buffer !== 'undefined' && Buffer.isBuffer(val); | ||
| } |
There was a problem hiding this comment.
In non-Node.js environments (such as browsers or custom runtimes), a global Buffer object might exist but may not implement the standard isBuffer method. To prevent a potential runtime TypeError, verify that Buffer.isBuffer is a function before calling it.
function isBuffer(val: unknown): val is Buffer {
return (
typeof Buffer !== 'undefined' &&
typeof Buffer.isBuffer === 'function' &&
Buffer.isBuffer(val)
);
}1ca783f to
2387b3d
Compare
| depth++; | ||
| } | ||
|
|
||
| return undefined; |
There was a problem hiding this comment.
nit: I think this is equivalent to just return.
…onventions - Set span.status.message for HTTP and gRPC failure paths - Implement 5-tier error.type resolution hierarchy unwrapping e.cause - Omit response status codes on client-side errors without server response - Conditionally set server.address and server.port, omitting on pre-connection failures - Record client stack traces on client errors and server error details in exception.stacktrace for server errors - Avoid recording metadata, status_details, domain, reason, or error_info_metadata as span/event attributes - Update harness and unit tests for all error scenarios
…util - Safely check typeof Buffer !== 'undefined' before accessing Buffer in TracerHelper - Move error codes, generic classes, and pre-connection codes from loops in TracerHelper to util.ts - Move ignoredClientHeaderTokens from loop in metadataResolver to util.ts - Add unit tests for Buffer handling and exported util constants
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
- Check resolveHttpStatusCode and resolveRpcStatusName before stack check in isPreConnectionFailure - Allow plain error objects carrying valid status codes in isServerSideError - Add unit tests verifying plain objects retain server address/port and resolve error.type
…cular errors in TracerHelper
2387b3d to
d2e2888
Compare
## [6.8.0](google-gax-v6.7.0...google-gax-v6.8.0) (2026-09-25) ### Features * **gax:** Differentiate between server side and client side errors ([#9451](#9451)) ([c477918](c477918))
Align error.type and span error attributes with OTel semantic conventions
Fixes: