structlog-throttling 1.0.2__py3-none-any.whl
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.
Potentially problematic release.
This version of structlog-throttling might be problematic. Click here for more details.
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import typing
|
|
5
|
+
|
|
6
|
+
from structlog import DropEvent
|
|
7
|
+
from structlog.typing import EventDict
|
|
8
|
+
|
|
9
|
+
from .throttlers import ThrottlerProtocol, TimeThrottler
|
|
10
|
+
|
|
11
|
+
_T = typing.TypeVar("_T", bound=ThrottlerProtocol)
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"LogTimeThrottler",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class LogTimeThrottler:
|
|
19
|
+
"""Drop logs when throttled based on time in between calls.
|
|
20
|
+
|
|
21
|
+
This should generally be close to the top of your processor chain so that processors
|
|
22
|
+
run in a log that will ultimately be throttled.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
key: Unique key in the ``event_dict`` to determine if log should be throttled.
|
|
26
|
+
every_seconds: How long to throttle logs for, in seconds.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(self, key: str, every_seconds: int | float) -> None:
|
|
30
|
+
self.key = key
|
|
31
|
+
self.throttler = TimeThrottler(every_seconds)
|
|
32
|
+
|
|
33
|
+
def __call__(self, _: logging.Logger, __: str, event_dict: EventDict) -> EventDict:
|
|
34
|
+
if self.throttler.is_throttled(event_dict[self.key]):
|
|
35
|
+
raise DropEvent
|
|
36
|
+
return event_dict
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
import typing
|
|
5
|
+
import weakref
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class _Hashable(typing.Protocol):
|
|
9
|
+
def __hash__(self) -> int: ...
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ThrottlerProtocol(typing.Protocol):
|
|
13
|
+
def is_throttled(self, key: str) -> bool: ...
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class _Link:
|
|
17
|
+
"""A link in a doubly-linked list"""
|
|
18
|
+
|
|
19
|
+
__slots__ = "at", "previous", "next", "__weakref__"
|
|
20
|
+
previous: "_Link" | None
|
|
21
|
+
next: "_Link" | None
|
|
22
|
+
at: float | None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class TimeThrottler:
|
|
26
|
+
"""A throttler for time-based throttling."""
|
|
27
|
+
|
|
28
|
+
def __init__(self, every_seconds: int | float) -> None:
|
|
29
|
+
self.every = every_seconds
|
|
30
|
+
|
|
31
|
+
self._last: _Link | None = None
|
|
32
|
+
self._indexes = weakref.WeakValueDictionary()
|
|
33
|
+
|
|
34
|
+
def is_throttled(self, key: _Hashable) -> bool:
|
|
35
|
+
"""Determine whether ``key`` is throttled.
|
|
36
|
+
|
|
37
|
+
Examples:
|
|
38
|
+
>>> tt = TimeThrottler(every_seconds=1)
|
|
39
|
+
>>> tt.is_throttled("event")
|
|
40
|
+
False
|
|
41
|
+
>>> tt.is_throttled("event")
|
|
42
|
+
True
|
|
43
|
+
>>> tt.is_throttled("another-event")
|
|
44
|
+
False
|
|
45
|
+
>>> tt.is_throttled("another-event")
|
|
46
|
+
True
|
|
47
|
+
>>> time.sleep(1)
|
|
48
|
+
>>> tt.is_throttled("event")
|
|
49
|
+
False
|
|
50
|
+
>>> tt.is_throttled("another-event")
|
|
51
|
+
False
|
|
52
|
+
"""
|
|
53
|
+
now = time.monotonic()
|
|
54
|
+
|
|
55
|
+
if key not in self._indexes:
|
|
56
|
+
new = _Link()
|
|
57
|
+
new.at = now
|
|
58
|
+
# Stores a weak reference
|
|
59
|
+
self._indexes[key] = new
|
|
60
|
+
|
|
61
|
+
if self._last:
|
|
62
|
+
# 'next' is a weak reference
|
|
63
|
+
self._last.next = self._indexes[key]
|
|
64
|
+
# 'previous' is not
|
|
65
|
+
new.previous = self._last
|
|
66
|
+
|
|
67
|
+
self._last = new
|
|
68
|
+
|
|
69
|
+
return False
|
|
70
|
+
|
|
71
|
+
link = self._indexes[key]
|
|
72
|
+
if (now - link.at) >= self.every:
|
|
73
|
+
del link
|
|
74
|
+
return False
|
|
75
|
+
|
|
76
|
+
return True
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: structlog-throttling
|
|
3
|
+
Version: 1.0.2
|
|
4
|
+
Summary: Log throttling utilities for structlog.
|
|
5
|
+
Keywords: structlog,throttling,throttle
|
|
6
|
+
License-Expression: MIT OR Apache-2.0
|
|
7
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
8
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: Topic :: System :: Logging
|
|
17
|
+
Classifier: Typing :: Typed
|
|
18
|
+
Requires-Dist: structlog>=25.5.0
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
|
+
Project-URL: Codeberg, https://codeberg.org/tomasfarias/structlog-throttling
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# *structlog-throttling*: Throttling for *[structlog](https://www.structlog.org/)* loggers
|
|
24
|
+
|
|
25
|
+
<a href="https://pypi.org/project/structlog-throttling/"><img src="https://img.shields.io/pypi/pyversions/structlog-throttling.svg" alt="Supported Python versions from PyPI." /></a>
|
|
26
|
+
|
|
27
|
+
Logging offers a trade-off between visibility and performance. A particularly high performance cost can be incurred when logging in each iteration of a loop, common [hot spots](https://en.wikipedia.org/wiki/Hot_spot_%28computer_programming%29) in most programs. A solution to this problem is to space out the log calls such that they only happen every some time instead of on every iteration of the loop. By tweaking the time in between log calls we can move within the visibility-performance trade-off.
|
|
28
|
+
|
|
29
|
+
*structlog-throttling* brings this solution to *[structlog](https://www.structlog.org/)* in the form of processors to throttle log calls based on time.
|
|
30
|
+
|
|
31
|
+
## Getting started
|
|
32
|
+
|
|
33
|
+
### Installation
|
|
34
|
+
|
|
35
|
+
Install *structlog-throttling* from PyPI:
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
pip install structlog-throttling
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Configure
|
|
42
|
+
|
|
43
|
+
When configuring *structlog*, use one of the processors offered by *structlog-throttling*. I recommend putting the processor close to the beginning of your processor chain, to avoid processing logs that will ultimately be dropped:
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
import structlog
|
|
47
|
+
from structlog_throttling.processors import LogTimeThrottler
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
structlog.configure(
|
|
51
|
+
processors=[
|
|
52
|
+
# Logs with the same 'event' will only be allowed through every 5 seconds.
|
|
53
|
+
LogTimeThrottler("event", every_seconds=5),
|
|
54
|
+
...
|
|
55
|
+
]
|
|
56
|
+
)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Examples
|
|
60
|
+
|
|
61
|
+
Throttle logs based on log level:
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
import structlog
|
|
65
|
+
from structlog_throttling.processors import LogTimeThrottler
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
structlog.configure(
|
|
69
|
+
processors=[
|
|
70
|
+
structlog.processors.add_log_level,
|
|
71
|
+
LogTimeThrottler("level", every_seconds=5),
|
|
72
|
+
...
|
|
73
|
+
],
|
|
74
|
+
)
|
|
75
|
+
```
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
structlog_throttling/__init__.py,sha256=KtJ2XWBLHTNeOBHq5r6OR7-m8Kmk570EEXItCTineco,133
|
|
2
|
+
structlog_throttling/processors.py,sha256=b61N6jsAOYno4usPuRxtDYxe6gjEsGl4wCqCaF3LPX8,1043
|
|
3
|
+
structlog_throttling/throttlers.py,sha256=hLqWLNp7OGRswy480C8YcwqDD04cRAeahwO5ezFZeOo,1885
|
|
4
|
+
structlog_throttling-1.0.2.dist-info/WHEEL,sha256=DpNsHFUm_gffZe1FgzmqwuqiuPC6Y-uBCzibcJcdupM,78
|
|
5
|
+
structlog_throttling-1.0.2.dist-info/METADATA,sha256=68LnuIrwOh_TkZv7b6qYeOwi2PJ0zpZlT5atL1LlKFw,2797
|
|
6
|
+
structlog_throttling-1.0.2.dist-info/RECORD,,
|