Log HTTP requests made with Python Requests
Use urllib3 diagnostics or Requests response hooks, understand which failures and payloads they omit, and avoid exposing credentials in HTTP logs.
For temporary connection diagnostics, enable the urllib3 logger. For application logs, a Requests response hook gives you more control over the fields you retain. Neither method automatically produces a complete, safe record of every HTTP exchange.
Enable connection-level diagnostics
import logging
import requests
logging.basicConfig(level=logging.DEBUG)
logging.getLogger("urllib3").setLevel(logging.DEBUG)
response = requests.get("https://httpbin.org/get", timeout=10)
This can show connection activity and response summaries. It is not a complete request-and-response body recorder. The example makes a real external request; use an endpoint you control when testing application data.
For lower-level debugging, http.client can print additional protocol details directly to stdout:
from http.client import HTTPConnection
previous_debuglevel = HTTPConnection.debuglevel
try:
HTTPConnection.debuglevel = 1
response = requests.get("https://httpbin.org/get", timeout=10)
finally:
HTTPConnection.debuglevel = previous_debuglevel
This can expose outgoing headers and body bytes, status lines, and response headers. It does not generally dump response bodies. It bypasses logging handlers, so a logging filter will not redact that stdout output. Changing this class setting also affects other relevant connections in the process.
Record selected fields with a response hook
import logging
from urllib.parse import urlsplit
import requests
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("outbound_http")
def log_response(response, *args, **kwargs):
url = urlsplit(response.url)
logger.info(
"%s host=%s status=%s",
response.request.method,
url.hostname,
response.status_code,
)
with requests.Session() as session:
session.hooks["response"].append(log_response)
response = session.get("https://httpbin.org/get", timeout=10)
This deliberately omits credentials, query strings, URL paths, and bodies. If you need a path or more context, add an allowlisted, redacted field appropriate to your application's data.
Hooks run when a response is received, including intermediate redirect responses. They do not cover connection failures that never produce a response, and they do not provide one entry for every lower-level retry attempt. Catch requests.RequestException around the call when you also need a failure record. Avoid logging the full exception string without checking whether it contains a sensitive URL.
Choose diagnostic detail deliberately
Low-level debug output can contain tokens, cookies, or private payloads. Keep it scoped to a controlled reproduction and turn it off afterward. For sustained production visibility, use selected application fields and supported HTTP tracing instrumentation rather than retaining raw protocol dumps. Check instrumentation coverage and redaction for your client version.
FAQ
Can I log just the URL and status? Use a response hook, but sanitize the URL first. Query parameters and paths can contain secrets or personal data.
Can debuglevel output go to a file? Redirecting stdout captures it, but also captures other stdout output and does not route it through logging. A response hook is easier to format, filter, and send to a chosen handler.
Which logger does Requests use? Its connection diagnostics primarily come from urllib3. Setting a logger named requests to DEBUG does not by itself produce full exchange details.
References
Contact us
Join the community
to join the community
Try Guance
Start online and pay only for what you use.
Get startedChoose a Guance plan