Skip to main content

A Django application that logs requests and responses to your project for auditing or troubleshooting purposes.

Project description

Django Rapyd Wiretap

Tests PyPI version Python versions Django versions License

A Django middleware that logs HTTP requests and responses to your database for auditing or troubleshooting purposes. Unlike similar packages, it works in production — logging is not gated on settings.DEBUG.

Inspired by nathforge/django-wiretap.

Install

pip install django-rapyd-wiretap

Quickstart

  1. Add wiretap to INSTALLED_APPS:

    INSTALLED_APPS = [
        ...
        "wiretap",
    ]
    
  2. Add the middleware to MIDDLEWARE:

    MIDDLEWARE = [
        ...
        "wiretap.middleware.WiretapMiddleware",
    ]
    
  3. Apply migrations:

    python manage.py migrate
    

Usage

In the Django admin, create a Tap to configure which requests to capture:

  • Path — a Python regex matched against the full request path with re.search.
  • Is active — deactivate a tap without deleting it.

Each matched request is stored as a Message with the request method, path, headers, body, response status, and timing information. Messages are read-only in the admin.

Tap recipes

Goal Path regex
Capture all /api/ traffic ^/api/
Capture a specific endpoint exactly ^/api/v1/payments/$
Capture a versioned endpoint (any version) ^/api/v\d+/payments/
Capture everything /
Capture everything except /admin/ and /static/ ^/(?!admin/|static/)
Capture POSTs to webhooks (combine with another middleware filtering by method) ^/webhooks/

The path regex is matched with re.search, not re.fullmatch — anchor with ^ if you want a prefix match, and add $ if you want an exact match. Query strings are not part of the path; they're available on Message.request_path only if Django's path router includes them (it normally doesn't).

Reading captured messages

Each Message row has the following fields:

Field Description
started_at / ended_at When request logging began and response logging finished (UTC, indexed).
duration Whole seconds between started_at and ended_at (indexed). For sub-second precision, compute from the timestamps directly.
remote_addr Client IP from REMOTE_ADDR (indexed). If you sit behind a proxy, install django.middleware.common.CommonMiddleware-style IP unwrapping before WiretapMiddleware.
request_method GET, POST, etc. (indexed).
request_path Full request path (no query string).
request_headers_json / response_headers_json JSON-encoded header dicts. Use the request_headers / response_headers properties to get a dict.
request_body_raw / response_body_raw UTF-8-decoded body. Set to empty string for empty bodies; non-UTF-8 bodies are skipped (the row is still saved).
request_body_pretty / response_body_pretty JSON-pretty-printed body, populated only when the corresponding Content-Type contains json and the body parses. NULL otherwise.
response_status_code / response_reason_phrase HTTP status (indexed).

Helper methods on Message:

message.get_request_header("Content-Type")          # raises KeyError if missing
message.get_request_header("X-Custom", default=None)  # returns default if missing
message.get_response_header("Location", "")

Header lookups are case-insensitive (titled-cased internally).

Operations

Pruning old messages

Message rows accumulate forever once a Tap is active. A 100 RPS endpoint matched by ^/api/ produces ~8.6M rows/day — plan storage accordingly and prune on a schedule.

# delete messages older than 30 days
python manage.py wiretap_prune --older-than-days 30

# preview without deleting
python manage.py wiretap_prune --older-than-days 30 --dry-run

Run as a daily cron / scheduled job. The command issues a single bulk DELETE filtered on started_at.

Middleware ordering

Place WiretapMiddleware near the top of MIDDLEWARE, after security/common middleware but before any middleware that mutates request bodies or response content. The earlier it sits, the closer the captured payload is to the on-the-wire form.

If you sit behind a load balancer or reverse proxy, install IP-unwrapping middleware (e.g., django.middleware.common.CommonMiddleware plus USE_X_FORWARDED_HOST, or a dedicated package) before WiretapMiddleware, so remote_addr reflects the real client IP rather than the proxy's.

Indexed fields and ad-hoc queries

started_at, ended_at, duration, remote_addr, request_method, response_status_code, and response_reason_phrase are indexed. Filtering/ordering by those scales. Filtering by request_path (a TextField) on a large table will table-scan; if you do this often, add a custom index in your project's migrations.

Sensitive data

Wiretap captures everything in matched requests, including Authorization and Cookie headers, request/response bodies, and any tokens or PII passing through. Tap conservatively, and keep the Message table on storage with the same threat model as your secrets store.

Built-in opt-in redaction is on the roadmap — see issue #10.

Supported versions

Package Versions
Python 3.10, 3.11, 3.12, 3.13
Django 4.2 LTS, 5.2 LTS

Contributing

See CONTRIBUTING.md for development setup, test commands, and the release process.

License

Apache 2.0. See LICENSE.

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

django_rapyd_wiretap-0.2.0.tar.gz (87.3 kB view details)

Uploaded Source

Built Distribution

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

django_rapyd_wiretap-0.2.0-py3-none-any.whl (18.1 kB view details)

Uploaded Python 3

File details

Details for the file django_rapyd_wiretap-0.2.0.tar.gz.

File metadata

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

File hashes

Hashes for django_rapyd_wiretap-0.2.0.tar.gz
Algorithm Hash digest
SHA256 42a2a79c0e2cbae6bbfb6a4e155402295e7f64722ff6b8cde15fbb6ef35eae80
MD5 a27cd94b65ee429f97436eed035e1ea2
BLAKE2b-256 a49c5d109e94d4eae0640edf8e550f08f3b5f12030615ec6adc2b5c6f84ce173

See more details on using hashes here.

Provenance

The following attestation bundles were made for django_rapyd_wiretap-0.2.0.tar.gz:

Publisher: publish.yml on karthicraghupathi/django_rapyd_wiretap

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

File details

Details for the file django_rapyd_wiretap-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for django_rapyd_wiretap-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1ca0d046416bbdbb47674797dbaa1d07665a88044a75a0f3b6b80ff2c7f2b036
MD5 f922de4eb651c31a07e17b3597feba6e
BLAKE2b-256 721a65d9350cb105fb99fec6c75f0bc08a2148906046bcac9fd6479b9d3ab802

See more details on using hashes here.

Provenance

The following attestation bundles were made for django_rapyd_wiretap-0.2.0-py3-none-any.whl:

Publisher: publish.yml on karthicraghupathi/django_rapyd_wiretap

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