Skip to content

Commit a950e2d

Browse files
committed
Handle OpenTelemetry propagation failures
1 parent 20845c2 commit a950e2d

2 files changed

Lines changed: 33 additions & 1 deletion

File tree

src/httpx2/httpx2/_opentelemetry.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,13 @@ def start_request(self, request: Request) -> RequestTrace:
140140
span_context_manager=span_cm,
141141
start=time.perf_counter(),
142142
)
143-
self._propagate.inject(request.headers)
143+
try:
144+
self._propagate.inject(request.headers)
145+
except BaseException as exc:
146+
trace.set_exception(exc)
147+
trace.detach_current(type(exc), exc, exc.__traceback__)
148+
trace.close()
149+
raise
144150
return trace
145151

146152

tests/httpx2/test_opentelemetry.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,32 @@ def handler(request: httpx2.Request) -> httpx2.Response:
155155
assert _duration_metric(capfire)["data"]["data_points"][0]["attributes"]["error.type"] == "httpx2.ConnectError"
156156

157157

158+
def test_opentelemetry_records_propagation_injection_exceptions(
159+
capfire: CaptureLogfire,
160+
monkeypatch: pytest.MonkeyPatch,
161+
) -> None:
162+
otel = otel_module.get_opentelemetry()
163+
assert otel is not None
164+
165+
def inject(headers: httpx2.Headers) -> None:
166+
raise RuntimeError("inject failed")
167+
168+
def handler(request: httpx2.Request) -> httpx2.Response:
169+
pytest.fail("transport should not be called") # pragma: no cover
170+
171+
monkeypatch.setattr(otel._propagate, "inject", inject)
172+
173+
transport = httpx2.MockTransport(handler)
174+
with httpx2.Client(transport=transport) as client:
175+
with pytest.raises(RuntimeError, match="inject failed"):
176+
client.get("https://example.com/")
177+
178+
[span] = _httpx2_spans(capfire)
179+
assert span.attributes["error.type"] == "builtins.RuntimeError"
180+
assert span.status.status_code is StatusCode.ERROR
181+
assert _duration_metric(capfire)["data"]["data_points"][0]["attributes"]["error.type"] == "builtins.RuntimeError"
182+
183+
158184
def test_opentelemetry_records_sync_body_read_exceptions(capfire: CaptureLogfire) -> None:
159185
def handler(request: httpx2.Request) -> httpx2.Response:
160186
return httpx2.Response(200, stream=FailingSyncStream())

0 commit comments

Comments
 (0)