HTTPX
See every HTTP request your app makes with HTTPX or HTTPX2: 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 the synchronous Client and asynchronous AsyncClient from either library. If both
libraries are installed, one call to logfire.instrument_httpx() instruments both when
opentelemetry-instrumentation-httpx is version 0.65b0 or newer. With an earlier version, Logfire
instruments HTTPX and warns that it skipped HTTPX2.
- 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]'
The extra installs the OpenTelemetry integration that collects request data. It does not install
httpx or httpx2; keep the client library you use as an application dependency.
HTTPX2 support requires opentelemetry-instrumentation-httpx 0.65b0 or newer. A fresh installation
normally selects a compatible version. If an existing environment keeps an older version, use the
upgrade command in Troubleshooting.
Add two lines to your app: logfire.configure() to connect to your project, and
logfire.instrument_httpx() to record every request. With no
client argument, Logfire instruments both libraries when they are installed. Pass a client instance
to instrument only that client.
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 httpx2
import logfire
logfire.configure()
url = 'https://httpbin.org/get'
with httpx2.Client() as client:
logfire.instrument_httpx(client)
client.get(url)
async def main():
async with httpx2.AsyncClient() as client:
logfire.instrument_httpx(client)
await client.get(url)
asyncio.run(main())
Run it with python main.py.
You can also pass one httpx.Client or httpx.AsyncClient; the Logfire call stays the same.
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 both installed libraries; if you pass a specific client, make sure it’s the one making the request. -
HTTPX2 reports that it needs newer OpenTelemetry instrumentation. Upgrade Logfire and the HTTPX integration together so their OpenTelemetry dependencies remain compatible:
Terminal pip install -U 'logfire[httpx]' 'opentelemetry-instrumentation-httpx>=0.65b0' -
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. The same capture settings and hooks apply to HTTPX and HTTPX2. The
examples below use HTTPX.
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