Skip to main content

mitol-django-observability

MIT Open Learning Django plugin for OpenTelemetry tracing, structured logging (structlog), and alerting-as-code.

Installation

Add to INSTALLED_APPS:

"mitol.observability.apps.ObservabilityConfig",

See the RFC for full documentation.

Celery integration

To propagate structured log context (request ID, user ID, …) from web workers into Celery tasks and ensure Celery workers emit JSON logs through the same structlog pipeline, install the celery extra and follow the steps below.

1. Install the extra

pip install "mitol-django-observability[celery]"

This adds django-structlog[celery] (context propagation) and opentelemetry-instrumentation-celery (OTel task spans, auto-discovered).

2. Django settings

MIDDLEWARE = [
    # …
    "django_structlog.middlewares.RequestMiddleware",
]

DJANGO_STRUCTLOG_CELERY_ENABLED = True

3. Celery application

from celery import Celery
from celery.signals import setup_logging
from django_structlog.celery.steps import DjangoStructLogInitStep

from mitol.observability.celery import setup_celery_logging

app = Celery("yourproject")

@setup_logging.connect
def on_setup_logging(**kwargs):
    # Prevent Celery from overriding structlog's logging config in workers.
    setup_celery_logging(**kwargs)

# Propagate web-request context into task execution.
app.steps["worker"].add(DjangoStructLogInitStep)

How it works

  • setup_celery_logging calls configure_structlog(force=True), re-applying the structlog pipeline after Celery resets logging during worker boot.
  • DjangoStructLogInitStep installs signal handlers that bind the request context (captured by RequestMiddleware) to the structlog context vars before each task runs and clears it after.
  • opentelemetry-instrumentation-celery is auto-discovered via the opentelemetry_instrumentor entry-point group — no extra configuration required.

Postgres integration

To emit OTel spans for database queries, install the postgres extra:

pip install "mitol-django-observability[postgres]"

This adds two things:

  • opentelemetry-instrumentation-psycopg, auto-discovered via the opentelemetry_instrumentor entry-point group — no extra configuration required.
  • psycopg[c], the compiled binding, which is the implementation you want in production. The section below explains why the extra decides this on your behalf.

Build prerequisites

psycopg[c] is compiled from source at install time, so the build environment needs a C compiler, Python development headers, libpq-dev, and pg_config on PATH. Images built on mitodl/ol-python-base already provide all four.

CI runners generally do not. GitHub's ubuntu-24.04 image, for instance, ships PostgreSQL but not libpq-dev, so add it to your Aptfile (or equivalent) alongside the other -dev packages:

libpq-dev

If you are in an environment that genuinely cannot compile, install psycopg[binary] explicitly in your application — a pre-compiled wheel that bundles its own libpq and libssl. Those bundled libraries do not receive OS security updates, which is why it is not the default here.

Why the extra decides the driver

The psycopg instrumentation targets psycopg 3, so installing this extra puts psycopg 3 in your environment. That has a consequence which is easy to miss: it changes which driver Django uses. Django's Postgres backend prefers psycopg 3 over psycopg2 whenever psycopg 3 is importable (django/db/backends/postgresql/base.py):

try:
    try:
        import psycopg as Database
    except ImportError:
        import psycopg2 as Database

An application running on psycopg2 therefore switches to psycopg 3 the moment this instrumentation is installed, with no change to its own code and nothing in its dependency diff that names a driver.

Since the extra is already making that decision, it specifies the implementation too. psycopg 3 ships three interchangeable bindings to libpq, and a bare psycopg dependency selects the slowest:

dependency binding notes
psycopg pure Python, via ctypes upstream calls it "much slower"; intended for local development and small tasks
psycopg[c] compiled, linked against the system libpq psycopg's recommendation for production — system libpq/libssl upgrades carry through
psycopg[binary] compiled, bundles its own libpq/libssl no build tools needed, but the bundled libraries do not receive OS security updates

Extras union across dependency resolution, so requesting psycopg[c] here installs the compiled binding regardless of how the application declares psycopg itself.

Check what a deployed process actually resolved to — psycopg selects the best available implementation at import, so this reflects what is installed rather than what was requested:

>>> import psycopg
>>> psycopg.pq.__impl__
'c'

See psycopg's installation guide and pq module implementations for the full comparison.

Metadata

Release files for mitol-django-observability 2026.8.19

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

Source distribution (sdist)

Source distribution for mitol-django-observability 2026.8.19
File Size Uploaded
mitol_django_observability-2026.8.19.tar.gz 19.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mitol-django-observability 2026.8.19
File Interpreter ABI Platform
mitol_django_observability-2026.8.19-py3-none-any.whl Python 3 none any Details

Total release size: 47.1 kB

Release files / mitol_django_observability-2026.8.19.tar.gz

Download URL mitol_django_observability-2026.8.19.tar.gz
Size 19.2 kB
Tags Source
SHA-256 checksum
How to use checksums
3bf3afbd16c2f0ae087ed7911f301f31e3361ed170acdc9ef29e3cee8a8d0192
BLAKE2b-256 checksum
How to use checksums
b360ef5807301c6aa3a6ddbe2f48118a98d134f5fc324632f7715f270f3bb504
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / mitol_django_observability-2026.8.19-py3-none-any.whl

Download URL mitol_django_observability-2026.8.19-py3-none-any.whl
Size 27.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
442741f6b6d3ddacd85f5d32c8581c18899af2f7f299a74bc8a4116f0ae3bb8a
BLAKE2b-256 checksum
How to use checksums
80dd6e6608392f587f29a950b7e6b27ef4748458dfdfcac70e7fb81907d56deb
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

This release

2026.8.19 This release

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