Registry / observability / django-structlog

django-structlog

JSON →
library10.1.0pypypi✓ verified 25d ago

django-structlog is a structured logging integration for Django projects that leverages the `structlog` library. It enriches logs with cohesive metadata, simplifying event and incident tracking. The current version is 10.0.0, and the library maintains an active release cadence with multiple updates throughout the year to support new Django and Python versions.

pip install django-structlog
INSTALL
IMPORT
SIG · DJANGO-STRUCTLOG
D
django-structlog
observabilitypythonv10.1.0
Install
4.7s avg
Import
260ms
Disk
88MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.93.13
musl
3.93.13
Install & Compatibility
Where this runs
tested against v10.1.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
py 3.103.910 runs
installs and imports cleanly · install 0.0s · import 0.269s · 90MB
glibc
py 3.103.910 runs
installs and imports cleanly · install 4.7s · import 0.251s · 91MB
88MB installed
● package 88MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

get_logger
import structlog logger = structlog.get_logger(__name__)
This is the primary way to obtain a logger for structured logging.
RequestMiddleware
from django_structlog.middlewares import RequestMiddleware
'django_structlog.middlewares.StructlogMiddleware'
The middleware class name is `RequestMiddleware`, not `StructlogMiddleware`.
bind_contextvars
from structlog import contextvars contextvars.bind_contextvars(user_id=request.user.id)
logger.bind(user_id=request.user.id)
Since v3.0+, `django-structlog` uses `structlog.contextvars.bind_contextvars` instead of `logger.bind` to manage context variables.

To get started with `django-structlog`, install the package, add `"django_structlog"` to your `INSTALLED_APPS`, and `"django_structlog.middlewares.RequestMiddleware"` to your `MIDDLEWARE` settings. Crucially, configure your `LOGGING` dictionary in `settings.py` to use `structlog.stdlib.ProcessorFormatter` with appropriate processors, including `structlog.contextvars.merge_contextvars` as the first processor. Finally, configure `structlog` itself using `structlog.configure()`. You can then obtain loggers using `structlog.get_logger()` and log structured messages.

import structlog # settings.py INSTALLED_APPS = [ # ... "django_structlog", # ... ] MIDDLEWARE = [ # ... "django_structlog.middlewares.RequestMiddleware", # ... ] LOGGING = { "version": 1, "disable_existing_loggers": False, "formatters": { "json_formatter": { "()": structlog.stdlib.ProcessorFormatter, "processor": structlog.processors.JSONRenderer(), "foreign_pre_chain": [ structlog.contextvars.merge_contextvars, structlog.processors.TimeStamper(fmt="iso"), structlog.stdlib.add_logger_name, structlog.stdlib.add_log_level, structlog.stdlib.PositionalArgumentsFormatter(), ], }, "plain_console": { "()": structlog.stdlib.ProcessorFormatter, "processor": structlog.dev.ConsoleRenderer(), "foreign_pre_chain": [ structlog.contextvars.merge_contextvars, structlog.processors.TimeStamper(fmt="iso"), structlog.stdlib.add_logger_name, structlog.stdlib.add_log_level, structlog.stdlib.PositionalArgumentsFormatter(), ], }, }, "handlers": { "console": { "class": "logging.StreamHandler", "formatter": "plain_console", }, "json_file": { "class": "logging.handlers.RotatingFileHandler", "filename": "logs/json.log", "maxBytes": 1024 * 1024 * 5, # 5 MB "backupCount": 5, "formatter": "json_formatter", }, }, "loggers": { "django_structlog": { "handlers": ["console", "json_file"], "level": "INFO", "propagate": False, }, "django": { "handlers": ["console", "json_file"], "level": "INFO", "propagate": False, }, "my_app": { # Example for your application logs "handlers": ["console", "json_file"], "level": "DEBUG", "propagate": False, }, "root": { "handlers": ["console", "json_file"], "level": "INFO", }, }, } structlog.configure( processors=[ structlog.contextvars.merge_contextvars, # MUST be the first processor structlog.stdlib.filter_by_level, structlog.processors.TimeStamper(fmt="iso"), structlog.stdlib.add_logger_name, structlog.stdlib.add_log_level, structlog.stdlib.PositionalArgumentsFormatter(), structlog.processors.StackInfoRenderer(), structlog.processors.format_exc_info, structlog.processors.UnicodeDecoder(), structlog.stdlib.ProcessorFormatter.wrap_for_formatter, ], logger_factory=structlog.stdlib.LoggerFactory(), cache_logger_on_first_use=True, ) # views.py (example usage) import structlog from django.http import HttpResponse logger = structlog.get_logger(__name__) def my_view(request): logger.info("request_received", path=request.path, method=request.method) # Your view logic return HttpResponse("Hello from django-structlog!")
Debug
Known issues
breakingFor `django-structlog` v10.0.0+, the `RequestMiddleware` now relies on the `django.dispatch.signal.got_request_exception` signal for exception handling, rather than the older `process_exception` middleware method. This change primarily affects how unhandled exceptions are intercepted and may impact custom exception handling logic.
fix
Review custom exception handling within middleware or signal receivers to ensure compatibility with the new `got_request_exception` signal mechanism.
affects: 10.0.0+
breakingWhen upgrading to `django-structlog` v8.0.0+, the optional signals (`bind_extra_request_metadata`, `bind_extra_request_finished_metadata`, `bind_extra_request_failed_metadata`) now include a new `log_kwargs` argument. If your signal receivers do not accept `**kwargs`, you will need to update their signatures to include `log_kwargs` if you intend to modify the log metadata.
fix
Update signal receiver functions to accept `log_kwargs` (e.g., `def my_receiver(request, logger, log_kwargs, **kwargs):`).
affects: 8.0.0+
breakingFrom `django-structlog` v3.0.0+ onwards, the library transitioned from `structlog.threadlocal` to `structlog.contextvars`. This requires updating your `structlog.configure()` settings to include `structlog.contextvars.merge_contextvars` as the first processor and removing `context_class=structlog.threadlocal.wrap_dict(dict)`. Additionally, all calls to `logger.bind()` should be replaced with `structlog.contextvars.bind_contextvars()`.
fix
Update `structlog.configure` processors and replace `logger.bind` calls with `structlog.contextvars.bind_contextvars`. Consult the upgrade guide for detailed instructions.
affects: 3.0.0+
breakingWith `django-structlog` v7.0.0+, the `django-ipware` dependency was upgraded to version 6. If you have custom configurations or rely on specific behaviors of `django-ipware` versions prior to 6, this upgrade may introduce breaking changes. Most users should not be affected, but customizations may require adjustments.
fix
Review `django-ipware`'s changelog for version 6 and adjust any custom IP address retrieval or handling logic if necessary.
affects: 7.0.0+
gotchaWhen using Django REST Framework's `TokenAuthentication` (or similar DRF authentications), the `user_id` may only be present in `request_finished` and `request_failed` log events, rather than in every log produced during the request.
fix
If `user_id` is critical for all logs within a DRF authenticated request, consider explicitly binding it early in the request lifecycle using a custom signal receiver for `django_structlog.signals.bind_extra_request_metadata` or a custom middleware.
affects: All
gotchaIntegrating with Celery requires additional configuration beyond the basic `django-structlog` setup. Simply installing `django-structlog[celery]` is not sufficient; specific settings for Celery task logging need to be applied as detailed in the documentation.
fix
Refer to the 'Celery Integration' section in the official `django-structlog` documentation for complete setup instructions and recommended configurations.
affects: All
Errors
Common errors & fixes
ModuleNotFoundError: No module named 'structlog'
The core 'structlog' library, which 'django-structlog' depends on, has not been installed in the Python environment.
fix
Install the 'structlog' library using pip: `pip install structlog`.
django-structlog is not printing or writing log message to console or file
This commonly occurs when the logging configuration in Django's `settings.py` has incorrect logger names or log levels that filter out messages, or `disable_existing_loggers` is set to `True` without proper re-configuration. A frequent mistake is not renaming a demo logger (e.g., 'django_structlog_demo_project') to your actual application's logger name or a global root logger.
fix
Ensure your `LOGGING` dictionary in `settings.py` includes a logger for your application (e.g., `""` for the root logger or your specific app name) with the desired `level` (e.g., `DEBUG` or `INFO`), and set `disable_existing_loggers: False` if you intend to integrate with existing Django loggers. For example: `LOGGING = {..., 'loggers': {'': {'handlers': ['console'], 'level': 'INFO', 'propagate': True}, ...}}`.
AttributeError: 'PrintLogger' object has no attribute 'setLevel'
This error typically indicates that `structlog.configure()` was called too late, after a logger had already been implicitly created by `structlog.get_logger()` without proper configuration. This results in the default `structlog.PrintLogger` being used, which does not support standard `logging` module methods like `setLevel`.
fix
Ensure that `structlog.configure()` is called before any `structlog.get_logger()` calls are made in your application, ideally at the very end of your `settings.py` file, and that it correctly specifies `logger_factory=structlog.stdlib.LoggerFactory()` if you intend to integrate with Python's standard logging library.
Request-specific metadata (request_id, user_id) missing from logs
The `django_structlog.middlewares.RequestMiddleware` is either not added to the `MIDDLEWARE` list in your Django `settings.py` or is placed incorrectly, preventing it from binding request-specific context to the logger.
fix
Add `'django_structlog.middlewares.RequestMiddleware'` to your `MIDDLEWARE` list in `settings.py`. For `user_id` to be bound, ensure it's placed after `django.contrib.sessions.middleware.SessionMiddleware` and `django.contrib.auth.middleware.AuthenticationMiddleware`.
logger.bind(...) context not appearing in logs after upgrade
After upgrading `django-structlog` (especially to versions 3.0.0 and above), the library switched from `structlog.threadlocal` to `structlog.contextvars`. Code still using `logger.bind()` (which often implicitly relied on `threadlocal`) will not correctly bind context variables with the new `contextvars` mechanism.
fix
Replace calls to `logger.bind(...)` with `structlog.contextvars.bind_contextvars(...)` for setting context. Additionally, ensure `structlog.contextvars.merge_contextvars` is included as the first processor in your `structlog.configure()` call to ensure context variables are properly merged into log events.
Upgrade
Version history
10.1.0latest on PyPI · released May 30, 2026
Audit
Dependencies
structlogrequiredCore dependency for structured logging functionality.
DjangorequiredRequires Django 5.1+ for version 10.0.0. Previous versions required Django 3.2+ or higher.
celeryoptionalOptional dependency for structured logging integration with Celery tasks.
django-ipwarerequiredUsed internally to retrieve IP addresses; version 6+ is required for django-structlog 7.0+.
Agent activity
15 hits · last 30 days
node
12
OpenAI (training)
2
Resources
django-structlog — pip install django-structlog · libregistry