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.
pip install requestsCopy 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.
# 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 headersNever 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.
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.
# 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.
{
"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`.
| Condition | Type (kind) | Severity |
|---|---|---|
| Unhandled exception | error | high |
| 4xx / 5xx | error | high |
| 3xx | info | low |
| 2xx | success | low |
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.
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.
# 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).
{
"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.
