Skip to main content
ImmutableLog logo
Back
DjangoPython

Django Integration

Integrate ImmutableLog into any Django application with a middleware that automatically captures all HTTP requests — errors, successes, and warnings — without changing a single line of your business code.

Installation

The middleware requires no dependencies beyond Django and the `requests` library, which is likely already installed in your project. Copy the `middleware.py` file into your application's configuration module (e.g., `api_core/middleware.py`) and install the dependency if needed.

bash
pip install requests

Copy the middleware.py file to your configuration module directory (e.g., api_core/middleware.py).

Configuration

Add the following variables to your `settings.py`. The `IMTBL_API_KEY` and `IMTBL_URL` variables are required — without them the middleware will not send any events. The remaining variables are optional and enrich the recorded metadata.

python
# settings.py

# Obrigatório / Required
IMTBL_API_KEY = "iml_live_xxxxxxxxxxxxxxxx"  # sua chave de API / your API key
IMTBL_URL = "https://api.immutablelog.com"                   # URL base da API / API base URL

# Opcional / Optional
IMTBL_SERVICE_NAME = "meu-servico-django"   # identifica o serviço / identifies the service
IMTBL_ENV = "production"                    # "production", "staging", "development"
IMTBL_HEADERS = {}                          # headers adicionais / extra headers

Never expose IMTBL_API_KEY in client-side code or public repositories. Use server-side environment variables and load them via os.environ.get() or tools like django-environ.

python
import os

IMTBL_API_KEY = os.environ.get("IMTBL_API_KEY", "")
IMTBL_URL = os.environ.get("IMTBL_URL", "https://api.immutablelog.com")

Register the Middleware

Add the middleware to your `MIDDLEWARE` list in `settings.py`. Order matters: place `ImmutableLogAuditMiddleware` right after Django's standard security middlewares to ensure all requests are captured, including those that raise unhandled exceptions.

python
# settings.py

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",

    # ImmutableLog — adicione após os middlewares padrão
    # ImmutableLog — add after standard middlewares
    "api_core.middleware.ImmutableLogAuditMiddleware",
]

How it works

The middleware intercepts the full lifecycle of each HTTP request. In `process_request`, it records the start timestamp and generates a unique `request_id` (or reuses the `X-Request-Id` header if present). In `process_response`, it calculates latency and sends the event to ImmutableLog. In `process_exception`, it captures unhandled exceptions and sends an error event with exception details.

process_request

Records start timestamp and generates unique request_id

process_response

Calculates latency, classifies the event, and sends it to ImmutableLog

process_exception

Captures unhandled exceptions and sends error event with details

The X-Request-Id header is returned in all responses, enabling end-to-end request tracing across systems.

Payload Structure

Each event sent to ImmutableLog contains a rich, structured payload with full request context. The payload is serialized as a JSON string (field `payload`) and accompanied by classification metadata (field `meta`). The server computes the SHA-256 hash over the payload exactly as sent.

json
{
  "payload": "{\"id\":\"d6b6c2e5-0c1a-4b92-9a62-2f2c4c2e9a2a\",\"kind\":\"success\",\"message\":\"GET /api/users/ concluído com sucesso\",\"timestamp\":\"2026-02-21T14:32:11.000Z\",\"context\":{\"ip\":\"192.168.1.100\",\"user_agent\":\"Mozilla/5.0\",\"user_id\":42,\"email\":\"user@example.com\"},\"request\":{\"request_id\":\"8d0b5f06-6d1f-4d3c-9b4f-9f5a2d7b3c1a\",\"method\":\"GET\",\"path\":\"/api/users/\",\"query_params\":null},\"metrics\":{\"latency_ms\":38,\"status_code\":200},\"severity\":\"low\",\"success\":{\"status_code\":200,\"result\":\"ok\"}}",
  "meta": {
    "type": "success",
    "event_name": "http.GET.api:user-list",
    "service": "meu-servico-django",
    "request_id": "8d0b5f06-6d1f-4d3c-9b4f-9f5a2d7b3c1a",
    "env": "production"
  }
}

Limit: Payload limit: 12KB per event. If the payload exceeds the limit, large fields (`error`, `request_body`) are automatically removed. As a last resort, only essential fields (`id`, `kind`, `message`, `timestamp`) are kept.

Event classification

The middleware automatically classifies each event based on the HTTP response status or the presence of an exception. Unhandled exceptions result in `error`. 2xx status results in `success`. 3xx results in `info`. 4xx and 5xx result in `error`. Redirects and informational responses result in `info`.

ConditionType (kind)Severity
Unhandled exceptionerrorhigh
4xx / 5xxerrorhigh
3xxinfolow
2xxsuccesslow

Custom event names

By default, the middleware generates the event name from the HTTP method and Django's named route (e.g., `http.GET.api:user-me`). To override this name in a specific view, assign `request.imtbl_event_name` before returning the response. This enables granular traceability by business event.

python
from django.http import JsonResponse

def process_payment(request):
    # Sobrescreve o nome do evento para este endpoint
    # Override the event name for this endpoint
    request.imtbl_event_name = "payment.processed"

    # ... lógica de negócio / business logic ...

    return JsonResponse({"status": "ok"})

If not set, the middleware defaults to http.METHOD.view_name based on Django's URL resolver.

Health check exclusion

The middleware automatically ignores events named `http.GET.health-check`, preventing health check calls from load balancers and orchestrators from polluting the ledger. Make sure your health check route is named `health-check` in the Django URL resolver.

python
# urls.py
from django.urls import path
from . import views

urlpatterns = [
    # Nome "health-check" → ignorado automaticamente pelo middleware
    # Name "health-check" → automatically ignored by the middleware
    path("health/", views.health_check, name="health-check"),

    path("api/users/", views.user_list, name="user-list"),
]

Error enrichment

On error events (`status >= 400` or exception), the middleware includes additional details: SHA-256 hash of the request body (for audit without exposing data), full body if smaller than 2KB, exception class and message (if any), and a `retryable` flag indicating whether the error is transient (408, 429, 500, 502, 503, 504).

json
{
  "payload": "{\"id\":\"a1b2c3d4-...\",\"kind\":\"error\",\"message\":\"POST /api/checkout/ falhou com exceção: ValueError\",\"context\":{\"ip\":\"10.0.0.1\",\"user_id\":7},\"request\":{\"method\":\"POST\",\"path\":\"/api/checkout/\"},\"metrics\":{\"latency_ms\":12,\"status_code\":500},\"severity\":\"high\",\"error\":{\"status_code\":500,\"retryable\":true,\"exception\":\"ValueError\",\"exception_message\":\"Invalid product SKU\",\"request_body_hash\":\"4f2b8e9a3c5d...\",\"request_body\":\"{\\"sku\\":\\"INVALID\\"}\"}}",
  "meta": {
    "type": "error",
    "event_name": "http.POST.api:checkout",
    "service": "meu-servico-django",
    "env": "production"
  }
}

error.exception

Exception class name

error.exception_message

Exception message

error.request_body_hash

SHA-256 of body (always present on errors)

error.retryable

True for: 408, 429, 500, 502, 503, 504

This documentation reflects the current integration behavior. For questions or advanced integrations, contact the support team.