File: how_tos.rst

package info (click to toggle)
python-django-structlog 9.1.1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,004 kB
  • sloc: python: 3,509; sh: 206; javascript: 79; makefile: 19
file content (134 lines) | stat: -rw-r--r-- 4,739 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
.. _how_tos:

How Tos
=======

These are code snippets on how to achieve some specific use cases.

.. warning::
    Be aware they are untested. Please `open an issue <https://github.com/jrobichaud/django-structlog/issues/new?labels=how%20to>`_ if there are bugs in these examples or if you want to share some great examples that should be there.


Bind ``request_id`` to response's header
----------------------------------------

You can add the ``request_id`` to a custom response header ``X-Request-ID`` in order to trace the request by the caller.

Origin: `#231 <https://github.com/jrobichaud/django-structlog/issues/231>`_

.. code-block:: python

    from django.dispatch import receiver
    from django_structlog import signals
    import structlog


    @receiver(signals.update_failure_response)
    @receiver(signals.bind_extra_request_finished_metadata)
    def add_request_id_to_error_response(response, logger, **kwargs):
        context = structlog.contextvars.get_merged_contextvars(logger)
        response['X-Request-ID'] = context["request_id"]

Bind ``rest_framework_simplejwt`` token's user id
-------------------------------------------------

Bind token's user_id from `rest_framework_simplejwt <https://django-rest-framework-simplejwt.readthedocs.io/en/latest/>`_ to the request.

It is a workaround for ``restframework``'s non-standard authentication system.
It prevents access of the user in middlewares, therefore ``django-structlog`` cannot bind the ``user_id`` by default.

.. code-block:: python

    import structlog
    from django.dispatch import receiver
    from django_structlog.signals import bind_extra_request_metadata
    from rest_framework_simplejwt.tokens import UntypedToken

    @receiver(bind_extra_request_metadata)
    def bind_token_user_id(request, logger, **kwargs):
        try:
            header = request.META.get("HTTP_AUTHORIZATION")
            if header:
                raw_token = header.split()[1]
                token = UntypedToken(raw_token)
                user_id = token["user_id"]
                structlog.contextvars.bind_contextvars(user_id=user_id)
        except Exception:
            pass

Bind AWS's ``X-Amzn-Trace-Id``
------------------------------

See `Request tracing for your Application Load Balancer <https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-request-tracing.html>`_

Origin: `#324 <https://github.com/jrobichaud/django-structlog/issues/324>`_

.. code-block:: python

    from django.dispatch import receiver
    from django_structlog import signals
    from django_structlog.middlewares.request import get_request_header
    import structlog

    @receiver(signals.bind_extra_request_metadata)
    def bind_trace_id(request, logger, **kwargs):
        trace_id = get_request_header(
             request, "x-amzn-trace-id", "HTTP_X_AMZN_TRACE_ID"
        )
        if trace_id:
            structlog.contextvars.bind_contextvars(trace_id=trace_id)

Filter logs from being recorded
-------------------------------

You can add a custom filter to prevent some specific logs from being recorded, based on your criteria

See `Django logging documentation <https://docs.djangoproject.com/en/dev/topics/logging/#topic-logging-parts-filters>`_


Origin: `#412 <https://github.com/jrobichaud/django-structlog/issues/412>`_

.. code-block:: python

    # your_project/logging/filters.py

    import logging

    class ExcludeEventsFilter(logging.Filter):
        def __init__(self, excluded_event_type=None):
            super().__init__()
            self.excluded_event_type = excluded_event_type

        def filter(self, record):
            if not isinstance(record.msg, dict) or self.excluded_event_type is None:
                return True  # Include the log message if msg is not a dictionary or excluded_event_type is not provided

            if record.msg.get('event') in self.excluded_event_type:
                return False  # Exclude the log message
            return True  # Include the log message


    # in your settings.py

    LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'handlers': {
            'console': {
                'class': 'logging.StreamHandler',
                'filters': ['exclude_request_started']
            },
        },
        'filters': {
            'exclude_request_started': {
                '()': 'your_project.logging.filters.ExcludeEventsFilter',
                'excluded_event_type': ['request_started']  # Example excluding request_started event
            },
        },
        'loggers': {
            'django': {
                'handlers': ['console'],
                'level': 'DEBUG',
            },
        },
    }