Skip to main content

logsetu-django

Ship Django / DRF, Flask and FastAPI logs and unhandled errors to your self-hosted LogSetu server. Zero runtime dependencies, non-blocking (background thread + batching), and it never crashes your app if the log server is down.

pip install logsetu-django

Despite the name, the Django part is optional — the same package (import name logsetu) ships integrations for Flask and FastAPI / any ASGI app. The core client and logging handler work in any Python program.

Setup (2 minutes)

# settings.py
INSTALLED_APPS = [..., "logsetu"]  # optional, but nice for discoverability

LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "handlers": {
        "logsetu": {
            "class": "logsetu.handler.LogSetuHandler",
            "api_key": env("LOGSETU_API_KEY"),        # from the LogSetu dashboard → Projects
            "endpoint": env("LOGSETU_ENDPOINT"),      # e.g. https://logs.example.com
            "environment": env("ENVIRONMENT", default="production"),
            "source": "django-backend",
            "level": "WARNING",
        },
    },
    "root": {"handlers": ["logsetu"], "level": "INFO"},
}

MIDDLEWARE = [
    ...,
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "logsetu.middleware.LogSetuMiddleware",   # after auth middleware so user ids are captured
]

That's it. Every logging call at or above the handler's level is sent to LogSetu, and the middleware reports unhandled exceptions (and 5xx responses) with the request path, method, view, user, redacted headers and full traceback.

import logging
log = logging.getLogger(__name__)

log.warning("Checkout is slow", extra={"duration_ms": 1830, "cart_items": 12})
try:
    charge(card)
except PaymentError:
    log.exception("Payment failed")          # traceback is attached automatically

Multi-tenant apps

Tag every log with the current tenant by pointing the SDK at a callable (request) -> str | None:

# settings.py
LOGGING["handlers"]["logsetu"]["get_tenant_id"] = "myapp.tenants.get_tenant_id"

# myapp/tenants.py
def get_tenant_id(request):
    return getattr(request, "tenant", None) and request.tenant.slug

Or, from anywhere inside a request (e.g. after you resolve the tenant in your own middleware):

from logsetu import update_request_context
update_request_context(tenant_id=tenant.slug, plan=tenant.plan)

Handler options

Option Default Description
api_key / endpoint — Required (or set LOGSETU = {"API_KEY": ..., "ENDPOINT": ...} in settings)
environment "production" Tag on every log
source "django" Tag on every log; override per record with extra={"source": "celery"}
get_tenant_id None Dotted path or callable (request) -> str
include_extra True Forward extra={...} fields as metadata
include_request_context True Attach request id / path / method / tenant set by the middleware
flush_interval 2.0 Seconds between background flushes
batch_size 10 Flush as soon as this many logs are queued
max_queue_size 1000 Drop oldest logs beyond this
max_retries 3 Retries with exponential backoff on 5xx / network errors
timeout 5.0 HTTP timeout in seconds
debug False Print every transport failure to stderr (otherwise only the first)

Middleware options (settings.LOGSETU)

The middleware reuses the client and options of a configured LogSetuHandler. Without a handler it can run standalone:

LOGSETU = {
    "API_KEY": env("LOGSETU_API_KEY"),
    "ENDPOINT": env("LOGSETU_ENDPOINT"),
    "ENVIRONMENT": "production",
    "SOURCE": "django-backend",
    "GET_TENANT_ID": "myapp.tenants.get_tenant_id",
    "REDACT_HEADERS": ["authorization", "cookie", "x-api-key"],  # defaults already cover these
    "CAPTURE_5XX": True,   # also report 5xx responses that didn't raise
}

Every request gets a request_id (taken from X-Request-ID if present, otherwise generated) which is attached to all logs emitted during that request and exposed as request.logsetu_request_id.

Guarantees

  • Never blocks the request cycle: emit() only appends to an in-memory queue.
  • Never raises into your app: transport errors are printed once to stderr, then suppressed.
  • Never leaks secrets: Authorization, Cookie, X-Api-Key, X-CSRFToken and Proxy-Authorization are redacted.
  • Never loses the last logs on shutdown: the queue is flushed via atexit.

Celery / management commands

Nothing special — the handler works anywhere Python's logging does. Set extra={"source": "celery"} to distinguish workers, or configure a second handler with a different source.

Flask

import os
from flask import Flask
from logsetu.flask import LogSetu

app = Flask(__name__)
LogSetu(app, api_key=os.environ["LOGSETU_API_KEY"], endpoint=os.environ["LOGSETU_ENDPOINT"], source="flask-api")

App factory? Create logsetu = LogSetu() at module level and call logsetu.init_app(app); options you don't pass are read from app.config (LOGSETU_API_KEY, LOGSETU_ENDPOINT, LOGSETU_ENVIRONMENT, LOGSETU_SOURCE).

The extension reports unhandled exceptions and 5xx responses (route, endpoint, redacted headers, traceback), and attaches a LogSetuHandler to the root logger so logging.warning(...) and above is shipped with the request id, method and path of the current request. Flask's own "Exception on /path" log line is de-duplicated.

Option Default Description
api_key / endpoint app.config Project API key and server URL
environment / source "production" / "flask" Tags on every log
get_tenant_id — callable(request) -> str | None or dotted path
capture_logging True Attach a handler to the root logger
log_level logging.WARNING Minimum level forwarded from logging
capture_5xx True Report 5xx responses that didn't raise
log_requests False One info/warn log per request
redact_headers auth / cookie / API-key headers Header names replaced by [REDACTED]
client — Use an existing LogSetuClient

FastAPI / Starlette / ASGI

import os
from fastapi import FastAPI
from logsetu.fastapi import LogSetuMiddleware   # alias of logsetu.asgi — works with any ASGI app

app = FastAPI()
app.add_middleware(
    LogSetuMiddleware,
    api_key=os.environ["LOGSETU_API_KEY"],
    endpoint=os.environ["LOGSETU_ENDPOINT"],
    source="fastapi",
    ignore_paths=["/healthz"],
)

A pure ASGI middleware (streaming responses aren't buffered). Same options as Flask plus ignore_paths; get_tenant_id receives the ASGI scope, and api_key / endpoint / environment / source fall back to the LOGSETU_* environment variables. Request context reaches logs from both async def endpoints and sync endpoints running in the threadpool. HTTPExceptions with 4xx status codes aren't reported as errors. The request id is available as request.state.logsetu_request_id.

License

MIT

Metadata

Release files for logsetu-django 0.2.0

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

Source distribution (sdist)

Source distribution for logsetu-django 0.2.0
File Size Uploaded
logsetu_django-0.2.0.tar.gz 20.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for logsetu-django 0.2.0
File Interpreter ABI Platform
logsetu_django-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 42.2 kB

Release files / logsetu_django-0.2.0.tar.gz

Download URL logsetu_django-0.2.0.tar.gz
Size 20.4 kB
Tags Source
SHA-256 checksum
How to use checksums
ddaecfc6d13659c40577bd4af017a7b56ce245f4648f9273520e382a165c9617
BLAKE2b-256 checksum
How to use checksums
562ab8c7d2324c4d3c15f953d802d32b1d613604aa9afa782f5e0c98de69d0ee
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / logsetu_django-0.2.0-py3-none-any.whl

Download URL logsetu_django-0.2.0-py3-none-any.whl
Size 21.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
43befd1b34f168ccd6e2d88928029a8f5e22bba1879bea52a69c46b54c8b7b78
BLAKE2b-256 checksum
How to use checksums
6e1bf94f7ce9f84205a5ece0846f7928fae355502db2720892ba5eadec35beb5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

0.3.0

2 release files

This release

0.2.0 This release

2 release files

0.1.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