@@ -673,6 +673,101 @@ def test_is_json_type():
673673 assert not is_json_type ('application//json' )
674674
675675
676+ async def test_httpx_client_capture_all (exporter : TestExporter ):
677+ with check_traceparent_header () as checker :
678+ async with httpx .AsyncClient (transport = create_transport ()) as client :
679+ logfire .instrument_httpx (client , capture_all = True )
680+ response = await client .post ('https://example.org/' , json = {'hello' : 'world' })
681+ checker (response )
682+ assert response .json () == {'good' : 'response' }
683+ assert await response .aread () == b'{"good": "response"}'
684+
685+ assert exporter .exported_spans_as_dict () == snapshot (
686+ [
687+ {
688+ 'name' : 'POST' ,
689+ 'context' : {'trace_id' : 1 , 'span_id' : 3 , 'is_remote' : False },
690+ 'parent' : {'trace_id' : 1 , 'span_id' : 1 , 'is_remote' : False },
691+ 'start_time' : 2000000000 ,
692+ 'end_time' : 3000000000 ,
693+ 'attributes' : {
694+ 'http.method' : 'POST' ,
695+ 'http.request.method' : 'POST' ,
696+ 'http.url' : 'https://example.org/' ,
697+ 'url.full' : 'https://example.org/' ,
698+ 'http.host' : 'example.org' ,
699+ 'server.address' : 'example.org' ,
700+ 'network.peer.address' : 'example.org' ,
701+ 'logfire.span_type' : 'span' ,
702+ 'logfire.msg' : 'POST /' ,
703+ 'http.request.header.host' : ('example.org' ,),
704+ 'http.request.header.accept' : ('*/*' ,),
705+ 'http.request.header.accept-encoding' : ('gzip, deflate' ,),
706+ 'http.request.header.connection' : ('keep-alive' ,),
707+ 'http.request.header.user-agent' : ('python-httpx/0.28.1' ,),
708+ 'http.request.header.content-length' : ('17' ,),
709+ 'http.request.header.content-type' : ('application/json' ,),
710+ 'logfire.json_schema' : '{"type":"object","properties":{"http.request.body.text":{"type":"object"}}}' ,
711+ 'http.request.body.text' : '{"hello":"world"}' ,
712+ 'http.status_code' : 200 ,
713+ 'http.response.status_code' : 200 ,
714+ 'http.flavor' : '1.1' ,
715+ 'network.protocol.version' : '1.1' ,
716+ 'http.response.header.host' : ('example.org' ,),
717+ 'http.response.header.accept' : ('*/*' ,),
718+ 'http.response.header.accept-encoding' : ('gzip, deflate' ,),
719+ 'http.response.header.connection' : ('keep-alive' ,),
720+ 'http.response.header.user-agent' : ('python-httpx/0.28.1' ,),
721+ 'http.response.header.content-length' : ('17' ,),
722+ 'http.response.header.content-type' : ('application/json' ,),
723+ 'http.response.header.traceparent' : ('00-00000000000000000000000000000001-0000000000000003-01' ,),
724+ 'http.target' : '/' ,
725+ },
726+ },
727+ {
728+ 'name' : 'Reading response body' ,
729+ 'context' : {'trace_id' : 1 , 'span_id' : 5 , 'is_remote' : False },
730+ 'parent' : {'trace_id' : 1 , 'span_id' : 3 , 'is_remote' : False },
731+ 'start_time' : 4000000000 ,
732+ 'end_time' : 5000000000 ,
733+ 'attributes' : {
734+ 'code.filepath' : 'test_httpx.py' ,
735+ 'code.function' : 'test_httpx_client_capture_all' ,
736+ 'code.lineno' : 123 ,
737+ 'logfire.msg_template' : 'Reading response body' ,
738+ 'logfire.msg' : 'Reading response body' ,
739+ 'logfire.span_type' : 'span' ,
740+ 'http.response.body.text' : '{"good": "response"}' ,
741+ 'logfire.json_schema' : '{"type":"object","properties":{"http.response.body.text":{}}}' ,
742+ },
743+ },
744+ {
745+ 'name' : 'test span' ,
746+ 'context' : {'trace_id' : 1 , 'span_id' : 1 , 'is_remote' : False },
747+ 'parent' : None ,
748+ 'start_time' : 1000000000 ,
749+ 'end_time' : 6000000000 ,
750+ 'attributes' : {
751+ 'code.filepath' : 'test_httpx.py' ,
752+ 'code.function' : 'check_traceparent_header' ,
753+ 'code.lineno' : 123 ,
754+ 'logfire.msg_template' : 'test span' ,
755+ 'logfire.msg' : 'test span' ,
756+ 'logfire.span_type' : 'span' ,
757+ },
758+ },
759+ ]
760+ )
761+
762+
763+ def test_httpx_capture_all_and_other_flags_should_warn (exporter : TestExporter ):
764+ with httpx .Client (transport = create_transport ()) as client :
765+ with pytest .warns (
766+ UserWarning , match = 'You should use either `capture_all` or the specific capture parameters, not both.'
767+ ):
768+ logfire .instrument_httpx (client , capture_all = True , capture_request_body = True )
769+
770+
676771def test_missing_opentelemetry_dependency () -> None :
677772 with mock .patch .dict ('sys.modules' , {'opentelemetry.instrumentation.httpx' : None }):
678773 with pytest .raises (RuntimeError ) as exc_info :
0 commit comments