You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fixes#22663 — HTTP-layer SERVER/CLIENT tracing spans remain status.code = 0 (UNSET) for 4xx/5xx REST responses, making it impossible for observability backends to detect failed requests from the root span.
Root cause
TraceableRestChannel.sendResponse() and TraceableStreamingRestChannel.prepareResponse() did not check the HTTP response status code before ending the span. The http.status_code attribute was never set, and the span status was never set to ERROR for failed requests.
Changes
Span.java — Added setError(String errorMessage) method to the interface for recording error status without requiring an Exception object.
NoopSpan.java — No-op implementation of the new setError(String) method.
OTelSpan.java — Implementation delegates to delegateSpan.setStatus(StatusCode.ERROR, errorMessage).
The PR description states the intent is to flag both 4xx and 5xx as errors, but the implementation only calls setError when statusCode >= 500. 4xx client errors (e.g., 400, 404, 500-independent failures) will still leave the span status as UNSET. Per OTel HTTP semantic conventions, SERVER spans should be ERROR for 5xx, but if the intent stated in the PR title/description ("4xx/5xx") is to cover 4xx as well, this branch is incorrect. Please align implementation with intent.
addAttribute and setError are executed before delegate.prepareResponse(...) inside the try-with-resources, but there is no finally block. If delegate.prepareResponse throws, the attribute/error is set but the span is not ended here (span ends in sendResponse/sendChunk elsewhere), which may be acceptable — however, note that in the non-streaming counterpart the attribute is set in finally, while here it is set before the delegate call. Consider moving these calls to after the delegate to keep symmetry, or into a try/finally, to avoid recording attributes for a response that failed to be prepared.
If response or response.status() is null, the finally block will throw an NPE, which will mask the original exception from delegate.sendResponse(response) and prevent span.endSpan() from being called. Guard the attribute/error recording with a null check to ensure the span is always ended.
Why: A valid defensive coding suggestion; an NPE in the finally block could mask original exceptions and prevent span.endSpan() from being called, though in practice response is unlikely to be null.
Low
General
Mark 4xx responses as errors too
The PR title mentions setting status for 4xx/5xx responses, but the code only sets error status for 5xx. Consider also marking 4xx client errors as errors, or at least align the implementation with the stated intent to avoid missing error tracking for client-side failures.
Why: This is a debatable design choice; OpenTelemetry semantic conventions typically only mark 5xx as errors on the server side, so the current 5xx-only behavior is reasonable. The PR title mentioning 4xx/5xx is a weak justification.
The reason will be displayed to describe this comment to others. Learn more.
Just a suggestion, introduce reportError method to TraceableRestChannel and reuse in TraceableStreamingRestChannel (instead of duplicating same code), since TraceableStreamingRestChannel extends TraceableRestChannel
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Fixes #22663 — HTTP-layer SERVER/CLIENT tracing spans remain
status.code = 0(UNSET) for 4xx/5xx REST responses, making it impossible for observability backends to detect failed requests from the root span.Root cause
TraceableRestChannel.sendResponse()andTraceableStreamingRestChannel.prepareResponse()did not check the HTTP response status code before ending the span. Thehttp.status_codeattribute was never set, and the span status was never set to ERROR for failed requests.Changes
Span.java— AddedsetError(String errorMessage)method to the interface for recording error status without requiring anExceptionobject.NoopSpan.java— No-op implementation of the newsetError(String)method.OTelSpan.java— Implementation delegates todelegateSpan.setStatus(StatusCode.ERROR, errorMessage).AttributeNames.java— AddedHTTP_STATUS_CODE = "http.status_code"constant.TraceableRestChannel.java— InsendResponse(), addshttp.status_codeattribute and callssetError("HTTP <code>")when status >= 500.TraceableStreamingRestChannel.java— InprepareResponse(), addshttp.status_codeattribute and callssetError("HTTP <code>")when status >= 500.Testing
http.status_codeattribute is set on every REST response spanstatus.code = ERROR(2) is set for HTTP 5xx responsessendResponse()inTraceableRestChannelprepareResponse()inTraceableStreamingRestChannelRelated