django-structlog 9.0.0.dev1__tar.gz → 9.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {django_structlog-9.0.0.dev1/django_structlog.egg-info → django_structlog-9.0.1}/PKG-INFO +46 -2
- {django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/README.rst +44 -0
- {django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/django_structlog/__init__.py +1 -1
- {django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/django_structlog/celery/receivers.py +9 -12
- {django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/django_structlog/celery/signals.py +0 -1
- {django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/django_structlog/commands.py +10 -8
- {django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/django_structlog/middlewares/__init__.py +4 -0
- {django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/django_structlog/middlewares/request.py +55 -30
- {django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/django_structlog/signals.py +0 -1
- {django_structlog-9.0.0.dev1 → django_structlog-9.0.1/django_structlog.egg-info}/PKG-INFO +46 -2
- {django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/pyproject.toml +6 -13
- {django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/LICENSE.rst +0 -0
- {django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/MANIFEST.in +0 -0
- {django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/django_structlog/app_settings.py +0 -0
- {django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/django_structlog/apps.py +0 -0
- {django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/django_structlog/celery/__init__.py +0 -0
- {django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/django_structlog/celery/steps.py +0 -0
- {django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/django_structlog/py.typed +0 -0
- {django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/django_structlog.egg-info/SOURCES.txt +0 -0
- {django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/django_structlog.egg-info/dependency_links.txt +0 -0
- {django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/django_structlog.egg-info/requires.txt +0 -0
- {django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/django_structlog.egg-info/top_level.txt +0 -0
- {django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: django-structlog
|
|
3
|
-
Version: 9.0.
|
|
3
|
+
Version: 9.0.1
|
|
4
4
|
Summary: Structured Logging for Django
|
|
5
5
|
Author-email: Jules Robichaud-Gagnon <j.robichaudg+pypi@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -44,8 +44,14 @@ django-structlog
|
|
|
44
44
|
|
|
45
45
|
| |pypi| |wheels| |build-status| |docs| |coverage| |open_issues| |pull_requests|
|
|
46
46
|
| |django| |python| |license| |black| |ruff|
|
|
47
|
+
| |django_packages|
|
|
47
48
|
| |watchers| |stars| |forks|
|
|
48
49
|
|
|
50
|
+
|
|
51
|
+
.. |django_packages| image:: https://img.shields.io/badge/Published%20on-Django%20Packages-0c3c26
|
|
52
|
+
:target: https://djangopackages.org/packages/p/django-structlog/
|
|
53
|
+
:alt: Published on Django Packages
|
|
54
|
+
|
|
49
55
|
.. |build-status| image:: https://github.com/jrobichaud/django-structlog/actions/workflows/main.yml/badge.svg?branch=main
|
|
50
56
|
:target: https://github.com/jrobichaud/django-structlog/actions
|
|
51
57
|
:alt: Build Status
|
|
@@ -408,6 +414,44 @@ Json file (\ ``logs/json.log``\ )
|
|
|
408
414
|
Upgrade Guide
|
|
409
415
|
=============
|
|
410
416
|
|
|
417
|
+
.. _upgrade_9.0:
|
|
418
|
+
|
|
419
|
+
Upgrading to 9.0+
|
|
420
|
+
^^^^^^^^^^^^^^^^^
|
|
421
|
+
|
|
422
|
+
Minimum requirements
|
|
423
|
+
~~~~~~~~~~~~~~~~~~~~
|
|
424
|
+
- requires python 3.9+
|
|
425
|
+
- django 4.2 and 5.0+ are supported
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
Type hints
|
|
429
|
+
~~~~~~~~~~
|
|
430
|
+
|
|
431
|
+
``django-structlog`` now uses `python type hints <https://docs.python.org/3/library/typing.html>`_ and is being validated with `mypy <https://mypy.readthedocs.io/en/stable/>`_ ``--strict``.
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
For ``drf-standardized-errors`` users
|
|
435
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
436
|
+
|
|
437
|
+
Now unhandled exceptions when using `drf-standardized-errors <https://github.com/ghazi-git/drf-standardized-errors>`_ will be intercepted and the exception logged properly.
|
|
438
|
+
|
|
439
|
+
If you also use `structlog-sentry <https://github.com/kiwicom/structlog-sentry>`_, the exception will now be propagated as expected.
|
|
440
|
+
|
|
441
|
+
Other libraries alike may be affected by this change.
|
|
442
|
+
|
|
443
|
+
Internal changes in how ``RequestMiddleware`` handles exceptions
|
|
444
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
445
|
+
|
|
446
|
+
This only affects you if you implemented a middleware inheriting from ``RequestMiddleware`` and you overrided the ``process_exception`` method.
|
|
447
|
+
|
|
448
|
+
Did you?
|
|
449
|
+
|
|
450
|
+
If so:
|
|
451
|
+
|
|
452
|
+
- ``RequestMiddleware.process_exception`` was renamed to ``RequestMiddleware._process_exception``, you should to the same in the middleware.
|
|
453
|
+
|
|
454
|
+
|
|
411
455
|
.. _upgrade_8.0:
|
|
412
456
|
|
|
413
457
|
Upgrading to 8.0+
|
|
@@ -5,8 +5,14 @@ django-structlog
|
|
|
5
5
|
|
|
6
6
|
| |pypi| |wheels| |build-status| |docs| |coverage| |open_issues| |pull_requests|
|
|
7
7
|
| |django| |python| |license| |black| |ruff|
|
|
8
|
+
| |django_packages|
|
|
8
9
|
| |watchers| |stars| |forks|
|
|
9
10
|
|
|
11
|
+
|
|
12
|
+
.. |django_packages| image:: https://img.shields.io/badge/Published%20on-Django%20Packages-0c3c26
|
|
13
|
+
:target: https://djangopackages.org/packages/p/django-structlog/
|
|
14
|
+
:alt: Published on Django Packages
|
|
15
|
+
|
|
10
16
|
.. |build-status| image:: https://github.com/jrobichaud/django-structlog/actions/workflows/main.yml/badge.svg?branch=main
|
|
11
17
|
:target: https://github.com/jrobichaud/django-structlog/actions
|
|
12
18
|
:alt: Build Status
|
|
@@ -369,6 +375,44 @@ Json file (\ ``logs/json.log``\ )
|
|
|
369
375
|
Upgrade Guide
|
|
370
376
|
=============
|
|
371
377
|
|
|
378
|
+
.. _upgrade_9.0:
|
|
379
|
+
|
|
380
|
+
Upgrading to 9.0+
|
|
381
|
+
^^^^^^^^^^^^^^^^^
|
|
382
|
+
|
|
383
|
+
Minimum requirements
|
|
384
|
+
~~~~~~~~~~~~~~~~~~~~
|
|
385
|
+
- requires python 3.9+
|
|
386
|
+
- django 4.2 and 5.0+ are supported
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
Type hints
|
|
390
|
+
~~~~~~~~~~
|
|
391
|
+
|
|
392
|
+
``django-structlog`` now uses `python type hints <https://docs.python.org/3/library/typing.html>`_ and is being validated with `mypy <https://mypy.readthedocs.io/en/stable/>`_ ``--strict``.
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
For ``drf-standardized-errors`` users
|
|
396
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
397
|
+
|
|
398
|
+
Now unhandled exceptions when using `drf-standardized-errors <https://github.com/ghazi-git/drf-standardized-errors>`_ will be intercepted and the exception logged properly.
|
|
399
|
+
|
|
400
|
+
If you also use `structlog-sentry <https://github.com/kiwicom/structlog-sentry>`_, the exception will now be propagated as expected.
|
|
401
|
+
|
|
402
|
+
Other libraries alike may be affected by this change.
|
|
403
|
+
|
|
404
|
+
Internal changes in how ``RequestMiddleware`` handles exceptions
|
|
405
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
406
|
+
|
|
407
|
+
This only affects you if you implemented a middleware inheriting from ``RequestMiddleware`` and you overrided the ``process_exception`` method.
|
|
408
|
+
|
|
409
|
+
Did you?
|
|
410
|
+
|
|
411
|
+
If so:
|
|
412
|
+
|
|
413
|
+
- ``RequestMiddleware.process_exception`` was renamed to ``RequestMiddleware._process_exception``, you should to the same in the middleware.
|
|
414
|
+
|
|
415
|
+
|
|
372
416
|
.. _upgrade_8.0:
|
|
373
417
|
|
|
374
418
|
Upgrading to 8.0+
|
|
@@ -1,24 +1,22 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from typing import Type, Any, Optional, cast, TYPE_CHECKING
|
|
1
|
+
from typing import TYPE_CHECKING, Any, Optional, Type, cast
|
|
4
2
|
|
|
5
3
|
import structlog
|
|
6
4
|
from celery import current_app
|
|
7
5
|
from celery.signals import (
|
|
8
|
-
before_task_publish,
|
|
9
6
|
after_task_publish,
|
|
7
|
+
before_task_publish,
|
|
8
|
+
task_failure,
|
|
10
9
|
task_prerun,
|
|
10
|
+
task_rejected,
|
|
11
11
|
task_retry,
|
|
12
|
-
task_success,
|
|
13
|
-
task_failure,
|
|
14
12
|
task_revoked,
|
|
13
|
+
task_success,
|
|
15
14
|
task_unknown,
|
|
16
|
-
task_rejected,
|
|
17
15
|
)
|
|
18
16
|
|
|
19
17
|
from . import signals
|
|
20
18
|
|
|
21
|
-
if TYPE_CHECKING:
|
|
19
|
+
if TYPE_CHECKING: # pragma: no cover
|
|
22
20
|
from types import TracebackType
|
|
23
21
|
|
|
24
22
|
logger = structlog.getLogger(__name__)
|
|
@@ -35,7 +33,7 @@ class CeleryReceiver:
|
|
|
35
33
|
sender: Optional[Type[Any]] = None,
|
|
36
34
|
headers: Optional[dict[str, Any]] = None,
|
|
37
35
|
body: Optional[dict[str, str]] = None,
|
|
38
|
-
properties: Optional[dict[str,
|
|
36
|
+
properties: Optional[dict[str, Any]] = None,
|
|
39
37
|
routing_key: Optional[str] = None,
|
|
40
38
|
**kwargs: dict[str, str],
|
|
41
39
|
) -> None:
|
|
@@ -54,8 +52,7 @@ class CeleryReceiver:
|
|
|
54
52
|
)
|
|
55
53
|
if properties:
|
|
56
54
|
self._priority = properties.get("priority", None)
|
|
57
|
-
|
|
58
|
-
headers["__django_structlog__"] = context
|
|
55
|
+
cast(dict[str, Any], headers)["__django_structlog__"] = context
|
|
59
56
|
|
|
60
57
|
def receiver_after_task_publish(
|
|
61
58
|
self,
|
|
@@ -119,7 +116,7 @@ class CeleryReceiver:
|
|
|
119
116
|
self,
|
|
120
117
|
task_id: Optional[str] = None,
|
|
121
118
|
exception: Optional[Exception] = None,
|
|
122
|
-
traceback: Optional[TracebackType] = None,
|
|
119
|
+
traceback: Optional["TracebackType"] = None,
|
|
123
120
|
einfo: Optional[Any] = None,
|
|
124
121
|
sender: Optional[Type[Any]] = None,
|
|
125
122
|
*args: Any,
|
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import List, Tuple, Mapping, Any, Type, TYPE_CHECKING
|
|
4
|
-
|
|
5
|
-
import structlog
|
|
6
1
|
import uuid
|
|
2
|
+
from typing import TYPE_CHECKING, Any, List, Mapping, Tuple, Type
|
|
7
3
|
|
|
8
|
-
|
|
4
|
+
import structlog
|
|
5
|
+
from django_extensions.management.signals import ( # type: ignore[import-untyped]
|
|
6
|
+
post_command,
|
|
7
|
+
pre_command,
|
|
8
|
+
)
|
|
9
9
|
|
|
10
|
-
if TYPE_CHECKING:
|
|
10
|
+
if TYPE_CHECKING: # pragma: no cover
|
|
11
11
|
import contextvars
|
|
12
12
|
|
|
13
13
|
logger = structlog.getLogger(__name__)
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class DjangoCommandReceiver:
|
|
17
|
+
stack: List[Tuple[str, Mapping[str, "contextvars.Token[Any]"]]]
|
|
18
|
+
|
|
17
19
|
def __init__(self) -> None:
|
|
18
|
-
self.stack
|
|
20
|
+
self.stack = []
|
|
19
21
|
|
|
20
22
|
def pre_receiver(self, sender: Type[Any], *args: Any, **kwargs: Any) -> None:
|
|
21
23
|
command_id = str(uuid.uuid4())
|
{django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/django_structlog/middlewares/request.py
RENAMED
|
@@ -1,36 +1,50 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
1
|
import asyncio
|
|
4
2
|
import logging
|
|
3
|
+
import sys
|
|
5
4
|
import uuid
|
|
6
5
|
from typing import (
|
|
6
|
+
TYPE_CHECKING,
|
|
7
7
|
Any,
|
|
8
|
-
Generator,
|
|
9
8
|
AsyncGenerator,
|
|
9
|
+
AsyncIterator,
|
|
10
|
+
Awaitable,
|
|
10
11
|
Callable,
|
|
12
|
+
Generator,
|
|
13
|
+
Iterator,
|
|
14
|
+
Type,
|
|
11
15
|
Union,
|
|
12
|
-
Awaitable,
|
|
13
16
|
cast,
|
|
14
|
-
Iterator,
|
|
15
|
-
TYPE_CHECKING,
|
|
16
17
|
)
|
|
17
18
|
|
|
18
19
|
import structlog
|
|
19
|
-
from asgiref
|
|
20
|
+
from asgiref import sync
|
|
20
21
|
from django.core.exceptions import PermissionDenied
|
|
22
|
+
from django.core.signals import got_request_exception
|
|
21
23
|
from django.http import Http404, StreamingHttpResponse
|
|
22
|
-
from asgiref import sync
|
|
23
24
|
|
|
24
25
|
from .. import signals
|
|
25
26
|
from ..app_settings import app_settings
|
|
26
27
|
|
|
27
|
-
if
|
|
28
|
+
if sys.version_info >= (3, 12, 0):
|
|
29
|
+
from inspect import ( # type: ignore[attr-defined]
|
|
30
|
+
iscoroutinefunction,
|
|
31
|
+
markcoroutinefunction,
|
|
32
|
+
)
|
|
33
|
+
else:
|
|
34
|
+
from asgiref.sync import ( # type: ignore[no-redef]
|
|
35
|
+
iscoroutinefunction,
|
|
36
|
+
markcoroutinefunction,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
if TYPE_CHECKING: # pragma: no cover
|
|
40
|
+
from types import TracebackType
|
|
41
|
+
|
|
28
42
|
from django.http import HttpRequest, HttpResponse
|
|
29
43
|
|
|
30
44
|
logger = structlog.getLogger(__name__)
|
|
31
45
|
|
|
32
46
|
|
|
33
|
-
def get_request_header(request: HttpRequest, header_key: str, meta_key: str) -> Any:
|
|
47
|
+
def get_request_header(request: "HttpRequest", header_key: str, meta_key: str) -> Any:
|
|
34
48
|
if hasattr(request, "headers"):
|
|
35
49
|
return request.headers.get(header_key)
|
|
36
50
|
|
|
@@ -38,8 +52,8 @@ def get_request_header(request: HttpRequest, header_key: str, meta_key: str) ->
|
|
|
38
52
|
|
|
39
53
|
|
|
40
54
|
def sync_streaming_content_wrapper(
|
|
41
|
-
streaming_content:
|
|
42
|
-
) -> Generator[
|
|
55
|
+
streaming_content: Iterator[bytes], context: Any
|
|
56
|
+
) -> Generator[bytes, None, None]:
|
|
43
57
|
with structlog.contextvars.bound_contextvars(**context):
|
|
44
58
|
logger.info("streaming_started")
|
|
45
59
|
try:
|
|
@@ -47,13 +61,14 @@ def sync_streaming_content_wrapper(
|
|
|
47
61
|
yield chunk
|
|
48
62
|
except Exception:
|
|
49
63
|
logger.exception("streaming_failed")
|
|
64
|
+
raise
|
|
50
65
|
else:
|
|
51
66
|
logger.info("streaming_finished")
|
|
52
67
|
|
|
53
68
|
|
|
54
69
|
async def async_streaming_content_wrapper(
|
|
55
|
-
streaming_content:
|
|
56
|
-
) -> AsyncGenerator[
|
|
70
|
+
streaming_content: AsyncIterator[bytes], context: Any
|
|
71
|
+
) -> AsyncGenerator[bytes, Any]:
|
|
57
72
|
with structlog.contextvars.bound_contextvars(**context):
|
|
58
73
|
logger.info("streaming_started")
|
|
59
74
|
try:
|
|
@@ -64,6 +79,7 @@ async def async_streaming_content_wrapper(
|
|
|
64
79
|
raise
|
|
65
80
|
except Exception:
|
|
66
81
|
logger.exception("streaming_failed")
|
|
82
|
+
raise
|
|
67
83
|
else:
|
|
68
84
|
logger.info("streaming_finished")
|
|
69
85
|
|
|
@@ -84,24 +100,25 @@ class RequestMiddleware:
|
|
|
84
100
|
def __init__(
|
|
85
101
|
self,
|
|
86
102
|
get_response: Callable[
|
|
87
|
-
[HttpRequest], Union[HttpResponse, Awaitable[HttpResponse]]
|
|
103
|
+
["HttpRequest"], Union["HttpResponse", Awaitable["HttpResponse"]]
|
|
88
104
|
],
|
|
89
105
|
) -> None:
|
|
90
106
|
self.get_response = get_response
|
|
91
107
|
if iscoroutinefunction(self.get_response):
|
|
92
108
|
markcoroutinefunction(self)
|
|
109
|
+
got_request_exception.connect(self.process_got_request_exception)
|
|
93
110
|
|
|
94
111
|
def __call__(
|
|
95
|
-
self, request: HttpRequest
|
|
96
|
-
) -> Union[HttpResponse, Awaitable[HttpResponse]]:
|
|
112
|
+
self, request: "HttpRequest"
|
|
113
|
+
) -> Union["HttpResponse", Awaitable["HttpResponse"]]:
|
|
97
114
|
if iscoroutinefunction(self):
|
|
98
|
-
return cast(RequestMiddleware, self).__acall__(request)
|
|
115
|
+
return cast(RequestMiddleware, self).__acall__(request)
|
|
99
116
|
self.prepare(request)
|
|
100
117
|
response = cast("HttpResponse", self.get_response(request))
|
|
101
118
|
self.handle_response(request, response)
|
|
102
119
|
return response
|
|
103
120
|
|
|
104
|
-
async def __acall__(self, request: HttpRequest) -> HttpResponse:
|
|
121
|
+
async def __acall__(self, request: "HttpRequest") -> "HttpResponse":
|
|
105
122
|
await sync.sync_to_async(self.prepare)(request)
|
|
106
123
|
try:
|
|
107
124
|
response = await cast(Awaitable["HttpResponse"], self.get_response(request))
|
|
@@ -111,7 +128,7 @@ class RequestMiddleware:
|
|
|
111
128
|
await sync.sync_to_async(self.handle_response)(request, response)
|
|
112
129
|
return response
|
|
113
130
|
|
|
114
|
-
def handle_response(self, request: HttpRequest, response: HttpResponse) -> None:
|
|
131
|
+
def handle_response(self, request: "HttpRequest", response: "HttpResponse") -> None:
|
|
115
132
|
if not hasattr(request, "_raised_exception"):
|
|
116
133
|
self.bind_user_id(request)
|
|
117
134
|
context = structlog.contextvars.get_merged_contextvars(logger)
|
|
@@ -140,15 +157,13 @@ class RequestMiddleware:
|
|
|
140
157
|
)
|
|
141
158
|
if isinstance(response, StreamingHttpResponse):
|
|
142
159
|
streaming_content = response.streaming_content
|
|
143
|
-
|
|
144
|
-
iter(cast(Iterator[bytes], streaming_content))
|
|
145
|
-
except TypeError:
|
|
160
|
+
if response.is_async:
|
|
146
161
|
response.streaming_content = async_streaming_content_wrapper(
|
|
147
|
-
streaming_content, context
|
|
162
|
+
cast(AsyncIterator[bytes], streaming_content), context
|
|
148
163
|
)
|
|
149
164
|
else:
|
|
150
165
|
response.streaming_content = sync_streaming_content_wrapper(
|
|
151
|
-
streaming_content, context
|
|
166
|
+
cast(Iterator[bytes], streaming_content), context
|
|
152
167
|
)
|
|
153
168
|
|
|
154
169
|
else:
|
|
@@ -163,8 +178,8 @@ class RequestMiddleware:
|
|
|
163
178
|
)
|
|
164
179
|
structlog.contextvars.clear_contextvars()
|
|
165
180
|
|
|
166
|
-
def prepare(self, request: HttpRequest) -> None:
|
|
167
|
-
from ipware import get_client_ip
|
|
181
|
+
def prepare(self, request: "HttpRequest") -> None:
|
|
182
|
+
from ipware import get_client_ip # type: ignore[import-untyped]
|
|
168
183
|
|
|
169
184
|
request_id = get_request_header(
|
|
170
185
|
request, "x-request-id", "HTTP_X_REQUEST_ID"
|
|
@@ -188,11 +203,11 @@ class RequestMiddleware:
|
|
|
188
203
|
logger.info("request_started", **log_kwargs)
|
|
189
204
|
|
|
190
205
|
@staticmethod
|
|
191
|
-
def format_request(request: HttpRequest) -> str:
|
|
206
|
+
def format_request(request: "HttpRequest") -> str:
|
|
192
207
|
return f"{request.method} {request.get_full_path()}"
|
|
193
208
|
|
|
194
209
|
@staticmethod
|
|
195
|
-
def bind_user_id(request: HttpRequest) -> None:
|
|
210
|
+
def bind_user_id(request: "HttpRequest") -> None:
|
|
196
211
|
user_id_field = app_settings.USER_ID_FIELD
|
|
197
212
|
if hasattr(request, "user") and request.user is not None and user_id_field:
|
|
198
213
|
user_id = None
|
|
@@ -202,7 +217,17 @@ class RequestMiddleware:
|
|
|
202
217
|
user_id = str(user_id)
|
|
203
218
|
structlog.contextvars.bind_contextvars(user_id=user_id)
|
|
204
219
|
|
|
205
|
-
def
|
|
220
|
+
def process_got_request_exception(
|
|
221
|
+
self, sender: Type[Any], request: "HttpRequest", **kwargs: Any
|
|
222
|
+
) -> None:
|
|
223
|
+
if not hasattr(request, "_raised_exception"):
|
|
224
|
+
ex = cast(
|
|
225
|
+
tuple[Type[Exception], Exception, "TracebackType"],
|
|
226
|
+
sys.exc_info(),
|
|
227
|
+
)
|
|
228
|
+
self._process_exception(request, ex[1])
|
|
229
|
+
|
|
230
|
+
def _process_exception(self, request: "HttpRequest", exception: Exception) -> None:
|
|
206
231
|
if isinstance(exception, (Http404, PermissionDenied)):
|
|
207
232
|
# We don't log an exception here, and we don't set that we handled
|
|
208
233
|
# an error as we want the standard `request_finished` log message
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: django-structlog
|
|
3
|
-
Version: 9.0.
|
|
3
|
+
Version: 9.0.1
|
|
4
4
|
Summary: Structured Logging for Django
|
|
5
5
|
Author-email: Jules Robichaud-Gagnon <j.robichaudg+pypi@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -44,8 +44,14 @@ django-structlog
|
|
|
44
44
|
|
|
45
45
|
| |pypi| |wheels| |build-status| |docs| |coverage| |open_issues| |pull_requests|
|
|
46
46
|
| |django| |python| |license| |black| |ruff|
|
|
47
|
+
| |django_packages|
|
|
47
48
|
| |watchers| |stars| |forks|
|
|
48
49
|
|
|
50
|
+
|
|
51
|
+
.. |django_packages| image:: https://img.shields.io/badge/Published%20on-Django%20Packages-0c3c26
|
|
52
|
+
:target: https://djangopackages.org/packages/p/django-structlog/
|
|
53
|
+
:alt: Published on Django Packages
|
|
54
|
+
|
|
49
55
|
.. |build-status| image:: https://github.com/jrobichaud/django-structlog/actions/workflows/main.yml/badge.svg?branch=main
|
|
50
56
|
:target: https://github.com/jrobichaud/django-structlog/actions
|
|
51
57
|
:alt: Build Status
|
|
@@ -408,6 +414,44 @@ Json file (\ ``logs/json.log``\ )
|
|
|
408
414
|
Upgrade Guide
|
|
409
415
|
=============
|
|
410
416
|
|
|
417
|
+
.. _upgrade_9.0:
|
|
418
|
+
|
|
419
|
+
Upgrading to 9.0+
|
|
420
|
+
^^^^^^^^^^^^^^^^^
|
|
421
|
+
|
|
422
|
+
Minimum requirements
|
|
423
|
+
~~~~~~~~~~~~~~~~~~~~
|
|
424
|
+
- requires python 3.9+
|
|
425
|
+
- django 4.2 and 5.0+ are supported
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
Type hints
|
|
429
|
+
~~~~~~~~~~
|
|
430
|
+
|
|
431
|
+
``django-structlog`` now uses `python type hints <https://docs.python.org/3/library/typing.html>`_ and is being validated with `mypy <https://mypy.readthedocs.io/en/stable/>`_ ``--strict``.
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
For ``drf-standardized-errors`` users
|
|
435
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
436
|
+
|
|
437
|
+
Now unhandled exceptions when using `drf-standardized-errors <https://github.com/ghazi-git/drf-standardized-errors>`_ will be intercepted and the exception logged properly.
|
|
438
|
+
|
|
439
|
+
If you also use `structlog-sentry <https://github.com/kiwicom/structlog-sentry>`_, the exception will now be propagated as expected.
|
|
440
|
+
|
|
441
|
+
Other libraries alike may be affected by this change.
|
|
442
|
+
|
|
443
|
+
Internal changes in how ``RequestMiddleware`` handles exceptions
|
|
444
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
445
|
+
|
|
446
|
+
This only affects you if you implemented a middleware inheriting from ``RequestMiddleware`` and you overrided the ``process_exception`` method.
|
|
447
|
+
|
|
448
|
+
Did you?
|
|
449
|
+
|
|
450
|
+
If so:
|
|
451
|
+
|
|
452
|
+
- ``RequestMiddleware.process_exception`` was renamed to ``RequestMiddleware._process_exception``, you should to the same in the middleware.
|
|
453
|
+
|
|
454
|
+
|
|
411
455
|
.. _upgrade_8.0:
|
|
412
456
|
|
|
413
457
|
Upgrading to 8.0+
|
|
@@ -158,17 +158,10 @@ include = [
|
|
|
158
158
|
python_version=3.9
|
|
159
159
|
strict=true
|
|
160
160
|
packages=[
|
|
161
|
-
"django_structlog"
|
|
161
|
+
"django_structlog",
|
|
162
|
+
"test_app",
|
|
162
163
|
]
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
"django_extensions.*",
|
|
168
|
-
"ipware",
|
|
169
|
-
"django.*",
|
|
170
|
-
"structlog.*",
|
|
171
|
-
"celery.*",
|
|
172
|
-
"asgiref.*",
|
|
173
|
-
]
|
|
174
|
-
ignore_missing_imports = true
|
|
164
|
+
|
|
165
|
+
[tool.isort]
|
|
166
|
+
profile = "black"
|
|
167
|
+
filter_files = true
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/django_structlog.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/django_structlog.egg-info/requires.txt
RENAMED
|
File without changes
|
{django_structlog-9.0.0.dev1 → django_structlog-9.0.1}/django_structlog.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|