HTTPX
See every HTTP request your app makes with HTTPX: the URL, the response status, how long it took, and any errors, as a span (one unit of work with a name, a start, and a duration) in Logfire. Related spans link together into a trace (the full journey of one request), so a slow outgoing call shows up right next to the code that triggered it.
This works with both the synchronous httpx.Client and the asynchronous httpx.AsyncClient.
- Each request as a span, with its URL, method, response status, and duration
- Any errors that occurred during the request
- Optionally, request and response headers and bodies (off by default: see below)
You’ll need a Logfire project. Open Add data in your project (top navigation) and follow the
setup for your language: it signs your machine in with logfire auth (a browser sign-in, no token
to copy) and, for production or other languages, creates a write token (the credential your app
uses to send data). New to Logfire? Start with Getting Started.
Install logfire with the httpx extra:
pip install 'logfire[httpx]'
uv add 'logfire[httpx]'
Add two lines to your app: logfire.configure() to connect to your project, and
logfire.instrument_httpx() to record every request.
import asyncio
import httpx
import logfire
logfire.configure()
logfire.instrument_httpx()
url = 'https://httpbin.org/get'
with httpx.Client() as client:
client.get(url)
async def main():
async with httpx.AsyncClient() as client:
await client.get(url)
asyncio.run(main())
import asyncio
import httpx
import logfire
logfire.configure()
url = 'https://httpbin.org/get'
with httpx.Client() as client:
logfire.instrument_httpx(client)
client.get(url)
async def main():
async with httpx.AsyncClient() as client:
logfire.instrument_httpx(client)
await client.get(url)
asyncio.run(main())
Run it with python main.py.
Run your program, then open your project in the
Logfire web app and go to the Live view. Within a few seconds you
should see a span for the GET request. Click it to see the URL, response status, and how long it
took.
Not seeing your requests in Logfire? Check these first:
logfire.configure()runs beforelogfire.instrument_httpx(). Configure the connection first, then instrument.- You instrument the client you actually call.
instrument_httpx()with no argument covers all clients; if you pass a specific client, make sure it’s the one making the request. - Your write token is set. In local development, run
logfire projects use <your-project>; in production, set theLOGFIRE_TOKENenvironment variable. See Getting Started. - You actually made a request. Spans appear only after a request completes.
The logfire.instrument_httpx() method accepts several parameters
to control what’s captured.
Capture all request and response headers and bodies by setting capture_all=True. This sends that
data to Logfire, so avoid it if your requests carry secrets or personally identifiable information
(PII).
import httpx
import logfire
logfire.configure()
logfire.instrument_httpx(capture_all=True)
client = httpx.Client()
client.post('https://httpbin.org/post', json={'key': 'value'})
By default, Logfire doesn’t record HTTP headers. Turn them on with capture_headers=True:
import httpx
import logfire
logfire.configure()
logfire.instrument_httpx(capture_headers=True)
client = httpx.Client()
client.get('https://httpbin.org/get')
Instead of capturing both request and response headers, you can use a request hook to capture only the request headers:
import httpx
from opentelemetry.trace import Span
import logfire
from logfire.integrations.httpx import RequestInfo
def capture_request_headers(span: Span, request: RequestInfo):
headers = request.headers
span.set_attributes(
{f'http.request.header.{header_name}': headers.get_list(header_name) for header_name in headers.keys()}
)
logfire.configure()
logfire.instrument_httpx(request_hook=capture_request_headers)
client = httpx.Client()
client.get('https://httpbin.org/get')
Similarly, use a response hook to capture only the response headers:
import httpx
from opentelemetry.trace import Span
import logfire
from logfire.integrations.httpx import RequestInfo, ResponseInfo
def capture_response_headers(span: Span, request: RequestInfo, response: ResponseInfo):
headers = response.headers
span.set_attributes(
{f'http.response.header.{header_name}': headers.get_list(header_name) for header_name in headers.keys()}
)
logfire.configure()
logfire.instrument_httpx(response_hook=capture_response_headers)
client = httpx.Client()
client.get('https://httpbin.org/get')
Inside a hook you choose which headers to record on the span. If you also set capture_headers=True, though, Logfire records the headers before your hook runs, so a hook can’t redact those after the fact; use scrubbing for that.
By default, Logfire doesn’t record HTTP bodies. Turn them on with capture_request_body and
capture_response_body. As with headers, this sends the body data to Logfire, so avoid it for
requests that carry sensitive data.
import httpx
import logfire
logfire.configure()
logfire.instrument_httpx(
capture_request_body=True,
capture_response_body=True,
)
client = httpx.Client()
client.post('https://httpbin.org/post', data='Hello, World!')
- API reference:
logfire.instrument_httpx() - Underlying OpenTelemetry package: HTTPX instrumentation