Skip to content

fix(exporter/otlp/http): log error details from response on export failure#5155

Open
grvmishra788 wants to merge 9 commits intoopen-telemetry:mainfrom
grvmishra788:worktree-issue-4526
Open

fix(exporter/otlp/http): log error details from response on export failure#5155
grvmishra788 wants to merge 9 commits intoopen-telemetry:mainfrom
grvmishra788:worktree-issue-4526

Conversation

@grvmishra788
Copy link
Copy Markdown

@grvmishra788 grvmishra788 commented Apr 27, 2026

Description

Fixes #4526.

Before: When an OTLP HTTP export fails (non-2xx response), all three exporters (trace, metrics, logs) log only resp.reason — the HTTP reason phrase (e.g. "Bad Request"). The response body is never read, so server-provided error details (e.g. a protobuf-encoded error from telemetry.googleapis.com) are silently discarded.

After: On a non-2xx response, exporters parse the body using the Content-Type header before logging:

Content-Type Behaviour
application/x-protobuf Deserialise as google.rpc.Status; extract message field
application/json Parse JSON; extract partialSuccess.errorMessage or message (google.rpc.Status)
Unknown or missing Return resp.text.strip()
Empty body or parse failure Return resp.reason (previous behaviour, unchanged)

Type of change

  • Bug fix (non-breaking change which fixes an issue)

How Has This Been Tested?

The fix was verified end-to-end by constructing a 400 response with a protobuf-encoded ExportTraceServiceResponse body (containing partial_success.error_message = "Request contains too many spans (limit: 10000)") and a mocked OTLP endpoint (via the responses library). Before the fix, the logged reason was "Bad Request"; after, it is the server-provided message. The same was confirmed for a JSON google.rpc.Status body and for an empty body (fallback to resp.reason, no regression).

Run from the repo root:

pytest exporter/opentelemetry-exporter-otlp-proto-http/tests/test_response_body_parsing.py \
       exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_span_exporter.py \
       exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py
  • 11 unit tests in test_response_body_parsing.py — cover every branch of _parse_response_body: protobuf with/without error message, JSON partialSuccess and message fields, ; charset=utf-8 content-type variants, unknown content-type, empty body, malformed protobuf, malformed JSON.
  • 3 integration tests in test_proto_span_exporter.py and test_proto_log_exporter.py — verify the parsed message appears in the error log on a real export call.
  • All 41 tests pass; pylint 10.00/10.

Does This PR Require a Contrib Repo Change?

  • No.

Checklist:

  • Followed the style guidelines of this project
  • Changelogs have been updated
  • Unit tests have been added
  • Documentation has been updated

Comment thread exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py Outdated
@grvmishra788 grvmishra788 marked this pull request as ready for review April 29, 2026 19:53
@grvmishra788 grvmishra788 requested a review from a team as a code owner April 29, 2026 19:53
@github-project-automation github-project-automation Bot moved this to Reviewed PRs that need fixes in Python PR digest Apr 29, 2026
Copy link
Copy Markdown

@amir-h-rassafi amir-h-rassafi left a comment

Choose a reason for hiding this comment

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

LGTM

return resp.reason

content_type = (
resp.headers.get("Content-Type", "").split(";", 1)[0].strip().lower()
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.

why do we split on semi-colon, shouldn't we do it on comma ? https://requests.readthedocs.io/en/latest/user/quickstart/#response-headers -- mentions comma

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The semicolon split is intentional here. Per https://www.rfc-editor.org/rfc/rfc9110#section-8.3.1, the Content-Type header uses semicolons to separate the media type from parameters like charset:

Content-Type: application/x-protobuf; charset=utf-8

I believe the comma behavior you linked is about how requests combines multiple values of the same header into a single string - that's a different concept. Since Content-Type only has one value with optional ;-delimited parameters, splitting on ; is correct to extract just the media type portion.

@grvmishra788
Copy link
Copy Markdown
Author

@DylanRussell One of the earlier CI checks failed tests / opentelemetry-sdk pypy-3.10 Windows - a completely different package (opentelemetry-sdk) that this PR doesn't touch. This appears to be a flaky infrastructure issue. Do you have any recommendations as to how I should handle this?

@grvmishra788
Copy link
Copy Markdown
Author

@DylanRussell One of the earlier CI checks failed tests / opentelemetry-sdk pypy-3.10 Windows - a completely different package (opentelemetry-sdk) that this PR doesn't touch. This appears to be a flaky infrastructure issue. Do you have any recommendations as to how I should handle this?

Now, a different check failed: test_weaver_live_check.py::TestSDKInitLiveCheck::test_end_no_violations in the opentelemetry-test-utils package (not otlp-proto-http).
This seems like a PyPy 3.10 + gRPC incompatibility on the CI runner: the weaver binary can't initialize its event loop properly under PyPy.
It has nothing to do with the OTLP HTTP exporter changes in this PR.

@MikeGoldsmith
Copy link
Copy Markdown
Member

@grvmishra788 I've merged main into your branch, hopefully we'll see a clean run this time.

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

Labels

None yet

Projects

Status: Reviewed PRs that need fixes

Development

Successfully merging this pull request may close these issues.

OTLP HTTP Exporter Should Parse response based on content-type header

4 participants