Capture outgoing HTTP requests and inspect them in a local web dashboard
Project description
Smello
Capture outgoing and incoming HTTP requests, Python logs, and unhandled exceptions in a local web dashboard.
Like Mailpit, but for your entire debug output.
Setup
Install the client SDK and the server:
pip install smello smello-server
Start the server:
smello-server
Add two lines to your code:
import smello
smello.init(server_url="http://localhost:5110")
import requests
resp = requests.get("https://api.stripe.com/v1/charges")
# Browse captured events at http://localhost:5110
Smello monkey-patches requests, httpx, aiohttp, grpc, and botocore to capture outgoing traffic. It also hooks into sys.excepthook to capture unhandled exceptions with full tracebacks, and optionally into Python's logging module to capture log records. For server-side capture, add the FastAPI middleware.
Or leave smello.init() without arguments and set SMELLO_URL in your environment. No URL, no side effects.
Run without modifying code
For programs you don't want to (or can't) edit, wrap them with smello run:
smello run my_app.py # .py files run with current Python
smello run --server http://localhost:5110 pytest tests/ # console scripts work directly
smello run uvicorn app:app
Smello activates in the wrapped process before user code runs. Subprocess instrumentation propagates automatically through PYTHONPATH, so wrapping gunicorn also captures traffic from worker processes.
CLI flags map 1:1 to the SMELLO_* env vars: --server, --capture-host, --ignore-host, --capture-all / --no-capture-all, --redact-header, --redact-query-param.
FastAPI middleware
To capture incoming requests, add the Smello middleware to your FastAPI app:
import smello
from smello.integrations.fastapi import SmelloMiddleware
from fastapi import FastAPI
smello.init()
app = FastAPI()
app.add_middleware(SmelloMiddleware, ignore_paths=["/health"])
The middleware captures method, path, status code, duration, route pattern, client IP, and request/response bodies. Unhandled exceptions are captured with full tracebacks. When Smello is inactive (no server URL configured), the middleware passes requests through without capturing anything.
Google Cloud libraries
Many Google Cloud Python libraries — BigQuery, Firestore, Pub/Sub, Analytics Data API (GA4), Vertex AI, Speech-to-Text, Vision, Translation, and others — use gRPC under the hood. Smello captures these calls automatically:
import smello
smello.init(server_url="http://localhost:5110")
from google.cloud import bigquery
client = bigquery.Client()
rows = client.query("SELECT 1").result()
# gRPC calls to bigquery.googleapis.com appear at http://localhost:5110
Any library that calls grpc.secure_channel() or grpc.insecure_channel() is automatically captured.
What Smello captures
Outgoing HTTP requests — method, URL, headers, body, response status/headers/body, duration, and library used (requests, httpx, aiohttp, grpc, or botocore).
Incoming HTTP requests (via FastAPI middleware) — method, path, route pattern, status code, duration, client IP, request/response headers and bodies, plus exception tracebacks if a handler raises.
Unhandled exceptions (enabled by default) — exception type, message, full traceback, and stack frames with source context.
Log records (opt-in via capture_logs=True) — level, logger name, message, source location, and extra attributes.
Smello redacts sensitive headers (Authorization, X-Api-Key) by default and optionally redacts query string parameters.
Configuration
smello.init(
server_url="http://localhost:5110", # where to send captured data
# HTTP capture
capture_hosts=["api.stripe.com"], # only capture these hosts
capture_all=True, # capture everything (default)
ignore_hosts=["localhost"], # skip these hosts
redact_headers=["Authorization"], # replace header values with [REDACTED]
redact_query_params=["api_key", "token"], # replace query param values with [REDACTED]
# Logs & exceptions
capture_exceptions=True, # capture unhandled exceptions (default)
capture_logs=False, # capture log records (opt-in)
log_level=30, # minimum log level to capture (WARNING)
ignore_loggers=["uvicorn.access"], # suppress noisy framework loggers
)
All parameters fall back to SMELLO_* environment variables when not passed explicitly:
| Parameter | Env variable | Default |
|---|---|---|
server_url |
SMELLO_URL |
None (inactive) |
capture_all |
SMELLO_CAPTURE_ALL |
True |
capture_hosts |
SMELLO_CAPTURE_HOSTS |
[] |
ignore_hosts |
SMELLO_IGNORE_HOSTS |
[] |
redact_headers |
SMELLO_REDACT_HEADERS |
["Authorization", "X-Api-Key"] |
redact_query_params |
SMELLO_REDACT_QUERY_PARAMS |
[] |
capture_exceptions |
SMELLO_CAPTURE_EXCEPTIONS |
True |
capture_logs |
SMELLO_CAPTURE_LOGS |
False |
log_level |
SMELLO_LOG_LEVEL |
30 (WARNING) |
ignore_loggers |
SMELLO_IGNORE_LOGGERS |
[] |
The server URL is the activation signal — init() does nothing unless server_url is passed or SMELLO_URL is set. Boolean env vars accept true/1/yes and false/0/no (case-insensitive). List env vars are comma-separated.
Supported libraries
- requests — patches
Session.send() - httpx — patches
Client.send()andAsyncClient.send() - aiohttp — patches
ClientSession._request()to capture async HTTP traffic - grpc — patches
insecure_channel()andsecure_channel()to intercept unary-unary calls - botocore — patches
URLLib3Session.send()to capture boto3 / AWS SDK traffic
Requires
- Python >= 3.10
- smello-server running locally
Links
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file smello-0.11.0.tar.gz.
File metadata
- Download URL: smello-0.11.0.tar.gz
- Upload date:
- Size: 43.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f420146de1b95acb86ae9624632358efca170ef7ee2b61699937a60e706e3699
|
|
| MD5 |
48fedb1de382300a1f060d36c3d9b11b
|
|
| BLAKE2b-256 |
3a2a34541a95edd52851ad6d4c0553136fc7380df12bbd167dab3ab774a71213
|
Provenance
The following attestation bundles were made for smello-0.11.0.tar.gz:
Publisher:
publish-client.yml on smelloscope/smello
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
smello-0.11.0.tar.gz -
Subject digest:
f420146de1b95acb86ae9624632358efca170ef7ee2b61699937a60e706e3699 - Sigstore transparency entry: 1602111829
- Sigstore integration time:
-
Permalink:
smelloscope/smello@d85ea7b03966475f858f4d20a7782db225da60ae -
Branch / Tag:
refs/tags/smello/v0.11.0 - Owner: https://github.com/smelloscope
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-client.yml@d85ea7b03966475f858f4d20a7782db225da60ae -
Trigger Event:
push
-
Statement type:
File details
Details for the file smello-0.11.0-py3-none-any.whl.
File metadata
- Download URL: smello-0.11.0-py3-none-any.whl
- Upload date:
- Size: 33.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
81a6a7c263aa88df22c1e8a84b9c679762a665692b601ca177f05fb7e3744d7e
|
|
| MD5 |
9898194f4068d81372f37a7a944697bb
|
|
| BLAKE2b-256 |
e7f17a14c9f073441b1f1a1d394e11f5b5f5dd44d4bc70ba709b844d5a0cbf62
|
Provenance
The following attestation bundles were made for smello-0.11.0-py3-none-any.whl:
Publisher:
publish-client.yml on smelloscope/smello
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
smello-0.11.0-py3-none-any.whl -
Subject digest:
81a6a7c263aa88df22c1e8a84b9c679762a665692b601ca177f05fb7e3744d7e - Sigstore transparency entry: 1602111836
- Sigstore integration time:
-
Permalink:
smelloscope/smello@d85ea7b03966475f858f4d20a7782db225da60ae -
Branch / Tag:
refs/tags/smello/v0.11.0 - Owner: https://github.com/smelloscope
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-client.yml@d85ea7b03966475f858f4d20a7782db225da60ae -
Trigger Event:
push
-
Statement type: