Skip to content

Commit

Permalink
Add log_kwargs to bind_extra_task_metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
jrobichaud committed Mar 14, 2024
1 parent 19fd934 commit 28332cf
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 14 deletions.
24 changes: 24 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,30 @@ Json file (\ ``logs/json.log``\ )
Upgrade Guide
=============

.. _upgrade_8.0:

Upgrading to 8.0+
^^^^^^^^^^^^^^^^^

The optional :class:`django_structlog.signals.bind_extra_request_metadata` signal has now a new keyword argument ``log_kwargs``.

It should not affect you if you have a ``**kwargs`` in the signature of your receiver.

``log_kwargs`` is a dictionary containing the log metadata that will be added to the log ``"request_started"``.

If you use ``bind_extra_request_metadata`` signal, you will need to update your receiver to accept this new argument.

.. code-block:: python
from django.contrib.sites.shortcuts import get_current_site
from django.dispatch import receiver
from django_structlog import signals
import structlog
@receiver(signals.bind_extra_request_metadata)
def my_receiver(request, logger, log_kwargs, **kwargs): # <- add `log_kwargs` if needed
...
.. _upgrade_7.0:

Upgrading to 7.0+
Expand Down
2 changes: 1 addition & 1 deletion django_structlog/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@

name = "django_structlog"

VERSION = (7, 1, 0)
VERSION = (8, 0, 0)

__version__ = ".".join(str(v) for v in VERSION)
2 changes: 1 addition & 1 deletion django_structlog/celery/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
>>> import structlog
>>>
>>> @receiver(signals.bind_extra_task_metadata)
... def receiver_bind_extra_request_metadata(sender, signal, task=None, logger=None, **kwargs):
... def receiver_bind_extra_task_metadata(sender, signal, task=None, logger=None, **kwargs):
... structlog.contextvars.bind_contextvars(correlation_id=task.request.correlation_id)
"""
Expand Down
12 changes: 6 additions & 6 deletions django_structlog/middlewares/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,14 +146,14 @@ def prepare(self, request):
structlog.contextvars.bind_contextvars(correlation_id=correlation_id)
ip, _ = get_client_ip(request)
structlog.contextvars.bind_contextvars(ip=ip)
log_kwargs = {
"request": self.format_request(request),
"user_agent": request.META.get("HTTP_USER_AGENT"),
}
signals.bind_extra_request_metadata.send(
sender=self.__class__, request=request, logger=logger
)
logger.info(
"request_started",
request=self.format_request(request),
user_agent=request.META.get("HTTP_USER_AGENT"),
sender=self.__class__, request=request, logger=logger, log_kwargs=log_kwargs
)
logger.info("request_started", **log_kwargs)

@staticmethod
def format_request(request):
Expand Down
10 changes: 6 additions & 4 deletions django_structlog/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@
bind_extra_request_metadata = django.dispatch.Signal()
""" Signal to add extra ``structlog`` bindings from ``django``'s request.
:param logger: the logger to bind more metadata or override existing bound metadata
:param request: the request returned by the view
:param logger: the logger
:param log_kwargs: dictionary of log metadata for the ``request_started`` event. It contains ``request`` and ``user_agent`` keys. You may modify it to add extra information.
>>> from django.contrib.sites.shortcuts import get_current_site
>>> from django.dispatch import receiver
>>> from django_structlog import signals
>>> import structlog
>>>
>>> @receiver(signals.bind_extra_request_metadata)
... def bind_domain(request, logger, **kwargs):
... def bind_domain(request, logger, log_kwargs, **kwargs):
... current_site = get_current_site(request)
... structlog.contextvars.bind_contextvars(domain=current_site.domain)
Expand All @@ -21,7 +23,7 @@
bind_extra_request_finished_metadata = django.dispatch.Signal()
""" Signal to add extra ``structlog`` bindings from ``django``'s finished request and response.
:param logger: the logger to bind more metadata or override existing bound metadata
:param logger: the logger
:param response: the response resulting of the request
>>> from django.contrib.sites.shortcuts import get_current_site
Expand All @@ -39,7 +41,7 @@
bind_extra_request_failed_metadata = django.dispatch.Signal()
""" Signal to add extra ``structlog`` bindings from ``django``'s failed request and exception.
:param logger: the logger to bind more metadata or override existing bound metadata
:param logger: the logger
:param exception: the exception resulting of the request
>>> from django.contrib.sites.shortcuts import get_current_site
Expand Down
9 changes: 9 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
Change Log
==========

8.0.0 (March 13, 2024)
----------------------

See: :ref:`upgrade_8.0`

*New:*
- add ``log_kwargs`` to :class:`django_structlog.signals.bind_extra_request_metadata`. See `#484 <https://github.com/jrobichaud/django-structlog/issues/484>`_. Special thanks to `@shtoltz <https://github.com/shtoltz>`_.


7.1.0 (December 20, 2023)
-------------------------

Expand Down
23 changes: 21 additions & 2 deletions test_app/tests/middlewares/test_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,9 +318,15 @@ def get_response(_response):
def test_signal_bind_extra_request_metadata(self):
@receiver(bind_extra_request_metadata)
def receiver_bind_extra_request_metadata(
sender, signal, request=None, logger=None
sender,
signal,
request=None,
logger=None,
log_kwargs=None,
**kwargs,
):
current_site = get_current_site(request)
log_kwargs["request_started_log"] = "foo"
structlog.contextvars.bind_contextvars(domain=current_site.domain)

mock_response = Mock()
Expand All @@ -338,7 +344,11 @@ def get_response(_response):
request.user = mock_user

middleware = middlewares.RequestMiddleware(get_response)
middleware(request)

with self.assertLogs(
"django_structlog.middlewares.request", logging.INFO
) as django_structlog_results:
middleware(request)

self.assertEqual(1, len(self.log_results.records))
record = self.log_results.records[0]
Expand All @@ -349,6 +359,15 @@ def get_response(_response):
self.assertIn("user_id", record.msg)
self.assertEqual(mock_user.id, record.msg["user_id"])

self.assertEqual(2, len(django_structlog_results.records))
record = django_structlog_results.records[0]
self.assertEqual("request_started", record.msg["event"])
self.assertEqual("foo", record.msg["request_started_log"])

record = django_structlog_results.records[1]
self.assertEqual("request_finished", record.msg["event"])
self.assertNotIn("request_started_log", record.msg)

def test_signal_bind_extra_request_finished_metadata(self):
mock_response = Mock()
mock_response.status_code = 200
Expand Down

0 comments on commit 28332cf

Please sign in to comment.