{"id":2483,"library":"django-structlog","title":"django-structlog","description":"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.","status":"active","version":"10.0.0","language":"en","source_language":"en","source_url":"https://github.com/jrobichaud/django-structlog","tags":["django","logging","structured logging","structlog","celery"],"install":[{"cmd":"pip install django-structlog","lang":"bash","label":"Basic Installation"},{"cmd":"pip install django-structlog[celery]","lang":"bash","label":"With Celery Integration"}],"dependencies":[{"reason":"Core dependency for structured logging functionality.","package":"structlog","optional":false},{"reason":"Requires Django 5.1+ for version 10.0.0. Previous versions required Django 3.2+ or higher.","package":"Django","optional":false},{"reason":"Optional dependency for structured logging integration with Celery tasks.","package":"celery","optional":true},{"reason":"Used internally to retrieve IP addresses; version 6+ is required for django-structlog 7.0+.","package":"django-ipware","optional":false}],"imports":[{"note":"This is the primary way to obtain a logger for structured logging.","symbol":"get_logger","correct":"import structlog\nlogger = structlog.get_logger(__name__)"},{"note":"The middleware class name is `RequestMiddleware`, not `StructlogMiddleware`.","wrong":"'django_structlog.middlewares.StructlogMiddleware'","symbol":"RequestMiddleware","correct":"from django_structlog.middlewares import RequestMiddleware"},{"note":"Since v3.0+, `django-structlog` uses `structlog.contextvars.bind_contextvars` instead of `logger.bind` to manage context variables.","wrong":"logger.bind(user_id=request.user.id)","symbol":"bind_contextvars","correct":"from structlog import contextvars\ncontextvars.bind_contextvars(user_id=request.user.id)"}],"quickstart":{"code":"import structlog\n\n# settings.py\n\nINSTALLED_APPS = [\n    # ...\n    \"django_structlog\",\n    # ...\n]\n\nMIDDLEWARE = [\n    # ...\n    \"django_structlog.middlewares.RequestMiddleware\",\n    # ...\n]\n\nLOGGING = {\n    \"version\": 1,\n    \"disable_existing_loggers\": False,\n    \"formatters\": {\n        \"json_formatter\": {\n            \"()\": structlog.stdlib.ProcessorFormatter,\n            \"processor\": structlog.processors.JSONRenderer(),\n            \"foreign_pre_chain\": [\n                structlog.contextvars.merge_contextvars,\n                structlog.processors.TimeStamper(fmt=\"iso\"),\n                structlog.stdlib.add_logger_name,\n                structlog.stdlib.add_log_level,\n                structlog.stdlib.PositionalArgumentsFormatter(),\n            ],\n        },\n        \"plain_console\": {\n            \"()\": structlog.stdlib.ProcessorFormatter,\n            \"processor\": structlog.dev.ConsoleRenderer(),\n            \"foreign_pre_chain\": [\n                structlog.contextvars.merge_contextvars,\n                structlog.processors.TimeStamper(fmt=\"iso\"),\n                structlog.stdlib.add_logger_name,\n                structlog.stdlib.add_log_level,\n                structlog.stdlib.PositionalArgumentsFormatter(),\n            ],\n        },\n    },\n    \"handlers\": {\n        \"console\": {\n            \"class\": \"logging.StreamHandler\",\n            \"formatter\": \"plain_console\",\n        },\n        \"json_file\": {\n            \"class\": \"logging.handlers.RotatingFileHandler\",\n            \"filename\": \"logs/json.log\",\n            \"maxBytes\": 1024 * 1024 * 5,  # 5 MB\n            \"backupCount\": 5,\n            \"formatter\": \"json_formatter\",\n        },\n    },\n    \"loggers\": {\n        \"django_structlog\": {\n            \"handlers\": [\"console\", \"json_file\"],\n            \"level\": \"INFO\",\n            \"propagate\": False,\n        },\n        \"django\": {\n            \"handlers\": [\"console\", \"json_file\"],\n            \"level\": \"INFO\",\n            \"propagate\": False,\n        },\n        \"my_app\": { # Example for your application logs\n            \"handlers\": [\"console\", \"json_file\"],\n            \"level\": \"DEBUG\",\n            \"propagate\": False,\n        },\n        \"root\": {\n            \"handlers\": [\"console\", \"json_file\"],\n            \"level\": \"INFO\",\n        },\n    },\n}\n\nstructlog.configure(\n    processors=[\n        structlog.contextvars.merge_contextvars, # MUST be the first processor\n        structlog.stdlib.filter_by_level,\n        structlog.processors.TimeStamper(fmt=\"iso\"),\n        structlog.stdlib.add_logger_name,\n        structlog.stdlib.add_log_level,\n        structlog.stdlib.PositionalArgumentsFormatter(),\n        structlog.processors.StackInfoRenderer(),\n        structlog.processors.format_exc_info,\n        structlog.processors.UnicodeDecoder(),\n        structlog.stdlib.ProcessorFormatter.wrap_for_formatter,\n    ],\n    logger_factory=structlog.stdlib.LoggerFactory(),\n    cache_logger_on_first_use=True,\n)\n\n# views.py (example usage)\nimport structlog\nfrom django.http import HttpResponse\n\nlogger = structlog.get_logger(__name__)\n\ndef my_view(request):\n    logger.info(\"request_received\", path=request.path, method=request.method)\n    # Your view logic\n    return HttpResponse(\"Hello from django-structlog!\")\n","lang":"python","description":"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."},"warnings":[{"fix":"Review custom exception handling within middleware or signal receivers to ensure compatibility with the new `got_request_exception` signal mechanism.","message":"For `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.","severity":"breaking","affected_versions":"10.0.0+"},{"fix":"Update signal receiver functions to accept `log_kwargs` (e.g., `def my_receiver(request, logger, log_kwargs, **kwargs):`).","message":"When 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.","severity":"breaking","affected_versions":"8.0.0+"},{"fix":"Update `structlog.configure` processors and replace `logger.bind` calls with `structlog.contextvars.bind_contextvars`. Consult the upgrade guide for detailed instructions.","message":"From `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()`.","severity":"breaking","affected_versions":"3.0.0+"},{"fix":"Review `django-ipware`'s changelog for version 6 and adjust any custom IP address retrieval or handling logic if necessary.","message":"With `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.","severity":"breaking","affected_versions":"7.0.0+"},{"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.","message":"When 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.","severity":"gotcha","affected_versions":"All"},{"fix":"Refer to the 'Celery Integration' section in the official `django-structlog` documentation for complete setup instructions and recommended configurations.","message":"Integrating 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.","severity":"gotcha","affected_versions":"All"}],"env_vars":null,"last_verified":"2026-04-10T00:00:00.000Z","next_check":"2026-07-09T00:00:00.000Z"}