django-structlog 8.1.0__tar.gz → 9.0.0.dev1__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-8.1.0/django_structlog.egg-info → django_structlog-9.0.0.dev1}/PKG-INFO +5 -3
- {django_structlog-8.1.0 → django_structlog-9.0.0.dev1}/django_structlog/__init__.py +1 -1
- {django_structlog-8.1.0 → django_structlog-9.0.0.dev1}/django_structlog/app_settings.py +4 -4
- {django_structlog-8.1.0 → django_structlog-9.0.0.dev1}/django_structlog/apps.py +1 -1
- {django_structlog-8.1.0 → django_structlog-9.0.0.dev1}/django_structlog/celery/receivers.py +75 -32
- {django_structlog-8.1.0 → django_structlog-9.0.0.dev1}/django_structlog/celery/steps.py +3 -1
- {django_structlog-8.1.0 → django_structlog-9.0.0.dev1}/django_structlog/commands.py +14 -5
- {django_structlog-8.1.0 → django_structlog-9.0.0.dev1}/django_structlog/middlewares/request.py +42 -15
- django_structlog-9.0.0.dev1/django_structlog/py.typed +0 -0
- {django_structlog-8.1.0 → django_structlog-9.0.0.dev1/django_structlog.egg-info}/PKG-INFO +5 -3
- {django_structlog-8.1.0 → django_structlog-9.0.0.dev1}/django_structlog.egg-info/SOURCES.txt +1 -0
- {django_structlog-8.1.0 → django_structlog-9.0.0.dev1}/pyproject.toml +32 -8
- {django_structlog-8.1.0 → django_structlog-9.0.0.dev1}/LICENSE.rst +0 -0
- {django_structlog-8.1.0 → django_structlog-9.0.0.dev1}/MANIFEST.in +0 -0
- {django_structlog-8.1.0 → django_structlog-9.0.0.dev1}/README.rst +0 -0
- {django_structlog-8.1.0 → django_structlog-9.0.0.dev1}/django_structlog/celery/__init__.py +0 -0
- {django_structlog-8.1.0 → django_structlog-9.0.0.dev1}/django_structlog/celery/signals.py +0 -0
- {django_structlog-8.1.0 → django_structlog-9.0.0.dev1}/django_structlog/middlewares/__init__.py +0 -0
- {django_structlog-8.1.0 → django_structlog-9.0.0.dev1}/django_structlog/signals.py +0 -0
- {django_structlog-8.1.0 → django_structlog-9.0.0.dev1}/django_structlog.egg-info/dependency_links.txt +0 -0
- {django_structlog-8.1.0 → django_structlog-9.0.0.dev1}/django_structlog.egg-info/requires.txt +0 -0
- {django_structlog-8.1.0 → django_structlog-9.0.0.dev1}/django_structlog.egg-info/top_level.txt +0 -0
- {django_structlog-8.1.0 → django_structlog-9.0.0.dev1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: django-structlog
|
|
3
|
-
Version:
|
|
3
|
+
Version: 9.0.0.dev1
|
|
4
4
|
Summary: Structured Logging for Django
|
|
5
5
|
Author-email: Jules Robichaud-Gagnon <j.robichaudg+pypi@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -13,17 +13,19 @@ Classifier: Development Status :: 5 - Production/Stable
|
|
|
13
13
|
Classifier: Framework :: Django
|
|
14
14
|
Classifier: Framework :: Django :: 4.2
|
|
15
15
|
Classifier: Framework :: Django :: 5.0
|
|
16
|
+
Classifier: Framework :: Django :: 5.1
|
|
16
17
|
Classifier: Programming Language :: Python :: 3
|
|
17
18
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.9
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
24
|
Classifier: Topic :: System :: Logging
|
|
24
25
|
Classifier: License :: OSI Approved :: MIT License
|
|
25
26
|
Classifier: Operating System :: OS Independent
|
|
26
|
-
|
|
27
|
+
Classifier: Typing :: Typed
|
|
28
|
+
Requires-Python: >=3.9
|
|
27
29
|
Description-Content-Type: text/x-rst
|
|
28
30
|
License-File: LICENSE.rst
|
|
29
31
|
Requires-Dist: django>=4.2
|
|
@@ -8,19 +8,19 @@ class AppSettings:
|
|
|
8
8
|
PREFIX = "DJANGO_STRUCTLOG_"
|
|
9
9
|
|
|
10
10
|
@property
|
|
11
|
-
def CELERY_ENABLED(self):
|
|
11
|
+
def CELERY_ENABLED(self) -> bool:
|
|
12
12
|
return getattr(settings, self.PREFIX + "CELERY_ENABLED", False)
|
|
13
13
|
|
|
14
14
|
@property
|
|
15
|
-
def STATUS_4XX_LOG_LEVEL(self):
|
|
15
|
+
def STATUS_4XX_LOG_LEVEL(self) -> int:
|
|
16
16
|
return getattr(settings, self.PREFIX + "STATUS_4XX_LOG_LEVEL", logging.WARNING)
|
|
17
17
|
|
|
18
18
|
@property
|
|
19
|
-
def COMMAND_LOGGING_ENABLED(self):
|
|
19
|
+
def COMMAND_LOGGING_ENABLED(self) -> bool:
|
|
20
20
|
return getattr(settings, self.PREFIX + "COMMAND_LOGGING_ENABLED", False)
|
|
21
21
|
|
|
22
22
|
@property
|
|
23
|
-
def USER_ID_FIELD(self):
|
|
23
|
+
def USER_ID_FIELD(self) -> str:
|
|
24
24
|
return getattr(settings, self.PREFIX + "USER_ID_FIELD", "pk")
|
|
25
25
|
|
|
26
26
|
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Type, Any, Optional, cast, TYPE_CHECKING
|
|
4
|
+
|
|
1
5
|
import structlog
|
|
2
6
|
from celery import current_app
|
|
3
7
|
from celery.signals import (
|
|
@@ -14,23 +18,27 @@ from celery.signals import (
|
|
|
14
18
|
|
|
15
19
|
from . import signals
|
|
16
20
|
|
|
21
|
+
if TYPE_CHECKING:
|
|
22
|
+
from types import TracebackType
|
|
17
23
|
|
|
18
24
|
logger = structlog.getLogger(__name__)
|
|
19
25
|
|
|
20
26
|
|
|
21
27
|
class CeleryReceiver:
|
|
22
|
-
|
|
28
|
+
_priority: Optional[str]
|
|
29
|
+
|
|
30
|
+
def __init__(self) -> None:
|
|
23
31
|
self._priority = None
|
|
24
32
|
|
|
25
33
|
def receiver_before_task_publish(
|
|
26
34
|
self,
|
|
27
|
-
sender=None,
|
|
28
|
-
headers=None,
|
|
29
|
-
body=None,
|
|
30
|
-
properties=None,
|
|
31
|
-
routing_key=None,
|
|
32
|
-
**kwargs,
|
|
33
|
-
):
|
|
35
|
+
sender: Optional[Type[Any]] = None,
|
|
36
|
+
headers: Optional[dict[str, Any]] = None,
|
|
37
|
+
body: Optional[dict[str, str]] = None,
|
|
38
|
+
properties: Optional[dict[str, Optional[str]]] = None,
|
|
39
|
+
routing_key: Optional[str] = None,
|
|
40
|
+
**kwargs: dict[str, str],
|
|
41
|
+
) -> None:
|
|
34
42
|
if current_app.conf.task_protocol < 2:
|
|
35
43
|
return
|
|
36
44
|
|
|
@@ -46,12 +54,17 @@ class CeleryReceiver:
|
|
|
46
54
|
)
|
|
47
55
|
if properties:
|
|
48
56
|
self._priority = properties.get("priority", None)
|
|
49
|
-
|
|
50
|
-
|
|
57
|
+
if headers is not None:
|
|
58
|
+
headers["__django_structlog__"] = context
|
|
51
59
|
|
|
52
60
|
def receiver_after_task_publish(
|
|
53
|
-
self,
|
|
54
|
-
|
|
61
|
+
self,
|
|
62
|
+
sender: Optional[Type[Any]] = None,
|
|
63
|
+
headers: Optional[dict[str, Optional[str]]] = None,
|
|
64
|
+
body: Optional[dict[str, Optional[str]]] = None,
|
|
65
|
+
routing_key: Optional[str] = None,
|
|
66
|
+
**kwargs: Any,
|
|
67
|
+
) -> None:
|
|
55
68
|
properties = {}
|
|
56
69
|
if self._priority is not None:
|
|
57
70
|
properties["priority"] = self._priority
|
|
@@ -59,13 +72,23 @@ class CeleryReceiver:
|
|
|
59
72
|
|
|
60
73
|
logger.info(
|
|
61
74
|
"task_enqueued",
|
|
62
|
-
child_task_id=
|
|
63
|
-
|
|
75
|
+
child_task_id=(
|
|
76
|
+
headers.get("id")
|
|
77
|
+
if headers
|
|
78
|
+
else cast(dict[str, Optional[str]], body).get("id")
|
|
79
|
+
),
|
|
80
|
+
child_task_name=(
|
|
81
|
+
headers.get("task")
|
|
82
|
+
if headers
|
|
83
|
+
else cast(dict[str, Optional[str]], body).get("task")
|
|
84
|
+
),
|
|
64
85
|
routing_key=routing_key,
|
|
65
86
|
**properties,
|
|
66
87
|
)
|
|
67
88
|
|
|
68
|
-
def receiver_task_prerun(
|
|
89
|
+
def receiver_task_prerun(
|
|
90
|
+
self, task_id: str, task: Any, *args: Any, **kwargs: Any
|
|
91
|
+
) -> None:
|
|
69
92
|
structlog.contextvars.clear_contextvars()
|
|
70
93
|
structlog.contextvars.bind_contextvars(task_id=task_id)
|
|
71
94
|
metadata = getattr(task.request, "__django_structlog__", {})
|
|
@@ -75,10 +98,18 @@ class CeleryReceiver:
|
|
|
75
98
|
)
|
|
76
99
|
logger.info("task_started", task=task.name)
|
|
77
100
|
|
|
78
|
-
def receiver_task_retry(
|
|
101
|
+
def receiver_task_retry(
|
|
102
|
+
self,
|
|
103
|
+
request: Optional[Any] = None,
|
|
104
|
+
reason: Optional[str] = None,
|
|
105
|
+
einfo: Optional[Any] = None,
|
|
106
|
+
**kwargs: Any,
|
|
107
|
+
) -> None:
|
|
79
108
|
logger.warning("task_retrying", reason=reason)
|
|
80
109
|
|
|
81
|
-
def receiver_task_success(
|
|
110
|
+
def receiver_task_success(
|
|
111
|
+
self, result: Optional[str] = None, **kwargs: Any
|
|
112
|
+
) -> None:
|
|
82
113
|
signals.pre_task_succeeded.send(
|
|
83
114
|
sender=self.receiver_task_success, logger=logger, result=result
|
|
84
115
|
)
|
|
@@ -86,14 +117,14 @@ class CeleryReceiver:
|
|
|
86
117
|
|
|
87
118
|
def receiver_task_failure(
|
|
88
119
|
self,
|
|
89
|
-
task_id=None,
|
|
90
|
-
exception=None,
|
|
91
|
-
traceback=None,
|
|
92
|
-
einfo=None,
|
|
93
|
-
sender=None,
|
|
94
|
-
*args,
|
|
95
|
-
**kwargs,
|
|
96
|
-
):
|
|
120
|
+
task_id: Optional[str] = None,
|
|
121
|
+
exception: Optional[Exception] = None,
|
|
122
|
+
traceback: Optional[TracebackType] = None,
|
|
123
|
+
einfo: Optional[Any] = None,
|
|
124
|
+
sender: Optional[Type[Any]] = None,
|
|
125
|
+
*args: Any,
|
|
126
|
+
**kwargs: Any,
|
|
127
|
+
) -> None:
|
|
97
128
|
throws = getattr(sender, "throws", ())
|
|
98
129
|
if isinstance(exception, throws):
|
|
99
130
|
logger.info(
|
|
@@ -108,8 +139,13 @@ class CeleryReceiver:
|
|
|
108
139
|
)
|
|
109
140
|
|
|
110
141
|
def receiver_task_revoked(
|
|
111
|
-
self,
|
|
112
|
-
|
|
142
|
+
self,
|
|
143
|
+
request: Any,
|
|
144
|
+
terminated: Optional[bool] = None,
|
|
145
|
+
signum: Optional[Any] = None,
|
|
146
|
+
expired: Optional[Any] = None,
|
|
147
|
+
**kwargs: Any,
|
|
148
|
+
) -> None:
|
|
113
149
|
metadata = getattr(request, "__django_structlog__", {}).copy()
|
|
114
150
|
metadata["task_id"] = request.id
|
|
115
151
|
metadata["task"] = request.task
|
|
@@ -124,24 +160,31 @@ class CeleryReceiver:
|
|
|
124
160
|
)
|
|
125
161
|
|
|
126
162
|
def receiver_task_unknown(
|
|
127
|
-
self,
|
|
128
|
-
|
|
163
|
+
self,
|
|
164
|
+
message: Optional[str] = None,
|
|
165
|
+
exc: Optional[Exception] = None,
|
|
166
|
+
name: Optional[str] = None,
|
|
167
|
+
id: Optional[str] = None,
|
|
168
|
+
**kwargs: Any,
|
|
169
|
+
) -> None:
|
|
129
170
|
logger.error(
|
|
130
171
|
"task_not_found",
|
|
131
172
|
task=name,
|
|
132
173
|
task_id=id,
|
|
133
174
|
)
|
|
134
175
|
|
|
135
|
-
def receiver_task_rejected(
|
|
176
|
+
def receiver_task_rejected(
|
|
177
|
+
self, message: Any, exc: Optional[Exception] = None, **kwargs: Any
|
|
178
|
+
) -> None:
|
|
136
179
|
logger.exception(
|
|
137
180
|
"task_rejected", task_id=message.properties.get("correlation_id")
|
|
138
181
|
)
|
|
139
182
|
|
|
140
|
-
def connect_signals(self):
|
|
183
|
+
def connect_signals(self) -> None:
|
|
141
184
|
before_task_publish.connect(self.receiver_before_task_publish)
|
|
142
185
|
after_task_publish.connect(self.receiver_after_task_publish)
|
|
143
186
|
|
|
144
|
-
def connect_worker_signals(self):
|
|
187
|
+
def connect_worker_signals(self) -> None:
|
|
145
188
|
before_task_publish.connect(self.receiver_before_task_publish)
|
|
146
189
|
after_task_publish.connect(self.receiver_after_task_publish)
|
|
147
190
|
task_prerun.connect(self.receiver_task_prerun)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
1
3
|
from celery import bootsteps
|
|
2
4
|
|
|
3
5
|
from .receivers import CeleryReceiver
|
|
@@ -14,7 +16,7 @@ class DjangoStructLogInitStep(bootsteps.Step):
|
|
|
14
16
|
|
|
15
17
|
"""
|
|
16
18
|
|
|
17
|
-
def __init__(self, parent, **kwargs):
|
|
19
|
+
def __init__(self, parent: Any, **kwargs: Any) -> None:
|
|
18
20
|
super().__init__(parent, **kwargs)
|
|
19
21
|
self.receiver = CeleryReceiver()
|
|
20
22
|
self.receiver.connect_worker_signals()
|
|
@@ -1,16 +1,23 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import List, Tuple, Mapping, Any, Type, TYPE_CHECKING
|
|
4
|
+
|
|
1
5
|
import structlog
|
|
2
6
|
import uuid
|
|
3
7
|
|
|
4
8
|
from django_extensions.management.signals import pre_command, post_command
|
|
5
9
|
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
import contextvars
|
|
12
|
+
|
|
6
13
|
logger = structlog.getLogger(__name__)
|
|
7
14
|
|
|
8
15
|
|
|
9
16
|
class DjangoCommandReceiver:
|
|
10
|
-
def __init__(self):
|
|
11
|
-
self.stack = []
|
|
17
|
+
def __init__(self) -> None:
|
|
18
|
+
self.stack: List[Tuple[str, Mapping[str, contextvars.Token[Any]]]] = []
|
|
12
19
|
|
|
13
|
-
def pre_receiver(self, sender, *args, **kwargs):
|
|
20
|
+
def pre_receiver(self, sender: Type[Any], *args: Any, **kwargs: Any) -> None:
|
|
14
21
|
command_id = str(uuid.uuid4())
|
|
15
22
|
if len(self.stack):
|
|
16
23
|
parent_command_id, _ = self.stack[-1]
|
|
@@ -26,13 +33,15 @@ class DjangoCommandReceiver:
|
|
|
26
33
|
command_name=sender.__module__.replace(".management.commands", ""),
|
|
27
34
|
)
|
|
28
35
|
|
|
29
|
-
def post_receiver(
|
|
36
|
+
def post_receiver(
|
|
37
|
+
self, sender: Type[Any], outcome: str, *args: Any, **kwargs: Any
|
|
38
|
+
) -> None:
|
|
30
39
|
logger.info("command_finished")
|
|
31
40
|
|
|
32
41
|
if len(self.stack): # pragma: no branch
|
|
33
42
|
command_id, tokens = self.stack.pop()
|
|
34
43
|
structlog.contextvars.reset_contextvars(**tokens)
|
|
35
44
|
|
|
36
|
-
def connect_signals(self):
|
|
45
|
+
def connect_signals(self) -> None:
|
|
37
46
|
pre_command.connect(self.pre_receiver)
|
|
38
47
|
post_command.connect(self.post_receiver)
|
{django_structlog-8.1.0 → django_structlog-9.0.0.dev1}/django_structlog/middlewares/request.py
RENAMED
|
@@ -1,6 +1,19 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import asyncio
|
|
2
4
|
import logging
|
|
3
5
|
import uuid
|
|
6
|
+
from typing import (
|
|
7
|
+
Any,
|
|
8
|
+
Generator,
|
|
9
|
+
AsyncGenerator,
|
|
10
|
+
Callable,
|
|
11
|
+
Union,
|
|
12
|
+
Awaitable,
|
|
13
|
+
cast,
|
|
14
|
+
Iterator,
|
|
15
|
+
TYPE_CHECKING,
|
|
16
|
+
)
|
|
4
17
|
|
|
5
18
|
import structlog
|
|
6
19
|
from asgiref.sync import iscoroutinefunction, markcoroutinefunction
|
|
@@ -11,17 +24,22 @@ from asgiref import sync
|
|
|
11
24
|
from .. import signals
|
|
12
25
|
from ..app_settings import app_settings
|
|
13
26
|
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
from django.http import HttpRequest, HttpResponse
|
|
29
|
+
|
|
14
30
|
logger = structlog.getLogger(__name__)
|
|
15
31
|
|
|
16
32
|
|
|
17
|
-
def get_request_header(request, header_key, meta_key):
|
|
33
|
+
def get_request_header(request: HttpRequest, header_key: str, meta_key: str) -> Any:
|
|
18
34
|
if hasattr(request, "headers"):
|
|
19
35
|
return request.headers.get(header_key)
|
|
20
36
|
|
|
21
37
|
return request.META.get(meta_key)
|
|
22
38
|
|
|
23
39
|
|
|
24
|
-
def sync_streaming_content_wrapper(
|
|
40
|
+
def sync_streaming_content_wrapper(
|
|
41
|
+
streaming_content: Any, context: Any
|
|
42
|
+
) -> Generator[Any, None, None]:
|
|
25
43
|
with structlog.contextvars.bound_contextvars(**context):
|
|
26
44
|
logger.info("streaming_started")
|
|
27
45
|
try:
|
|
@@ -33,7 +51,9 @@ def sync_streaming_content_wrapper(streaming_content, context):
|
|
|
33
51
|
logger.info("streaming_finished")
|
|
34
52
|
|
|
35
53
|
|
|
36
|
-
async def async_streaming_content_wrapper(
|
|
54
|
+
async def async_streaming_content_wrapper(
|
|
55
|
+
streaming_content: Any, context: Any
|
|
56
|
+
) -> AsyncGenerator[Any, None]:
|
|
37
57
|
with structlog.contextvars.bound_contextvars(**context):
|
|
38
58
|
logger.info("streaming_started")
|
|
39
59
|
try:
|
|
@@ -61,30 +81,37 @@ class RequestMiddleware:
|
|
|
61
81
|
sync_capable = True
|
|
62
82
|
async_capable = True
|
|
63
83
|
|
|
64
|
-
def __init__(
|
|
84
|
+
def __init__(
|
|
85
|
+
self,
|
|
86
|
+
get_response: Callable[
|
|
87
|
+
[HttpRequest], Union[HttpResponse, Awaitable[HttpResponse]]
|
|
88
|
+
],
|
|
89
|
+
) -> None:
|
|
65
90
|
self.get_response = get_response
|
|
66
91
|
if iscoroutinefunction(self.get_response):
|
|
67
92
|
markcoroutinefunction(self)
|
|
68
93
|
|
|
69
|
-
def __call__(
|
|
94
|
+
def __call__(
|
|
95
|
+
self, request: HttpRequest
|
|
96
|
+
) -> Union[HttpResponse, Awaitable[HttpResponse]]:
|
|
70
97
|
if iscoroutinefunction(self):
|
|
71
|
-
return self.__acall__(request)
|
|
98
|
+
return cast(RequestMiddleware, self).__acall__(request) # type: ignore[redundant-cast,unused-ignore]
|
|
72
99
|
self.prepare(request)
|
|
73
|
-
response = self.get_response(request)
|
|
100
|
+
response = cast("HttpResponse", self.get_response(request))
|
|
74
101
|
self.handle_response(request, response)
|
|
75
102
|
return response
|
|
76
103
|
|
|
77
|
-
async def __acall__(self, request):
|
|
104
|
+
async def __acall__(self, request: HttpRequest) -> HttpResponse:
|
|
78
105
|
await sync.sync_to_async(self.prepare)(request)
|
|
79
106
|
try:
|
|
80
|
-
response = await self.get_response(request)
|
|
107
|
+
response = await cast(Awaitable["HttpResponse"], self.get_response(request))
|
|
81
108
|
except asyncio.CancelledError:
|
|
82
109
|
logger.warning("request_cancelled")
|
|
83
110
|
raise
|
|
84
111
|
await sync.sync_to_async(self.handle_response)(request, response)
|
|
85
112
|
return response
|
|
86
113
|
|
|
87
|
-
def handle_response(self, request, response):
|
|
114
|
+
def handle_response(self, request: HttpRequest, response: HttpResponse) -> None:
|
|
88
115
|
if not hasattr(request, "_raised_exception"):
|
|
89
116
|
self.bind_user_id(request)
|
|
90
117
|
context = structlog.contextvars.get_merged_contextvars(logger)
|
|
@@ -114,7 +141,7 @@ class RequestMiddleware:
|
|
|
114
141
|
if isinstance(response, StreamingHttpResponse):
|
|
115
142
|
streaming_content = response.streaming_content
|
|
116
143
|
try:
|
|
117
|
-
iter(streaming_content)
|
|
144
|
+
iter(cast(Iterator[bytes], streaming_content))
|
|
118
145
|
except TypeError:
|
|
119
146
|
response.streaming_content = async_streaming_content_wrapper(
|
|
120
147
|
streaming_content, context
|
|
@@ -136,7 +163,7 @@ class RequestMiddleware:
|
|
|
136
163
|
)
|
|
137
164
|
structlog.contextvars.clear_contextvars()
|
|
138
165
|
|
|
139
|
-
def prepare(self, request):
|
|
166
|
+
def prepare(self, request: HttpRequest) -> None:
|
|
140
167
|
from ipware import get_client_ip
|
|
141
168
|
|
|
142
169
|
request_id = get_request_header(
|
|
@@ -161,11 +188,11 @@ class RequestMiddleware:
|
|
|
161
188
|
logger.info("request_started", **log_kwargs)
|
|
162
189
|
|
|
163
190
|
@staticmethod
|
|
164
|
-
def format_request(request):
|
|
191
|
+
def format_request(request: HttpRequest) -> str:
|
|
165
192
|
return f"{request.method} {request.get_full_path()}"
|
|
166
193
|
|
|
167
194
|
@staticmethod
|
|
168
|
-
def bind_user_id(request):
|
|
195
|
+
def bind_user_id(request: HttpRequest) -> None:
|
|
169
196
|
user_id_field = app_settings.USER_ID_FIELD
|
|
170
197
|
if hasattr(request, "user") and request.user is not None and user_id_field:
|
|
171
198
|
user_id = None
|
|
@@ -175,7 +202,7 @@ class RequestMiddleware:
|
|
|
175
202
|
user_id = str(user_id)
|
|
176
203
|
structlog.contextvars.bind_contextvars(user_id=user_id)
|
|
177
204
|
|
|
178
|
-
def process_exception(self, request, exception):
|
|
205
|
+
def process_exception(self, request: HttpRequest, exception: Exception) -> None:
|
|
179
206
|
if isinstance(exception, (Http404, PermissionDenied)):
|
|
180
207
|
# We don't log an exception here, and we don't set that we handled
|
|
181
208
|
# an error as we want the standard `request_finished` log message
|
|
File without changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: django-structlog
|
|
3
|
-
Version:
|
|
3
|
+
Version: 9.0.0.dev1
|
|
4
4
|
Summary: Structured Logging for Django
|
|
5
5
|
Author-email: Jules Robichaud-Gagnon <j.robichaudg+pypi@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -13,17 +13,19 @@ Classifier: Development Status :: 5 - Production/Stable
|
|
|
13
13
|
Classifier: Framework :: Django
|
|
14
14
|
Classifier: Framework :: Django :: 4.2
|
|
15
15
|
Classifier: Framework :: Django :: 5.0
|
|
16
|
+
Classifier: Framework :: Django :: 5.1
|
|
16
17
|
Classifier: Programming Language :: Python :: 3
|
|
17
18
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.9
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
24
|
Classifier: Topic :: System :: Logging
|
|
24
25
|
Classifier: License :: OSI Approved :: MIT License
|
|
25
26
|
Classifier: Operating System :: OS Independent
|
|
26
|
-
|
|
27
|
+
Classifier: Typing :: Typed
|
|
28
|
+
Requires-Python: >=3.9
|
|
27
29
|
Description-Content-Type: text/x-rst
|
|
28
30
|
License-File: LICENSE.rst
|
|
29
31
|
Requires-Dist: django>=4.2
|
|
@@ -10,7 +10,7 @@ build-backend = "setuptools.build_meta"
|
|
|
10
10
|
]
|
|
11
11
|
readme = "README.rst"
|
|
12
12
|
dynamic = ["version"]
|
|
13
|
-
requires-python = ">=3.
|
|
13
|
+
requires-python = ">=3.9"
|
|
14
14
|
license = { text = "MIT" }
|
|
15
15
|
dependencies = [
|
|
16
16
|
"django>=4.2",
|
|
@@ -23,16 +23,18 @@ build-backend = "setuptools.build_meta"
|
|
|
23
23
|
"Framework :: Django",
|
|
24
24
|
"Framework :: Django :: 4.2",
|
|
25
25
|
"Framework :: Django :: 5.0",
|
|
26
|
+
"Framework :: Django :: 5.1",
|
|
26
27
|
"Programming Language :: Python :: 3",
|
|
27
28
|
"Programming Language :: Python :: 3 :: Only",
|
|
28
|
-
"Programming Language :: Python :: 3.8",
|
|
29
29
|
"Programming Language :: Python :: 3.9",
|
|
30
30
|
"Programming Language :: Python :: 3.10",
|
|
31
31
|
"Programming Language :: Python :: 3.11",
|
|
32
32
|
"Programming Language :: Python :: 3.12",
|
|
33
|
+
"Programming Language :: Python :: 3.13",
|
|
33
34
|
"Topic :: System :: Logging",
|
|
34
35
|
"License :: OSI Approved :: MIT License",
|
|
35
36
|
"Operating System :: OS Independent",
|
|
37
|
+
"Typing :: Typed",
|
|
36
38
|
]
|
|
37
39
|
|
|
38
40
|
[project.urls]
|
|
@@ -62,11 +64,11 @@ build-backend = "setuptools.build_meta"
|
|
|
62
64
|
[tool.black]
|
|
63
65
|
line-length = 88
|
|
64
66
|
target-version = [
|
|
65
|
-
'py38',
|
|
66
67
|
'py39',
|
|
67
68
|
'py310',
|
|
68
69
|
'py311',
|
|
69
70
|
'py312',
|
|
71
|
+
'py313',
|
|
70
72
|
]
|
|
71
73
|
include = '\.pyi?$'
|
|
72
74
|
exclude = '''
|
|
@@ -84,7 +86,7 @@ build-backend = "setuptools.build_meta"
|
|
|
84
86
|
|
|
85
87
|
[tool.ruff]
|
|
86
88
|
line-length = 88
|
|
87
|
-
target-version = "
|
|
89
|
+
target-version = "py313"
|
|
88
90
|
lint.ignore = [
|
|
89
91
|
'E501',
|
|
90
92
|
]
|
|
@@ -99,17 +101,18 @@ build-backend = "setuptools.build_meta"
|
|
|
99
101
|
#
|
|
100
102
|
# Also, make sure that all python versions used here are included in ./github/worksflows/main.yml
|
|
101
103
|
envlist =
|
|
102
|
-
py{
|
|
103
|
-
py31{0,1}-
|
|
104
|
-
py312-django{42,50}-
|
|
104
|
+
py{39,310,311}-django42-celery5{2,3}-redis{3,4}-kombu5,
|
|
105
|
+
py31{0,1}-django5{0,1}-celery5{3,4}-redis4-kombu5,
|
|
106
|
+
py312-django{42,50,51}-celery5{3,4}-redis4-kombu5,
|
|
107
|
+
py313-django{51}-celery5{3,4}-redis4-kombu5,
|
|
105
108
|
|
|
106
109
|
[gh-actions]
|
|
107
110
|
python =
|
|
108
|
-
3.8: py38
|
|
109
111
|
3.9: py39
|
|
110
112
|
3.10: py310
|
|
111
113
|
3.11: py311
|
|
112
114
|
3.12: py312
|
|
115
|
+
3.13: py313
|
|
113
116
|
|
|
114
117
|
[testenv]
|
|
115
118
|
setenv =
|
|
@@ -125,8 +128,10 @@ build-backend = "setuptools.build_meta"
|
|
|
125
128
|
celery51: Celery >=5.1, <5.2
|
|
126
129
|
celery52: Celery >=5.2, <5.3
|
|
127
130
|
celery53: Celery >=5.3, <5.4
|
|
131
|
+
celery54: Celery >=5.4, <5.5
|
|
128
132
|
django42: Django >=4.2, <5.0
|
|
129
133
|
django50: Django >=5.0, <5.1
|
|
134
|
+
django51: Django >=5.1, <5.2
|
|
130
135
|
-r{toxinidir}/requirements/ci.txt
|
|
131
136
|
|
|
132
137
|
commands = pytest --cov=./test_app --cov=./django_structlog --cov-append test_app
|
|
@@ -148,3 +153,22 @@ include = [
|
|
|
148
153
|
"./django_structlog_demo_project/*",
|
|
149
154
|
"./test_app/*",
|
|
150
155
|
]
|
|
156
|
+
|
|
157
|
+
[tool.mypy]
|
|
158
|
+
python_version=3.9
|
|
159
|
+
strict=true
|
|
160
|
+
packages=[
|
|
161
|
+
"django_structlog"
|
|
162
|
+
]
|
|
163
|
+
disallow_subclassing_any=false
|
|
164
|
+
|
|
165
|
+
[[tool.mypy.overrides]]
|
|
166
|
+
module = [
|
|
167
|
+
"django_extensions.*",
|
|
168
|
+
"ipware",
|
|
169
|
+
"django.*",
|
|
170
|
+
"structlog.*",
|
|
171
|
+
"celery.*",
|
|
172
|
+
"asgiref.*",
|
|
173
|
+
]
|
|
174
|
+
ignore_missing_imports = true
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_structlog-8.1.0 → django_structlog-9.0.0.dev1}/django_structlog/middlewares/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_structlog-8.1.0 → django_structlog-9.0.0.dev1}/django_structlog.egg-info/requires.txt
RENAMED
|
File without changes
|
{django_structlog-8.1.0 → django_structlog-9.0.0.dev1}/django_structlog.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|