Getting Started
Install
Install the client SDK and the server:
Start the server:
Or run with Docker:
The server listens at http://localhost:5110.
Why port 5110?
Read it as 5-1-1-0 → S-L-L-O → smello.
Run your code with Smello
Prefix any Python command with smello run:
That's it. Smello activates before your code runs and monkey-patches requests, httpx, aiohttp, grpc, and botocore to capture all outgoing traffic. It also hooks sys.excepthook to capture unhandled exceptions. No code changes needed.
Subprocess instrumentation propagates automatically, so smello run gunicorn app:app also captures traffic from worker processes.
Use -- to disambiguate when smello flags conflict with the wrapped command's flags:
CLI flags map 1:1 to the environment variables:
| Flag | Env var |
|---|---|
--server |
SMELLO_URL |
--capture-host |
SMELLO_CAPTURE_HOSTS |
--ignore-host |
SMELLO_IGNORE_HOSTS |
--capture-all / --no-capture-all |
SMELLO_CAPTURE_ALL |
--redact-header |
SMELLO_REDACT_HEADERS |
--redact-query-param |
SMELLO_REDACT_QUERY_PARAMS |
Using smello.init() instead
If you prefer to activate Smello from within your code, call smello.init():
Smello only activates when a server URL is provided, either via the server_url parameter or the SMELLO_URL environment variable. Without a URL, init() is a safe no-op: no monkey-patching, no background threads, no side effects.
Like Sentry's SENTRY_DSN, this keeps instrumentation in place with zero production overhead. smello.init() is also the right choice for projects with a custom sitecustomize.py, where smello run can't be used.
FastAPI middleware
To capture incoming HTTP requests in a FastAPI app, add the Smello middleware:
from smello.integrations.fastapi import SmelloMiddleware
from fastapi import FastAPI
app = FastAPI()
app.add_middleware(SmelloMiddleware)
Then run your server with smello run:
Every request your server handles appears in the dashboard with method, path, status code, duration, route pattern, and client IP. If a route handler raises an unhandled exception, the middleware captures the traceback before re-raising.
By default, all paths are captured. Use ignore_paths to skip noisy endpoints like health checks and OpenAPI schema routes. Matching is prefix-based:
The middleware is a raw ASGI middleware (not Starlette's BaseHTTPMiddleware), so it works with streaming responses and background tasks. When Smello is inactive (no server URL configured), the middleware passes requests through without capturing anything.
Capturing logs
Log capture is opt-in. Enable it to see Python log records alongside your HTTP traffic and exceptions in the same timeline:
Or with smello.init():
Smello's own loggers (smello.*) and urllib3 loggers are always excluded to prevent recursion. You can suppress other noisy loggers with ignore_loggers:
Matching is hierarchical: "uvicorn" suppresses uvicorn, uvicorn.access, uvicorn.error, etc. See ignore_loggers for details.
Capturing exceptions
Unhandled exceptions are captured by default. No configuration needed. When your program crashes, Smello captures the full traceback with stack frames and source context, then flushes the event before the process exits.
To disable exception capture: smello run --no-capture-exceptions my_app.py or smello.init(capture_exceptions=False).
Google Cloud libraries
Many Google Cloud Python libraries use gRPC under the hood. Smello captures these calls automatically. No extra setup needed:
BigQuery, Firestore, Pub/Sub, Analytics (GA4), Vertex AI, Speech-to-Text, Vision, Translation: anything that calls grpc.secure_channel() or grpc.insecure_channel() is captured.
AWS libraries (boto3)
boto3 uses botocore, which calls urllib3 directly, bypassing requests and httpx. Smello patches botocore's HTTP session to capture all AWS API calls:
AWS calls appear at http://localhost:5110. XML responses show as a collapsible tree, just like JSON.
What Smello captures
Outgoing HTTP requests
For every outgoing HTTP and gRPC call:
- Method, URL, headers, and body
- Response status code, headers, and body
- Duration in milliseconds
- Library used (requests, httpx, aiohttp, grpc, or botocore)
The dashboard recognizes Unix timestamps in JSON bodies and shows the human-readable date in a tooltip. XML responses (common in AWS S3, STS, EC2) appear as a collapsible tree, just like JSON. Both formats offer Tree and Raw tabs. Tree shows an expandable tree; Raw shows syntax-highlighted source.
gRPC calls are displayed with a grpc:// URL scheme. Protobuf request and response bodies are automatically serialized to JSON.
Incoming HTTP requests
When you add the FastAPI middleware, Smello captures every request your server handles:
- Method, path, full URL, and route pattern (e.g.,
/api/users/{id}) - Request and response headers and bodies
- Response status code and duration
- Client IP address
- Exception type and traceback (if the handler raises)
Request and response bodies are capped at 1 MB, matching the outgoing capture limit.
Logs
When capture_logs=True, Smello captures Python log records at or above the configured log_level:
- Level (DEBUG, INFO, WARNING, ERROR, CRITICAL), logger name, and formatted message
- Source file path, line number, and function name
- Extra attributes attached to the record via
extra={...}
Smello's own loggers (smello.*) and urllib3 loggers are automatically excluded to prevent recursion.
Exceptions
Unhandled exceptions are captured with:
- Exception type, message, and module
- Full formatted traceback text
- Individual stack frames with filename, line number, function name, and source context line
Both sys.excepthook (main thread) and threading.excepthook (worker threads) are hooked.
Smello redacts sensitive headers (Authorization, X-Api-Key) by default and optionally redacts query string parameters (details).
Supported libraries
| Library | What Smello patches |
|---|---|
| requests | Session.send() |
| httpx | Client.send() and AsyncClient.send() |
| grpc | insecure_channel() and secure_channel() (unary-unary) |
| aiohttp | ClientSession._request() (async HTTP client) |
| botocore | URLLib3Session.send() (all boto3 / AWS SDK calls) |
Python version support
| Package | Python |
|---|---|
| smello (client SDK) | >= 3.10 |
| smello-server | >= 3.14 |