debugbundle-python 1.5.0__py3-none-any.whl → 2.0.1__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.
- debugbundle/acknowledgement.py +3 -1
- debugbundle/capture_hooks.py +65 -0
- debugbundle/core.py +347 -262
- debugbundle/delivery_hooks.py +62 -0
- debugbundle/event_support.py +1 -1
- debugbundle/exception_snapshot.py +74 -0
- debugbundle/flush_aggregates.py +37 -0
- debugbundle/probe_capture.py +101 -0
- debugbundle/process_support.py +59 -0
- debugbundle/queue_admission.py +39 -0
- debugbundle/request_capture_policy.py +45 -0
- debugbundle/suppression.py +13 -6
- debugbundle/transport.py +30 -7
- {debugbundle_python-1.5.0.dist-info → debugbundle_python-2.0.1.dist-info}/METADATA +12 -1
- {debugbundle_python-1.5.0.dist-info → debugbundle_python-2.0.1.dist-info}/RECORD +18 -10
- {debugbundle_python-1.5.0.dist-info → debugbundle_python-2.0.1.dist-info}/WHEEL +0 -0
- {debugbundle_python-1.5.0.dist-info → debugbundle_python-2.0.1.dist-info}/licenses/LICENSE +0 -0
- {debugbundle_python-1.5.0.dist-info → debugbundle_python-2.0.1.dist-info}/top_level.txt +0 -0
debugbundle/acknowledgement.py
CHANGED
|
@@ -19,8 +19,10 @@ class AcknowledgementDecision:
|
|
|
19
19
|
reason: str | None = None
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
def decide_acknowledgement(body: object | None, batch_length: int) -> AcknowledgementDecision:
|
|
22
|
+
def decide_acknowledgement(body: object | None, batch_length: int, required: bool = False) -> AcknowledgementDecision:
|
|
23
23
|
if not isinstance(body, dict) or not any(key in body for key in ("accepted", "rejected", "errors")):
|
|
24
|
+
if required:
|
|
25
|
+
return AcknowledgementDecision(kind="protocol_failure", reason="missing_acknowledgement")
|
|
24
26
|
return AcknowledgementDecision(kind="legacy")
|
|
25
27
|
|
|
26
28
|
accepted = body.get("accepted")
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Logger adapter and bounded capture admission for callback-heavy paths."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
import re
|
|
7
|
+
import time
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
from .process_support import ensure_current_process
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from .core import DebugBundleSdk
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def try_capture_lock(sdk: DebugBundleSdk) -> bool:
|
|
17
|
+
ensure_current_process(sdk)
|
|
18
|
+
for _ in range(8):
|
|
19
|
+
if sdk._lock.acquire(blocking=False):
|
|
20
|
+
return True
|
|
21
|
+
time.sleep(0)
|
|
22
|
+
return False
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class DebugBundleLogHandler(logging.Handler):
|
|
26
|
+
def __init__(self, sdk: DebugBundleSdk) -> None:
|
|
27
|
+
super().__init__()
|
|
28
|
+
self._sdk = sdk
|
|
29
|
+
|
|
30
|
+
def emit(self, record: logging.LogRecord) -> None:
|
|
31
|
+
if not self._sdk._log_level_eligible(record.levelname.lower()):
|
|
32
|
+
return
|
|
33
|
+
self._sdk.capture_log(
|
|
34
|
+
safe_log_message(record),
|
|
35
|
+
level=record.levelname.lower(),
|
|
36
|
+
context={
|
|
37
|
+
"logger_name": record.name,
|
|
38
|
+
"pathname": record.pathname,
|
|
39
|
+
"lineno": record.lineno,
|
|
40
|
+
},
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
_PLACEHOLDER = re.compile(r"%[sdif]")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def safe_log_message(record: logging.LogRecord) -> str:
|
|
48
|
+
template = record.msg
|
|
49
|
+
if type(template) is not str:
|
|
50
|
+
return "[non-string log message withheld]"
|
|
51
|
+
template = template[:16_384]
|
|
52
|
+
args = record.args
|
|
53
|
+
if not args:
|
|
54
|
+
return template
|
|
55
|
+
if type(args) is not tuple or len(args) > 8:
|
|
56
|
+
return template + " [log arguments withheld]"
|
|
57
|
+
safe_args = [
|
|
58
|
+
value[:1024] if type(value) is str else str(value) if type(value) in (int, float, bool)
|
|
59
|
+
else "[unsupported argument]"
|
|
60
|
+
for value in args
|
|
61
|
+
]
|
|
62
|
+
if len(_PLACEHOLDER.findall(template)) != len(safe_args):
|
|
63
|
+
return (template + " [args: " + ", ".join(safe_args) + "]")[:16_384]
|
|
64
|
+
iterator = iter(safe_args)
|
|
65
|
+
return _PLACEHOLDER.sub(lambda _match: next(iterator), template)[:16_384]
|