Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

Django Activity Audit

A Django package that extends the default logging mechanism to track CRUD operations and container logs.

Features

  • Automatic logging of CRUD operations (Create, Read, Update, Delete)
  • Tracks both HTTP requests and model changes
  • Custom log levels Audit(21) and API(22) for CRUD and Request-Response auditing.
  • Structured JSON logs for audit trails
  • Human-readable container logs
  • Console-only output via structlog, ready for pipeline ingestion (Vector, CloudWatch, etc.)

Installation

  1. Install the package:
pip install django-activity-audit

This also installs structlog and orjson as required dependencies.

  1. Add 'activity_audit' to your INSTALLED_APPS in settings.py:
INSTALLED_APPS = [
    ...
    'activity_audit',
]
  1. Add the middleware to your MIDDLEWARE in settings.py:
MIDDLEWARE = [
    ...
    'activity_audit.middleware.AuditLoggingMiddleware',
]
  1. Configure logging in settings.py:

Import the formatter helpers from activity_audit.config:

from activity_audit.config import get_plain_formatter, get_stdlib_formatter
  • get_stdlib_formatter() — structlog JSON renderer. Use in staging/production where logs are ingested by a pipeline (Vector, CloudWatch, etc.).
  • get_plain_formatter() — structlog plain-text renderer. Use locally for human-readable console output.

Local development (plain text output):

from activity_audit.config import get_plain_formatter, get_stdlib_formatter

LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "formatters": {
        "structlog": get_stdlib_formatter(),
        "default":   get_plain_formatter(),
    },
    "handlers": {
        "console":        {"class": "logging.StreamHandler", "formatter": "default"},
        "console_struct": {"class": "logging.StreamHandler", "formatter": "structlog"},
    },
    "root": {
        "level": "INFO",
        "handlers": ["console"],   # plain text fallback for all loggers
    },
    "loggers": {
        # Structlog owns these — explicit handler, no propagation to avoid double output
        "audit.model":   {"handlers": ["console_struct"], "propagate": False},
        "audit.request": {"handlers": ["console_struct"], "propagate": False},
        "audit.login":   {"handlers": ["console_struct"], "propagate": False},

        # Celery — structlog formats log_type correctly
        "celery":        {"level": "INFO", "handlers": ["console_struct"], "propagate": False},
        "celery.task":   {"level": "INFO", "handlers": ["console_struct"], "propagate": False},
        "celery.beat":   {"level": "INFO", "handlers": ["console_struct"], "propagate": False},

        # Third-party noise control — WARNING only, routed to root
        "django.db.backends": {"level": "WARNING", "handlers": [], "propagate": True},
        "boto3":              {"level": "WARNING", "handlers": [], "propagate": True},
        "botocore":           {"level": "WARNING", "handlers": [], "propagate": True},

        # Framework loggers
        "django":        {"level": "INFO", "handlers": [], "propagate": True},
        "uvicorn":       {"level": "INFO", "handlers": [], "propagate": True},
        "uvicorn.error": {"level": "INFO", "handlers": [], "propagate": True},
        "uvicorn.access":{"level": "INFO", "handlers": [], "propagate": True},
    },
}

Staging / production (structured JSON output): identical structure, but the root handler also uses console_struct (or keep console for mixed output — both handlers use the same StreamHandler class):

"root": {
    "level": "INFO",
    "handlers": ["console"],
}

When to add a logger entry

Add an explicit logger entry when you need any of the following:

Situation What to set
Route to structured JSON (console_struct) handlers: ["console_struct"], propagate: False
Suppress a noisy third-party library level: "WARNING", handlers: [], propagate: True
Prevent double output for a structlog-owned logger handlers: ["console_struct"], propagate: False
Change the log level for a specific namespace Set level explicitly

Do not add a logger entry if the default behaviour is acceptable — a logger with no entry propagates to root and is emitted in plain text at INFO level. That is the correct behaviour for most application loggers.

Silencing audit loggers (route to root instead of structlog)

By default audit.model, audit.request, and audit.login are pointed at console_struct with propagate: False so only the structlog-formatted JSON line is emitted.

To stop structlog from handling them and fall back to the plain-text root logger instead, set handlers: [] and propagate: True:

"loggers": {
    "audit.model":   {"handlers": [], "propagate": True},
    "audit.request": {"handlers": [], "propagate": True},
    "audit.login":   {"handlers": [], "propagate": True},
}

This routes all three through the root logger (console handler, default / plain-text formatter). Use this when you want to completely disable structured audit output — for example, in a minimal local environment or during debugging.

  1. Configure the service name in settings.py (optional, defaults to "default"):
AUDIT_SERVICE_NAME = "my_service"
  1. For external services logging, extend HTTPClient or SFTPClient
class ExternalService(HTTPClient):
    def __init__(self):
        super().__init__("service_name")

    def connect(self):
        url = "https://www.sample.com"
        response = self.get(url) # sample log structure below
  1. Create audit_logs folder in project directory

Log Types

Container Logs

Console Log Format

'%(levelname)s %(asctime)s %(pathname)s %(module)s %(funcName)s %(message)s'
-----------------------------------------------------------------------------
INFO 2025-04-30 08:51:10,403 /app/patients/api/utils.py utils create_patient_with_contacts_and_diseases Patient 'd6c9a056-0b57-453a-8c0f-44319004b761 - Patient3' created.

File Log Format

APP Log

{
    "timestamp": "2025-05-15 13:38:02.141",
    "level": "DEBUG",
    "name": "botocore.auth",
    "path": "/opt/venv/lib/python3.11/site-packages/botocore/auth.py",
    "module": "auth",
    "function": "add_auth",
    "message": "Calculating signature using v4 auth.",
    "exception": ""
}

CRUD Log

{
    "timestamp": "2025-08-16 17:06:32.403",
    "level": "AUDIT",
    "name": "audit.model",
    "message": "CREATE event by User (id: 6f77b814-f9c1-4cab-a737-6677734bc303)",
    "request_id": "f3c9a1b2-0001-4abc-beef-deadbeef0001",
    "model": "User",
    "event_type": "CREATE",
    "instance_id": "6f77b814-f9c1-4cab-a737-6677734bc303",
    "instance_repr" : {
        "name": "Test Model",
        "is_active": true,
        "created_at": "2025-08-29T08:18:54Z",
        "updated_at": "2025-08-29T08:18:54Z"
    },
    "user_id": "cae8ffb4-ba52-409c-9a6f-e10362bfaf97",
    "user_info": {
        "title": "mr",
        "email": "example@source.com",
        "first_name": "mohamlal",
        "middle_name": "v",
        "last_name": "nair",
        "sex": "m",
    },
    "extra": {}
}

Request-Response Log

Incoming Log Format

{
    "timestamp": "2025-05-19 15:25:27.836",
    "level": "API",
    "name": "audit.request",
    "message": "Audit Internal Request",
    "request_id": "f3c9a1b2-0001-4abc-beef-deadbeef0001",
    "service_name": "my_service",
    "request_type": "internal",
    "protocol": "http",
    "user_id": "14ab1197-ebdd-4300-a618-5910e0219936",
    "user_info": {
        "title": "mr",
        "email": "example@email.com",
        "first_name": "mohanlal",
        "middle_name": "",
        "last_name": "nair",
        "sex": "male",
        "date_of_birth": "21/30/1939"
    },
    "request_repr": {
        "method": "GET",
        "path": "/api/v1/health/",
        "query_params": {},
        "headers": {
            "Content-Type": "application/json",
        },
        "user": null,
        "body": {
            "title": "hello"
        }
    },
    "response_repr": {
        "status_code": 200,
        "headers": {
            "Content-Type": "application/json",
        },
        "body": {
            "status": "ok"
        }
    },
    "error_message": null,
    "execution_time": 5.376734018325806
}

External Log format

{
    "timestamp": "2025-05-19 15:25:27.717",
    "level": "API",
    "name": "audit.request",
    "message": "Audit External Service",
    "request_id": "f3c9a1b2-0001-4abc-beef-deadbeef0001",
    "service_name": "apollo",
    "request_type": "external",
    "protocol": "http",
    "user_id": "14ab1197-ebdd-4300-a618-5910e0219936",
    "user_info": {
        "title": "mr",
        "email": "example@email.com",
        "first_name": "mohanlal",
        "middle_name": "",
        "last_name": "nair",
        "sex": "male",
        "date_of_birth": "21/30/1939"
    },
    "request_repr": {
        "endpoint": "example.com",
        "method": "GET",
        "headers": {},
        "body": {}
    },
    "response_repr": {
        "status_code": 200,
        "body": {
            "title": "title",
            "expiresIn": 3600,
            "error": "",
            "errorDescription": ""
        }
    },
    "error_message": "",
    "execution_time": 5.16809344291687
}

Notes

  • Compatible with Django 3.2+ and Python 3.7+.
  • Designed for easy integration with observability stacks using Vector, ClickHouse, and Grafana.
  • Capture Django CRUD operations automatically
  • Write structured JSON logs
  • Ready for production-grade logging pipelines
  • Simple pip install, reusable across projects
  • Zero additional database overhead!

Related Tools

License

This project is licensed under the MIT License - see the LICENSE file for details.

Metadata

Release files for django-activity-audit 1.3.0.dev24

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-activity-audit 1.3.0.dev24
File Size Uploaded
django_activity_audit-1.3.0.dev24.tar.gz 1.7 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for django-activity-audit 1.3.0.dev24
File Interpreter ABI Platform
django_activity_audit-1.3.0.dev24-py3-none-any.whl Python 3 none any Details

Total release size: 1.7 MB

Release files / django_activity_audit-1.3.0.dev24.tar.gz

Download URL django_activity_audit-1.3.0.dev24.tar.gz
Size 1.7 MB
Tags Source
SHA-256 checksum
How to use checksums
30e81ac997d65ca8a418d12aed6bc6dde23d3b766adf7d9e432e5cb92840a24e
BLAKE2b-256 checksum
How to use checksums
4d87f32ef2708ddfaabe7931876937ac16fa42e017a75252aca8322467fcc01e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via Hatch/1.16.2 cpython/3.12.3 HTTPX/0.28.1

Release files / django_activity_audit-1.3.0.dev24-py3-none-any.whl

Download URL django_activity_audit-1.3.0.dev24-py3-none-any.whl
Size 18.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
85605f1b2af3535101a0deb9b6d510c9475a464ed1bfed63c89b573c58337dbc
BLAKE2b-256 checksum
How to use checksums
7848764f5468d0d9b7490ebfcc2a26a1928efc1718ade20532ef11fdd1847c3c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via Hatch/1.16.2 cpython/3.12.3 HTTPX/0.28.1

Release history Release notifications | RSS feed

This release

1.3.0.dev24 This release

2 release files

1.2.7

2 release files

1.2.6

2 release files

1.2.5

2 release files

1.2.4

2 release files

1.2.3

2 release files

1.2.2

2 release files

1.2.1

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.6

2 release files

1.0.5

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page