Skip to content

Use HTTP error bodies in HttpExporter warnings#8428

Merged
jack-berg merged 5 commits into
open-telemetry:mainfrom
ADITYA-CODE-SOURCE:issue-7704-http-exporter-warning
Jul 16, 2026
Merged

Use HTTP error bodies in HttpExporter warnings#8428
jack-berg merged 5 commits into
open-telemetry:mainfrom
ADITYA-CODE-SOURCE:issue-7704-http-exporter-warning

Conversation

@ADITYA-CODE-SOURCE

@ADITYA-CODE-SOURCE ADITYA-CODE-SOURCE commented May 27, 2026

Copy link
Copy Markdown
Contributor

Refs #7704.

Why

  • HttpExporter currently tries to parse every non-success HTTP response body as a serialized gRPC status.
  • When a custom server returns a JSON error body instead, export failure is reported correctly, but the warning text degrades to Unable to parse response body, which is noisy and hides the actual server response.

What

  • keep gRPC status parsing for responses that contain a serialized gRPC status body
  • fall back to logging the UTF-8 response body text when parsing fails
  • fall back to the HTTP status message when the body is empty
  • add a targeted test covering a JSON error response body

Testing

  • ./gradlew :exporters:otlp:all:test --tests "*HttpExporterTest"
  • ./gradlew :exporters:common:spotlessCheck :exporters:otlp:all:spotlessCheck
  • ./gradlew jApiCmp

@ADITYA-CODE-SOURCE ADITYA-CODE-SOURCE requested a review from a team as a code owner May 27, 2026 14:17

@psx95 psx95 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QQ: Why was this number chosen?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: could add a better message indicating this is a length = 0 case.

Something like "Response body has 0 length, HTTP status message: "

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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();

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in the latest version: decoding is now bounded to the configured max length before converting to UTF-8.

@ADITYA-CODE-SOURCE ADITYA-CODE-SOURCE force-pushed the issue-7704-http-exporter-warning branch from a12e8d8 to fff6013 Compare May 29, 2026 16:51
@ADITYA-CODE-SOURCE

ADITYA-CODE-SOURCE commented May 29, 2026

Copy link
Copy Markdown
Contributor Author

@psx95 Addressed the nits — bounded decoding, zero-length message, 1024 comment, and rebased onto latest main. I relied on CI for post-rebase verification since Gradle won't start locally due to paging-file limits.

@codecov

codecov Bot commented Jun 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.63%. Comparing base (6f6e146) to head (ebde5c4).

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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@linux-foundation-easycla

linux-foundation-easycla Bot commented Jul 11, 2026

Copy link
Copy Markdown

CLA Signed
The committers listed above are authorized under a signed CLA.

@ADITYA-CODE-SOURCE

Copy link
Copy Markdown
Contributor Author

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.

@opentelemetry-pr-dashboard

Copy link
Copy Markdown

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
@opentelemetry-pr-dashboard

Copy link
Copy Markdown

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.

@ADITYA-CODE-SOURCE ADITYA-CODE-SOURCE force-pushed the issue-7704-http-exporter-warning branch from 14c22f0 to be4b328 Compare July 11, 2026 12:10
@psx95

psx95 commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

@ADITYA-CODE-SOURCE could you fix the failing CI on this PR to ensure that the new changes are good?

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.

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.

@ADITYA-CODE-SOURCE ADITYA-CODE-SOURCE force-pushed the issue-7704-http-exporter-warning branch from be4b328 to a4f6c96 Compare July 14, 2026 13:06
@otelbot otelbot Bot added the api-change Changes to public API surface area label Jul 14, 2026
@ADITYA-CODE-SOURCE

Copy link
Copy Markdown
Contributor Author

@psx95 I pushed a follow-up for the failing CI and updated the PR description scope.

  • rebased branch now includes the missing tracked docs/apidiffs/current_vs_latest/*.txt refresh from ./gradlew jApiCmp
  • local verification completed with:
    • ./gradlew :exporters:otlp:all:test --tests "*HttpExporterTest"
    • ./gradlew :exporters:common:spotlessCheck :exporters:otlp:all:spotlessCheck
    • ./gradlew jApiCmp
  • the PR description now uses Refs #7704 instead of Fixes #7704, since this change improves the warning text but does not suppress the warning itself

Could you please take another look when you have a chance?

@psx95

psx95 commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Hi @ADITYA-CODE-SOURCE,

I think you need another rebase onto (latest) main - the contents of the files in current_vs_latest directory have been updated upstream, this PR should not be making changes to current_vs_latest directory since there are no API changes.

This should also trigger the CI checks (they are probably not triggered right now because of the merge conflicts).

@ADITYA-CODE-SOURCE ADITYA-CODE-SOURCE force-pushed the issue-7704-http-exporter-warning branch from a4f6c96 to ebde5c4 Compare July 15, 2026 03:52
@ADITYA-CODE-SOURCE

Copy link
Copy Markdown
Contributor Author

@psx95 I rebased this branch onto the latest main again and dropped the stale apidiff churn during the rebase. The branch is now back to the intended HttpExporter warning-body change only.

Local verification after the rebase:

  • ./gradlew :exporters:otlp:all:test --tests "*HttpExporterTest"
  • ./gradlew :exporters:common:spotlessCheck :exporters:otlp:all:spotlessCheck
  • ./gradlew jApiCmp

The PR description still uses Refs #7704.

Could you please take another look when you have a chance?

@otelbot otelbot Bot removed the api-change Changes to public API surface area label Jul 15, 2026

@psx95 psx95 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@jack-berg

Copy link
Copy Markdown
Member

HttpExporter currently tries to parse every non-success HTTP response body as a serialized gRPC status.

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

@ADITYA-CODE-SOURCE

Copy link
Copy Markdown
Contributor Author

HttpExporter currently tries to parse every non-success HTTP response body as a serialized gRPC status.

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 Export{Signal}ServiceResponse parsing behavior for follow-up work like #4706.

@jack-berg jack-berg merged commit ee9b063 into open-telemetry:main Jul 16, 2026
29 checks passed
@otelbot

otelbot Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants