Skip to main content

Capture outgoing HTTP requests and inspect them in a local web dashboard

Project description

Smello logo

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

Run your code with Smello:

smello run my_app.py
smello run pytest tests/
smello run uvicorn app:app

That's it. Smello activates before your code runs and monkey-patches requests, httpx, aiohttp, grpc, and botocore to capture outgoing traffic. It also hooks sys.excepthook to capture unhandled exceptions with full tracebacks, and optionally captures Python log records. No code changes needed.

Subprocess instrumentation propagates automatically through PYTHONPATH, so smello run gunicorn app:app 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, --capture-logs, --log-level, --app, --session.

Tag events with --app and --session to isolate a debugging run:

smello run --app myapp --session debug-payment python scripts/checkout.py

Using smello.init() instead

If you prefer to activate Smello from within your code (e.g., for programmatic configuration or projects with a custom sitecustomize.py):

import smello
smello.init()  # activates only when SMELLO_URL is set

Framework middleware

To capture incoming requests, add the Smello middleware to your web framework:

FastAPI:

from smello.integrations.fastapi import SmelloMiddleware
from fastapi import FastAPI

app = FastAPI()
app.add_middleware(SmelloMiddleware, ignore_paths=["/health"])

Django:

# settings.py
MIDDLEWARE = [
    "smello.integrations.django.SmelloMiddleware",
    ...
]
SMELLO_IGNORE_PATHS = ["/health/", "/admin/"]

Then run with smello run:

smello run uvicorn app:app        # FastAPI
smello run manage.py runserver    # Django

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:

smello run my_bigquery_script.py

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 or Django 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

    # Tagging
    app="myapp",                               # tag events with an application name
    session="debug-payment",                   # tag events with a session ID
)

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 []
app SMELLO_APP ""
session SMELLO_SESSION ""

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() and AsyncClient.send()
  • aiohttp — patches ClientSession._request() to capture async HTTP traffic
  • grpc — patches insecure_channel() and secure_channel() to intercept unary-unary calls
  • botocore — patches URLLib3Session.send() to capture boto3 / AWS SDK traffic

Requires

Links

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

smello-0.14.0.tar.gz (50.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

smello-0.14.0-py3-none-any.whl (39.3 kB view details)

Uploaded Python 3

File details

Details for the file smello-0.14.0.tar.gz.

File metadata

  • Download URL: smello-0.14.0.tar.gz
  • Upload date:
  • Size: 50.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for smello-0.14.0.tar.gz
Algorithm Hash digest
SHA256 04d873966a02c87bef2d2a8b1bacb070d2d503d51de9822ef7a75756600cc5ad
MD5 e753804a87d0762e77209388aa1dbac2
BLAKE2b-256 5bc66427c2442c4f87121e416c338c2a08285803dd882a744290681e2842e143

See more details on using hashes here.

Provenance

The following attestation bundles were made for smello-0.14.0.tar.gz:

Publisher: publish-client.yml on smelloscope/smello

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file smello-0.14.0-py3-none-any.whl.

File metadata

  • Download URL: smello-0.14.0-py3-none-any.whl
  • Upload date:
  • Size: 39.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for smello-0.14.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cea8ed2537011aa8147c605412165c6b5f866b38c9ec81e71542e2ede22a9e3f
MD5 1c9f180a8f18ab153541114be12b060b
BLAKE2b-256 e2b81973ca40f4288e88452d3c25c332606969ad6e160bac59f74f1bcb9f54bb

See more details on using hashes here.

Provenance

The following attestation bundles were made for smello-0.14.0-py3-none-any.whl:

Publisher: publish-client.yml on smelloscope/smello

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page