Use HTTP error bodies in HttpExporter warnings#8428
Conversation
psx95
left a comment
There was a problem hiding this comment.
This PR improves the default parsing experience of gRPC errors in HttpExporters by converting the raw bytes to a UTF-8 string as a fallback.
Looking at the original issue #7704 - the original ask was for a way to suppress the noisy logs - this PR makes the logs helpful, but does not suppress it - which IMO is ok (IIUC, a decision was not taken on it), but I'll defer to the maintainers here.
| @@ -32,6 +34,7 @@ | |||
| */ | |||
| @SuppressWarnings("checkstyle:JavadocMethod") | |||
| public final class HttpExporter { | |||
| private static final int MAX_RESPONSE_BODY_LOG_LENGTH = 1024; | |||
There was a problem hiding this comment.
QQ: Why was this number chosen?
There was a problem hiding this comment.
Chose 1024 as a conservative cap so failed exports can still show the server response without letting a large payload flood the warning log. Happy to adjust the bound if you would prefer a different limit.
| return "Response body missing, HTTP status message: " + statusMessage; | ||
| } | ||
| if (responseBody.length == 0) { | ||
| return "HTTP status message: " + statusMessage; |
There was a problem hiding this comment.
nit: could add a better message indicating this is a length = 0 case.
Something like "Response body has 0 length, HTTP status message: "
There was a problem hiding this comment.
Addressed in the latest version: zero-length bodies now produce a specific message instead of the generic fallback.
| } | ||
|
|
||
| private static String extractResponseBodyMessage(byte[] responseBody, String statusMessage) { | ||
| String responseBodyText = new String(responseBody, StandardCharsets.UTF_8).trim(); |
There was a problem hiding this comment.
nit: Minor improvement:
int lengthToRead = Math.min(responseBody.length, MAX_RESPONSE_BODY_LOG_LENGTH);
String responseBodyText = new String(responseBody, 0, lengthToRead, StandardCharsets.UTF_8).trim();
There was a problem hiding this comment.
Addressed in the latest version: decoding is now bounded to the configured max length before converting to UTF-8.
a12e8d8 to
fff6013
Compare
|
@psx95 Addressed the nits — bounded decoding, zero-length message, 1024 comment, and rebased onto latest |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #8428 +/- ##
============================================
+ Coverage 91.62% 91.63% +0.01%
- Complexity 10321 10326 +5
============================================
Files 1013 1013
Lines 27287 27295 +8
Branches 3203 3205 +2
============================================
+ Hits 25001 25012 +11
+ Misses 1559 1558 -1
+ Partials 727 725 -2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Quick clarification on scope: this PR does not suppress the warning itself. It keeps the existing warning behavior, but makes the warning actionable for non-gRPC HTTP error responses by surfacing the returned body text when gRPC status parsing fails. For empty or missing bodies it still falls back to the HTTP status message.\n\nI also pushed a small cleanup commit to reuse for the null-body test case raised in review. |
|
This PR has review comments. Review suggestions, whether from maintainers or automated reviewers, aren't always correct or required. Please evaluate each comment on its merits, then make sure each thread has a clear outcome. For example, link to the commit if you applied a suggestion, explain why it wasn't applied, or ask a follow-up question. Automation flags a PR for human review once every review thread has a reply or is marked as resolved. Status across open PRs is visible on the pull request dashboard. |
1 similar comment
|
This PR has review comments. Review suggestions, whether from maintainers or automated reviewers, aren't always correct or required. Please evaluate each comment on its merits, then make sure each thread has a clear outcome. For example, link to the commit if you applied a suggestion, explain why it wasn't applied, or ask a follow-up question. Automation flags a PR for human review once every review thread has a reply or is marked as resolved. Status across open PRs is visible on the pull request dashboard. |
14c22f0 to
be4b328
Compare
|
@ADITYA-CODE-SOURCE could you fix the failing CI on this PR to ensure that the new changes are good?
Also, could you update the description to remove "Fixes" from before the issue reference - otherwise merging this would close the issue and this comment clearly indicates that the PR does not address the mentioned issue. |
be4b328 to
a4f6c96
Compare
|
@psx95 I pushed a follow-up for the failing CI and updated the PR description scope.
Could you please take another look when you have a chance? |
|
I think you need another rebase onto (latest) main - the contents of the files in This should also trigger the CI checks (they are probably not triggered right now because of the merge conflicts). |
a4f6c96 to
ebde5c4
Compare
|
@psx95 I rebased this branch onto the latest Local verification after the rebase:
The PR description still uses Could you please take another look when you have a chance? |
psx95
left a comment
There was a problem hiding this comment.
Thanks for working through the review!
| @SuppressWarnings("checkstyle:JavadocMethod") | ||
| public final class HttpExporter { | ||
| // Limit logged response body text to avoid flooding warnings with large payloads. | ||
| private static final int MAX_RESPONSE_BODY_LOG_LENGTH = 1024; |
There was a problem hiding this comment.
The response body length is already limited elsewhere. 4mb by default. So code can't make it to this point with unbounded response bodies.
I think its arguably still good to truncate it so the log isn't overwhelming, but its not for safety
This is the problem. For otlp http/protobuf (i.e. the primary use case of HttpExporter), the server isn't expected to return a grpc status message as the body. Rather, its expected to return a protobuf binary encoded "Export{Signal}ServiceResponse" like ExportMetricsServiceResponse I'm not exactly sure why the code in HttpExporter tries to call the GrpcExporterUtil.getStatusMessage function. Looking at the git history, it seems to have originated from a split out of GrpcSender (former name of GrpcExporter). Ironically, GrpcExporter doesn't even try to parse anything to grpc status message! What we really need to do is parse the response bytes of both http and grpc responses to the "Export{Signal}ServiceResponse" types and write encoded versions of those out to the log message. I.e. #4706 I think trying to read the response body as a utf-8 string is a reasonable fallback for when this parsing fails, but I don't have sympathy for servers that are sending JSON payloads back because they are not following the OTLP spec. I'm inclined to accept this PR since although it doesn't solve the crux of the issue, I think it still serves as useful fallback even once the crux is solved. cc @jkwatson |
That makes sense. I agree the truncation here is mainly to keep the warning log from being overwhelming, not for response-size safety. And I agree this PR is only an incremental fallback improvement, not the full protocol-correct solution for OTLP HTTP/protobuf responses. I’m happy to treat the richer UTF-8 fallback as a narrow improvement here and leave the proper |
|
Thank you for your contribution @ADITYA-CODE-SOURCE! 🎉 We would like to hear from you about your experience contributing to OpenTelemetry by taking a few minutes to fill out this survey. |
Refs #7704.
Why
HttpExportercurrently tries to parse every non-success HTTP response body as a serialized gRPC status.Unable to parse response body, which is noisy and hides the actual server response.What
Testing
./gradlew :exporters:otlp:all:test --tests "*HttpExporterTest"./gradlew :exporters:common:spotlessCheck :exporters:otlp:all:spotlessCheck./gradlew jApiCmp