{"id":13625092,"url":"https://github.com/jrobichaud/django-structlog","last_synced_at":"2025-04-16T06:31:42.274Z","repository":{"id":34560945,"uuid":"180026172","full_name":"jrobichaud/django-structlog","owner":"jrobichaud","description":"Structured Logging for Django","archived":false,"fork":false,"pushed_at":"2024-04-08T11:39:58.000Z","size":4172,"stargazers_count":383,"open_issues_count":0,"forks_count":32,"subscribers_count":6,"default_branch":"main","last_synced_at":"2024-04-09T12:38:32.843Z","etag":null,"topics":["celery","django","django-rest-framework","hacktoberfest","logging","structlog","structured-logging"],"latest_commit_sha":null,"homepage":"https://django-structlog.readthedocs.io/en/latest/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jrobichaud.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.rst","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2019-04-07T21:29:34.000Z","updated_at":"2024-04-15T12:29:14.047Z","dependencies_parsed_at":"2024-02-12T12:30:23.503Z","dependency_job_id":"cb3e56e6-6c0a-46f6-8ff8-c37432448ee6","html_url":"https://github.com/jrobichaud/django-structlog","commit_stats":null,"previous_names":[],"tags_count":66,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jrobichaud%2Fdjango-structlog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jrobichaud%2Fdjango-structlog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jrobichaud%2Fdjango-structlog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jrobichaud%2Fdjango-structlog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jrobichaud","download_url":"https://codeload.github.com/jrobichaud/django-structlog/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223700218,"owners_count":17188269,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["celery","django","django-rest-framework","hacktoberfest","logging","structlog","structured-logging"],"created_at":"2024-08-01T21:01:50.744Z","updated_at":"2025-04-16T06:31:42.267Z","avatar_url":"https://github.com/jrobichaud.png","language":"Python","readme":".. inclusion-marker-introduction-begin\n\ndjango-structlog\n================\n\n| |pypi| |wheels| |build-status| |docs| |coverage| |open_issues| |pull_requests|\n| |django| |python| |license| |black| |ruff|\n| |django_packages|\n| |watchers| |stars| |forks|\n\n\n.. |django_packages| image:: https://img.shields.io/badge/Published%20on-Django%20Packages-0c3c26\n   :target: https://djangopackages.org/packages/p/django-structlog/\n   :alt: Published on Django Packages\n\n.. |build-status| image:: https://github.com/jrobichaud/django-structlog/actions/workflows/main.yml/badge.svg?branch=main\n   :target: https://github.com/jrobichaud/django-structlog/actions\n   :alt: Build Status\n\n.. |pypi| image:: https://img.shields.io/pypi/v/django-structlog.svg\n   :target: https://pypi.org/project/django-structlog/\n   :alt: PyPI version\n\n.. |docs| image:: https://readthedocs.org/projects/django-structlog/badge/?version=latest\n   :target: https://django-structlog.readthedocs.io/en/latest/?badge=latest\n   :alt: Documentation Status\n\n.. |coverage| image:: https://img.shields.io/codecov/c/github/jrobichaud/django-structlog.svg\n   :target: https://codecov.io/gh/jrobichaud/django-structlog\n   :alt: codecov\n\n.. |python| image:: https://img.shields.io/pypi/pyversions/django-structlog.svg\n    :target: https://pypi.org/project/django-structlog/\n    :alt: Supported Python versions\n\n.. |license| image:: https://img.shields.io/pypi/l/django-structlog.svg\n    :target: https://github.com/jrobichaud/django-structlog/blob/main/LICENSE.rst\n    :alt: License\n\n.. |open_issues| image:: https://img.shields.io/github/issues/jrobichaud/django-structlog.svg\n    :target: https://github.com/jrobichaud/django-structlog/issues\n    :alt: GitHub issues\n\n.. |django| image:: https://img.shields.io/pypi/djversions/django-structlog.svg\n    :target: https://pypi.org/project/django-structlog/\n    :alt: PyPI - Django Version\n\n.. |pull_requests| image:: https://img.shields.io/github/issues-pr/jrobichaud/django-structlog.svg\n    :target: https://github.com/jrobichaud/django-structlog/pulls\n    :alt: GitHub pull requests\n\n.. |forks| image:: https://img.shields.io/github/forks/jrobichaud/django-structlog.svg?style=social\n    :target: https://github.com/jrobichaud/django-structlog/\n    :alt: GitHub forks\n\n.. |stars| image:: https://img.shields.io/github/stars/jrobichaud/django-structlog.svg?style=social\n    :target: https://github.com/jrobichaud/django-structlog/\n    :alt: GitHub stars\n\n.. |watchers| image:: https://img.shields.io/github/watchers/jrobichaud/django-structlog.svg?style=social\n    :target: https://github.com/jrobichaud/django-structlog/\n    :alt: GitHub watchers\n\n.. |wheels| image:: https://img.shields.io/pypi/wheel/django-structlog.svg\n    :target: https://pypi.org/project/django-structlog/\n    :alt: PyPI - Wheel\n\n.. |black| image:: https://img.shields.io/badge/code%20style-black-000000.svg\n    :target: https://github.com/python/black\n    :alt: Black\n\n.. |ruff| image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json\n    :target: https://github.com/astral-sh/ruff\n    :alt: Ruff\n\ndjango-structlog is a structured logging integration for `Django \u003chttps://www.djangoproject.com/\u003e`_ project using `structlog \u003chttps://www.structlog.org/\u003e`_\n\nLogging will then produce additional cohesive metadata on each logs that makes it easier to track events or incidents.\n\n\nAdditional Popular Integrations\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n`Django REST framework \u003chttps://www.django-rest-framework.org/\u003e`_\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n``Django REST framework`` is supported by default. But when using it with ``rest_framework.authentication.TokenAuthentication`` (or other DRF authentications)  ``user_id`` will be only be in ``request_finished`` and ``request_failed`` instead of each logs.\n\nSee `#37  \u003chttps://github.com/jrobichaud/django-structlog/issues/37\u003e`_ for details.\n\n\n`django-ninja \u003chttps://django-ninja.dev/\u003e`_\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n``django-ninja`` is supported by default 🥷.\n\n\n`Celery \u003chttp://www.celeryproject.org/\u003e`_\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nCelery's task logging requires additional configurations, see `documentation \u003chttps://django-structlog.readthedocs.io/en/latest/celery.html\u003e`_ for details.\n\n\nLogging comparison\n^^^^^^^^^^^^^^^^^^\n\nStandard logging:\n~~~~~~~~~~~~~~~~~\n\n.. code-block:: python\n\n   \u003e\u003e\u003e import logging\n   \u003e\u003e\u003e logger = logging.get_logger(__name__)\n   \u003e\u003e\u003e logger.info(\"An error occurred\")\n\n.. code-block:: bash\n\n   An error occurred\n\nWell... ok\n\nWith django-structlog and flat_line:\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. code-block:: python\n\n   \u003e\u003e\u003e import structlog\n   \u003e\u003e\u003e logger = structlog.get_logger(__name__)\n   \u003e\u003e\u003e logger.info(\"an_error_occurred\", bar=\"Buz\")\n\n.. code-block:: bash\n\n   timestamp='2019-04-13T19:39:31.089925Z' level='info' event='an_error_occurred' logger='my_awesome_project.my_awesome_module' request_id='3a8f801c-072b-4805-8f38-e1337f363ed4' user_id=1 ip='0.0.0.0' bar='Buz'\n\nThen you can search with commands like:\n\n.. code-block:: bash\n\n   $ cat logs/flat_line.log | grep request_id='3a8f801c-072b-4805-8f38-e1337f363ed4'\n\nWith django-structlog and json\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. code-block:: python\n\n   \u003e\u003e\u003e import structlog\n   \u003e\u003e\u003e logger = structlog.get_logger(__name__)\n   \u003e\u003e\u003e logger.info(\"an_error_occurred\", bar=\"Buz\")\n\n.. code-block:: json\n\n   {\"request_id\": \"3a8f801c-072b-4805-8f38-e1337f363ed4\", \"user_id\": 1, \"ip\": \"0.0.0.0\", \"event\": \"an_error_occurred\", \"timestamp\": \"2019-04-13T19:39:31.089925Z\", \"logger\": \"my_awesome_project.my_awesome_module\", \"level\": \"info\", \"bar\": \"Buz\"}\n\nThen you can search with commands like:\n\n.. code-block:: bash\n\n   $ cat logs/json.log | jq '.[] | select(.request_id=\"3a8f801c-072b-4805-8f38-e1337f363ed4\")' -s\n\n.. inclusion-marker-introduction-end\n\n.. inclusion-marker-getting-started-begin\n\nGetting Started\n===============\n\nThese steps will show how to integrate the middleware to your awesome application.\n\nInstallation\n^^^^^^^^^^^^\n\nInstall the library\n\n.. code-block:: bash\n\n   pip install django-structlog\n\nAdd app\n\n.. code-block:: python\n\n   INSTALLED_APP = [\n       # ...\n       \"django_structlog\",\n       # ...\n   ]\n\nAdd middleware\n\n.. code-block:: python\n\n   MIDDLEWARE = [\n       # ...\n       \"django_structlog.middlewares.RequestMiddleware\",\n   ]\n\nAdd appropriate structlog configuration to your ``settings.py``\n\n.. code-block:: python\n\n   import structlog\n\n   LOGGING = {\n       \"version\": 1,\n       \"disable_existing_loggers\": False,\n       \"formatters\": {\n           \"json_formatter\": {\n               \"()\": structlog.stdlib.ProcessorFormatter,\n               \"processor\": structlog.processors.JSONRenderer(),\n           },\n           \"plain_console\": {\n               \"()\": structlog.stdlib.ProcessorFormatter,\n               \"processor\": structlog.dev.ConsoleRenderer(),\n           },\n           \"key_value\": {\n               \"()\": structlog.stdlib.ProcessorFormatter,\n               \"processor\": structlog.processors.KeyValueRenderer(key_order=['timestamp', 'level', 'event', 'logger']),\n           },\n       },\n       \"handlers\": {\n           # Important notes regarding handlers.\n           #\n           # 1. Make sure you use handlers adapted for your project.\n           # These handlers configurations are only examples for this library.\n           # See python's logging.handlers: https://docs.python.org/3/library/logging.handlers.html\n           #\n           # 2. You might also want to use different logging configurations depending of the environment.\n           # Different files (local.py, tests.py, production.py, ci.py, etc.) or only conditions.\n           # See https://docs.djangoproject.com/en/dev/topics/settings/#designating-the-settings\n           \"console\": {\n               \"class\": \"logging.StreamHandler\",\n               \"formatter\": \"plain_console\",\n           },\n           \"json_file\": {\n               \"class\": \"logging.handlers.WatchedFileHandler\",\n               \"filename\": \"logs/json.log\",\n               \"formatter\": \"json_formatter\",\n           },\n           \"flat_line_file\": {\n               \"class\": \"logging.handlers.WatchedFileHandler\",\n               \"filename\": \"logs/flat_line.log\",\n               \"formatter\": \"key_value\",\n           },\n       },\n       \"loggers\": {\n           \"django_structlog\": {\n               \"handlers\": [\"console\", \"flat_line_file\", \"json_file\"],\n               \"level\": \"INFO\",\n           },\n           # Make sure to replace the following logger's name for yours\n           \"django_structlog_demo_project\": {\n               \"handlers\": [\"console\", \"flat_line_file\", \"json_file\"],\n               \"level\": \"INFO\",\n           },\n       }\n   }\n\n   structlog.configure(\n       processors=[\n           structlog.contextvars.merge_contextvars,\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\nStart logging with ``structlog`` instead of ``logging``.\n\n.. code-block:: python\n\n   import structlog\n   logger = structlog.get_logger(__name__)\n\n.. _django_signals:\n\nExtending Request Log Metadata\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nBy default only a ``request_id`` and the ``user_id`` are bound from the request but pertinent log metadata may vary from a project to another.\n\nIf you need to add more metadata from the request you can implement a convenient signal receiver to bind them. You can also override existing bound metadata the same way.\n\n.. code-block:: python\n\n    from django.contrib.sites.shortcuts import get_current_site\n    from django.dispatch import receiver\n    from django_structlog import signals\n    import structlog\n\n\n    @receiver(signals.bind_extra_request_metadata)\n    def bind_domain(request, logger, **kwargs):\n        current_site = get_current_site(request)\n        structlog.contextvars.bind_contextvars(domain=current_site.domain)\n\n\nStandard Loggers\n^^^^^^^^^^^^^^^^\n\nIt is also possible to log using standard python logger.\n\nIn your formatters, add the ``foreign_pre_chain`` section, and then add ``structlog.contextvars.merge_contextvars``:\n\n.. code-block:: python\n\n   LOGGING = {\n       \"version\": 1,\n       \"disable_existing_loggers\": False,\n       \"formatters\": {\n           \"json_formatter\": {\n               \"()\": structlog.stdlib.ProcessorFormatter,\n               \"processor\": structlog.processors.JSONRenderer(),\n               # Add this section:\n               \"foreign_pre_chain\": [\n                   structlog.contextvars.merge_contextvars, # \u003c---- add this\n                   # customize the rest as you need\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       ...\n    }\n\n\n.. inclusion-marker-getting-started-end\n\n\n.. inclusion-marker-example-outputs-begin\n\nExample outputs\n===============\n\nFlat lines file (\\ ``logs/flat_lines.log``\\ )\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n.. code-block:: bash\n\n   timestamp='2019-04-13T19:39:29.321453Z' level='info' event='request_started' logger='django_structlog.middlewares.request' request_id='c53dff1d-3fc5-4257-a78a-9a567c937561' user_id=1 ip='0.0.0.0' request=GET / user_agent='Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'\n   timestamp='2019-04-13T19:39:29.345207Z' level='info' event='request_finished' logger='django_structlog.middlewares.request' request_id='c53dff1d-3fc5-4257-a78a-9a567c937561' user_id=1 ip='0.0.0.0' code=200\n   timestamp='2019-04-13T19:39:31.086155Z' level='info' event='request_started' logger='django_structlog.middlewares.request' request_id='3a8f801c-072b-4805-8f38-e1337f363ed4' user_id=1 ip='0.0.0.0' request=POST /success_task user_agent='Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'\n   timestamp='2019-04-13T19:39:31.089925Z' level='info' event='Enqueuing successful task' logger='django_structlog_demo_project.home.views' request_id='3a8f801c-072b-4805-8f38-e1337f363ed4' user_id=1 ip='0.0.0.0'\n   timestamp='2019-04-13T19:39:31.147590Z' level='info' event='task_enqueued' logger='django_structlog.middlewares.celery' request_id='3a8f801c-072b-4805-8f38-e1337f363ed4' user_id=1 ip='0.0.0.0' child_task_id='6b11fd80-3cdf-4de5-acc2-3fd4633aa654'\n   timestamp='2019-04-13T19:39:31.153081Z' level='info' event='This is a successful task' logger='django_structlog_demo_project.taskapp.celery' task_id='6b11fd80-3cdf-4de5-acc2-3fd4633aa654' request_id='3a8f801c-072b-4805-8f38-e1337f363ed4' user_id=1 ip='0.0.0.0'\n   timestamp='2019-04-13T19:39:31.160043Z' level='info' event='request_finished' logger='django_structlog.middlewares.request' request_id='3a8f801c-072b-4805-8f38-e1337f363ed4' user_id=1 ip='0.0.0.0' code=201\n   timestamp='2019-04-13T19:39:31.162372Z' level='info' event='task_succeed' logger='django_structlog.middlewares.celery' task_id='6b11fd80-3cdf-4de5-acc2-3fd4633aa654' request_id='3a8f801c-072b-4805-8f38-e1337f363ed4' user_id=1 ip='0.0.0.0' result='None'\n\nJson file (\\ ``logs/json.log``\\ )\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n.. code-block:: json\n\n   {\"request_id\": \"c53dff1d-3fc5-4257-a78a-9a567c937561\", \"user_id\": 1, \"ip\": \"0.0.0.0\", \"request\": \"GET /\", \"user_agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36\", \"event\": \"request_started\", \"timestamp\": \"2019-04-13T19:39:29.321453Z\", \"logger\": \"django_structlog.middlewares.request\", \"level\": \"info\"}\n   {\"request_id\": \"c53dff1d-3fc5-4257-a78a-9a567c937561\", \"user_id\": 1, \"ip\": \"0.0.0.0\", \"code\": 200, \"event\": \"request_finished\", \"timestamp\": \"2019-04-13T19:39:29.345207Z\", \"logger\": \"django_structlog.middlewares.request\", \"level\": \"info\"}\n   {\"request_id\": \"3a8f801c-072b-4805-8f38-e1337f363ed4\", \"user_id\": 1, \"ip\": \"0.0.0.0\", \"request\": \"POST /success_task\", \"user_agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36\", \"event\": \"request_started\", \"timestamp\": \"2019-04-13T19:39:31.086155Z\", \"logger\": \"django_structlog.middlewares.request\", \"level\": \"info\"}\n   {\"request_id\": \"3a8f801c-072b-4805-8f38-e1337f363ed4\", \"user_id\": 1, \"ip\": \"0.0.0.0\", \"event\": \"Enqueuing successful task\", \"timestamp\": \"2019-04-13T19:39:31.089925Z\", \"logger\": \"django_structlog_demo_project.home.views\", \"level\": \"info\"}\n   {\"request_id\": \"3a8f801c-072b-4805-8f38-e1337f363ed4\", \"user_id\": 1, \"ip\": \"0.0.0.0\", \"child_task_id\": \"6b11fd80-3cdf-4de5-acc2-3fd4633aa654\", \"event\": \"task_enqueued\", \"timestamp\": \"2019-04-13T19:39:31.147590Z\", \"logger\": \"django_structlog.middlewares.celery\", \"level\": \"info\"}\n   {\"task_id\": \"6b11fd80-3cdf-4de5-acc2-3fd4633aa654\", \"request_id\": \"3a8f801c-072b-4805-8f38-e1337f363ed4\", \"user_id\": 1, \"ip\": \"0.0.0.0\", \"event\": \"This is a successful task\", \"timestamp\": \"2019-04-13T19:39:31.153081Z\", \"logger\": \"django_structlog_demo_project.taskapp.celery\", \"level\": \"info\"}\n   {\"request_id\": \"3a8f801c-072b-4805-8f38-e1337f363ed4\", \"user_id\": 1, \"ip\": \"0.0.0.0\", \"code\": 201, \"event\": \"request_finished\", \"timestamp\": \"2019-04-13T19:39:31.160043Z\", \"logger\": \"django_structlog.middlewares.request\", \"level\": \"info\"}\n   {\"task_id\": \"6b11fd80-3cdf-4de5-acc2-3fd4633aa654\", \"request_id\": \"3a8f801c-072b-4805-8f38-e1337f363ed4\", \"user_id\": 1, \"ip\": \"0.0.0.0\", \"result\": \"None\", \"event\": \"task_succeed\", \"timestamp\": \"2019-04-13T19:39:31.162372Z\", \"logger\": \"django_structlog.middlewares.celery\", \"level\": \"info\"}\n\n.. inclusion-marker-example-outputs-end\n\n.. inclusion-marker-upgrade-guide-begin\n\nUpgrade Guide\n=============\n\n.. _upgrade_9.0:\n\nUpgrading to 9.0+\n^^^^^^^^^^^^^^^^^\n\nMinimum requirements\n~~~~~~~~~~~~~~~~~~~~\n- requires python 3.9+\n- django 4.2 and 5.0+ are supported\n\n\nType hints\n~~~~~~~~~~\n\n``django-structlog`` now uses `python type hints \u003chttps://docs.python.org/3/library/typing.html\u003e`_ and is being validated with `mypy \u003chttps://mypy.readthedocs.io/en/stable/\u003e`_ ``--strict``.\n\n\nFor ``drf-standardized-errors`` users\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nNow unhandled exceptions when using `drf-standardized-errors \u003chttps://github.com/ghazi-git/drf-standardized-errors\u003e`_ will be intercepted and the exception logged properly.\n\nIf you also use `structlog-sentry \u003chttps://github.com/kiwicom/structlog-sentry\u003e`_, the exception will now be propagated as expected.\n\nOther libraries alike may be affected by this change.\n\nInternal changes in how ``RequestMiddleware`` handles exceptions\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThis only affects you if you implemented a middleware inheriting from ``RequestMiddleware`` and you overrode the ``process_exception`` method.\n\nDid you?\n\nIf so:\n\n   - ``RequestMiddleware.process_exception`` was renamed to ``RequestMiddleware._process_exception``, you should to the same in the middleware.\n\n\n.. _upgrade_8.0:\n\nUpgrading to 8.0+\n^^^^^^^^^^^^^^^^^\n\nA new keyword argument ``log_kwargs`` was added to the the optional signals:\n    - ``django_structlog.signals.bind_extra_request_metadata``;\n    - ``django_structlog.signals.bind_extra_request_finished_metadata``;\n    - ``django_structlog.signals.bind_extra_request_failed_metadata``.\n\nIt should not affect you if you have a ``**kwargs`` in the signature of your receivers.\n\n``log_kwargs`` is a dictionary containing the log metadata that will be added to their respective logs (``\"request_started\"``, ``\"request_finished\"``, ``\"request_failed\"``).\n\nIf you use any of these signals, you may need to update your receiver to accept this new argument:\n\n.. code-block:: python\n\n    from django.contrib.sites.shortcuts import get_current_site\n    from django.dispatch import receiver\n    from django_structlog import signals\n    import structlog\n\n    @receiver(signals.bind_extra_request_metadata)\n    def my_receiver(request, logger, log_kwargs, **kwargs): # \u003c- add `log_kwargs` if necessary\n        ...\n\n    @receiver(signals.bind_extra_request_finished_metadata)\n    def my_receiver_finished(request, logger, response, log_kwargs, **kwargs): # \u003c- add `log_kwargs` if necessary\n        ...\n\n    @receiver(signals.bind_extra_request_failed_metadata)\n    def my_receiver_failed(request, logger, exception, log_kwargs, **kwargs): # \u003c- add `log_kwargs` if necessary\n        ...\n\n\n.. _upgrade_7.0:\n\nUpgrading to 7.0+\n^^^^^^^^^^^^^^^^^\n\nThe dependency `django-ipware \u003chttps://github.com/un33k/django-ipware\u003e`_ was upgraded to version 6. This library is used to retrieve the request's ip address.\n\nVersion 6 may have some `breaking changes \u003chttps://github.com/un33k/django-ipware/compare/v5.0.2...v6.0.2#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5R97\u003e`_ if you did customizations.\n\nIt should not affect most of the users but if you did some customizations, you might need to update your configurations.\n\n.. _upgrade_6.0:\n\nUpgrading to 6.0+\n^^^^^^^^^^^^^^^^^\n\nMinimum requirements\n~~~~~~~~~~~~~~~~~~~~\n- requires python 3.8+\n\nChanges to do\n~~~~~~~~~~~~~\n\nAdd ``django_structlog`` to installed app\n-----------------------------------------\n.. code-block:: python\n\n   INSTALLED_APP = [\n       # ...\n       \"django_structlog\",\n       # ...\n   ]\n\n\nMake sure you use ``django_structlog.middlewares.RequestMiddleware``\n--------------------------------------------------------------------\n\nIf you used any of the experimental async or sync middlewares, you do not need to anymore.\nMake sure you use ``django_structlog.middlewares.RequestMiddleware`` instead of any of the other request middlewares commented below:\n\n.. code-block:: python\n\n    MIDDLEWARE += [\n        # \"django_structlog.middlewares.request_middleware_router\", # \u003c- remove\n        # \"django_structlog.middlewares.requests.SyncRequestMiddleware\", # \u003c- remove\n        # \"django_structlog.middlewares.requests.AsyncRequestMiddleware\", # \u003c- remove\n        \"django_structlog.middlewares.RequestMiddleware\", # \u003c- make sure you use this one\n    ]\n\n\n(If you use celery) Make sure you use ``DJANGO_STRUCTLOG_CELERY_ENABLED = True``\n--------------------------------------------------------------------------------\n\nIt is only applicable if you use celery integration.\n\n``django_structlog.middlewares.CeleryMiddleware`` has been remove in favor of a django settings.\n\n.. code-block:: python\n\n    MIDDLEWARE += [\n        \"django_structlog.middlewares.RequestMiddleware\",\n        # \"django_structlog.middlewares.CeleryMiddleware\",  # \u003c- remove this\n    ]\n\n    DJANGO_STRUCTLOG_CELERY_ENABLED = True # \u003c-- add this\n\n.. _upgrade_5.0:\n\nUpgrading to 5.0+\n^^^^^^^^^^^^^^^^^\n\nMinimum requirements\n~~~~~~~~~~~~~~~~~~~~\n- requires asgiref 3.6+\n\n.. _upgrade_4.0:\n\nUpgrading to 4.0+\n^^^^^^^^^^^^^^^^^\n\n``django-structlog`` drops support of django below 3.2.\n\nMinimum requirements\n~~~~~~~~~~~~~~~~~~~~\n- requires django 3.2+\n- requires python 3.7+\n- requires structlog 21.4.0+\n- (optionally) requires celery 5.1+\n\n\nChanges if you use ``celery``\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nYou can now install ``django-structlog`` explicitly with ``celery`` extra in order to validate the compatibility with your version of ``celery``.\n\n\n.. code-block:: bash\n\n    django-structlog[celery]==4.0.0\n\nSee `Installing “Extras” \u003chttps://packaging.python.org/en/latest/tutorials/installing-packages/#installing-extras\u003e`_ for more information about this ``pip`` feature.\n\n.. _upgrade_3.0:\n\nUpgrading to 3.0+\n^^^^^^^^^^^^^^^^^\n\n``django-structlog`` now use  `structlog.contextvars.bind_contextvars \u003chttps://www.structlog.org/en/stable/contextvars.html\u003e`_ instead of ``threadlocal``.\n\nMinimum requirements\n~~~~~~~~~~~~~~~~~~~~\n- requires python 3.7+\n- requires structlog 21.4.0+\n\n\nChanges you need to do\n~~~~~~~~~~~~~~~~~~~~~~\n\n1. Update structlog settings\n----------------------------\n\n- add ``structlog.contextvars.merge_contextvars`` as first ``processors``\n- remove ``context_class=structlog.threadlocal.wrap_dict(dict),``\n- (if you use standard loggers) add ``structlog.contextvars.merge_contextvars`` in `foreign_pre_chain`\n- (if you use standard loggers) remove ``django_structlog.processors.inject_context_dict,``\n\n\n.. code-block:: python\n\n   structlog.configure(\n       processors=[\n           structlog.contextvars.merge_contextvars, # \u003c---- add this\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       # context_class=structlog.threadlocal.wrap_dict(dict), # \u003c---- remove this\n       logger_factory=structlog.stdlib.LoggerFactory(),\n       cache_logger_on_first_use=True,\n   )\n\n   # If you use standard logging\n   LOGGING = {\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, # \u003c---- add this\n                   # django_structlog.processors.inject_context_dict, # \u003c---- remove this\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       ...\n    }\n\n\n2. Replace all ``logger.bind`` with ``structlog.contextvars.bind_contextvars``\n------------------------------------------------------------------------------\n\n.. code-block:: python\n\n    @receiver(bind_extra_request_metadata)\n    def bind_domain(request, logger, **kwargs):\n        current_site = get_current_site(request)\n        # logger.bind(domain=current_site.domain)\n        structlog.contextvars.bind_contextvars(domain=current_site.domain)\n\n.. _upgrade_2.0:\n\nUpgrading to 2.0+\n^^^^^^^^^^^^^^^^^\n\n``django-structlog`` was originally developed using the debug configuration `ExceptionPrettyPrinter \u003chttps://www.structlog.org/en/stable/api.html#structlog.processors.ExceptionPrettyPrinter\u003e`_ which led to incorrect handling of exception.\n\n- remove ``structlog.processors.ExceptionPrettyPrinter(),`` of your processors.\n- make sure you have ``structlog.processors.format_exc_info,`` in your processors if you want appropriate exception logging.\n\n.. inclusion-marker-upgrade-guide-end\n\n.. inclusion-marker-running-tests-begin\n\nRunning the tests\n=================\n\nNote: For the moment redis is needed to run the tests. The easiest way is to start docker demo's redis.\n\n.. code-block:: bash\n\n   docker compose up -d redis\n   pip install -r requirements.txt\n   env CELERY_BROKER_URL=redis://0.0.0.0:6379 DJANGO_SETTINGS_MODULE=config.settings.test pytest test_app\n   env CELERY_BROKER_URL=redis://0.0.0.0:6379 DJANGO_SETTINGS_MODULE=config.settings.test_demo_app pytest django_structlog_demo_project\n   docker compose stop redis\n\n.. inclusion-marker-running-tests-end\n\n\n.. inclusion-marker-demo-begin\n\nDemo app\n========\n\n.. code-block:: bash\n\n   docker compose up --build\n\nOpen ``http://127.0.0.1:8000/`` in your browser.\n\nNavigate while looking into the log files and shell's output.\n\n.. inclusion-marker-demo-end\n\n\n.. inclusion-marker-authors-begin\n\nAuthors\n=======\n\n\n* **Jules Robichaud-Gagnon** - *Initial work* - `jrobichaud \u003chttps://github.com/jrobichaud\u003e`_\n\nSee also the list of `contributors \u003chttps://github.com/jrobichaud/django-structlog/contributors\u003e`_ who participated in this project.\n\n.. inclusion-marker-authors-end\n\n\n.. inclusion-marker-acknowledgements-begin\n\nAcknowledgments\n===============\n\n* Very huge thanks to my awesome 🦄 and generous employer `TLM 🩵💜❤️🧡💚🐈‍⬛ \u003chttps://tlmgo.com/en/\u003e`_ for letting me maintain this project on my work hours because it believes in open source.\n* Big thanks to `@ferd \u003chttps://github.com/ferd\u003e`_ for his `bad opinions \u003chttps://ferd.ca/erlang-otp-21-s-new-logger.html\u003e`_ that inspired the author enough to spend time on this library.\n* `This issue \u003chttps://github.com/hynek/structlog/issues/175\u003e`_ helped the author to figure out how to integrate ``structlog`` in Django.\n* `This stack overflow question \u003chttps://stackoverflow.com/questions/43855507/configuring-and-using-structlog-with-django\u003e`_ was also helpful.\n\n.. inclusion-marker-acknowledgements-end\n\nLicense\n=======\n\nThis project is licensed under the MIT License - see the `LICENSE \u003chttps://github.com/jrobichaud/django-structlog/blob/main/LICENSE.rst\u003e`_ file for details\n","funding_links":[],"categories":["Python","Third-Party Packages"],"sub_categories":["Logging"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjrobichaud%2Fdjango-structlog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjrobichaud%2Fdjango-structlog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjrobichaud%2Fdjango-structlog/lists"}