debugbundle-python 0.1.0__py3-none-any.whl → 0.1.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.
debugbundle/config.py CHANGED
@@ -37,15 +37,15 @@ class RemoteConfigSnapshot:
37
37
  BALANCED_CAPTURE_POLICY = CapturePolicy(
38
38
  preset="balanced",
39
39
  capture_logs="warning",
40
- capture_request_events="all",
41
- capture_breadcrumbs="local_only",
42
- capture_probe_events="standalone_when_activated",
40
+ capture_request_events="failures_only",
41
+ capture_breadcrumbs="exception_only",
42
+ capture_probe_events="buffer_only",
43
43
  )
44
44
 
45
45
  MINIMAL_CAPTURE_POLICY = CapturePolicy(
46
46
  preset="minimal",
47
- capture_logs="warning",
48
- capture_request_events="off",
47
+ capture_logs="error",
48
+ capture_request_events="failures_only",
49
49
  capture_breadcrumbs="local_only",
50
50
  capture_probe_events="buffer_only",
51
51
  )
debugbundle/core.py CHANGED
@@ -2,9 +2,12 @@ from __future__ import annotations
2
2
 
3
3
  import asyncio
4
4
  import logging
5
+ import os
5
6
  import platform
7
+ import socket
6
8
  import sys
7
9
  import threading
10
+ import time
8
11
  import traceback
9
12
  import uuid
10
13
  from collections import deque
@@ -32,10 +35,16 @@ from .suppression import EventSuppressionTracker
32
35
  from .transport import HttpTransport, Transport, coerce_transport_response
33
36
  from .trigger_token import resolve_request_trigger_directives
34
37
 
38
+ try:
39
+ import resource
40
+ except ImportError: # pragma: no cover - resource is unavailable on some platforms.
41
+ resource = None # type: ignore[assignment]
42
+
35
43
  DEFAULT_BATCH_SIZE = 25
36
44
  DEFAULT_FLUSH_INTERVAL = 5.0
37
45
  DEFAULT_ENDPOINT = "https://api.debugbundle.com/v1/events"
38
46
  DEFAULT_LOG_LEVEL = "warning"
47
+ PROCESS_START_MONOTONIC = time.monotonic()
39
48
  SCHEMA_VERSION = "2026-03-01"
40
49
  LEVEL_RANKS = {
41
50
  "debug": 10,
@@ -225,7 +234,7 @@ class DebugBundleSdk:
225
234
  "handled": handled,
226
235
  "request": request_payload,
227
236
  "response": response_payload,
228
- "runtime": {"version": platform.python_version()},
237
+ "runtime": _runtime_process_facts(),
229
238
  }
230
239
  if self._probe_flush_on_error:
231
240
  probe_data = self._build_probe_data()
@@ -590,19 +599,25 @@ class DebugBundleSdk:
590
599
 
591
600
  def _should_capture_request_event(self, response: Mapping[str, object] | None) -> bool:
592
601
  policy = self._capture_policy.capture_request_events
602
+ status_code = None
603
+ if response is not None:
604
+ candidate = response.get("status_code") or response.get("response_status")
605
+ if isinstance(candidate, int):
606
+ status_code = candidate
607
+ if status_code is not None and status_code >= 500:
608
+ return True
593
609
  if policy == "off":
594
610
  return False
595
611
  if policy == "all":
596
612
  return True
597
613
  if response is None:
598
614
  return policy == "filtered"
599
- status_code = response.get("status_code") or response.get("response_status")
600
- if not isinstance(status_code, int):
615
+ if status_code is None:
601
616
  return policy == "filtered"
602
617
  if policy == "failures_only":
603
- return status_code >= 500
618
+ return False
604
619
  if policy == "filtered":
605
- return status_code >= 500
620
+ return False
606
621
  return True
607
622
 
608
623
  def _emit_probe_events(self, label: str, data: dict[str, object], directives: list[RemoteProbeDirective]) -> None:
@@ -693,6 +708,51 @@ def _redact_mapping(value: object, redact_fields: set[str]) -> Any:
693
708
  return value
694
709
 
695
710
 
711
+ def _runtime_process_facts() -> dict[str, object]:
712
+ return {
713
+ "version": platform.python_version(),
714
+ "platform": sys.platform,
715
+ "arch": platform.machine() or None,
716
+ "pid": os.getpid(),
717
+ "cwd": _safe_cwd(),
718
+ "uptime_sec": round(max(0.0, time.monotonic() - PROCESS_START_MONOTONIC), 3),
719
+ "hostname": _safe_hostname(),
720
+ "thread_id": threading.get_ident(),
721
+ "memory": _memory_facts(),
722
+ }
723
+
724
+
725
+ def _safe_cwd() -> str | None:
726
+ try:
727
+ return os.getcwd()
728
+ except OSError:
729
+ return None
730
+
731
+
732
+ def _safe_hostname() -> str | None:
733
+ try:
734
+ return socket.gethostname()
735
+ except OSError:
736
+ return None
737
+
738
+
739
+ def _memory_facts() -> dict[str, object]:
740
+ memory: dict[str, object] = {
741
+ "rss": None,
742
+ "heap_total": None,
743
+ "heap_used": None,
744
+ "external": None,
745
+ "peak": None,
746
+ }
747
+ if resource is None:
748
+ return memory
749
+
750
+ usage = resource.getrusage(resource.RUSAGE_SELF)
751
+ # ru_maxrss is KiB on Linux and bytes on macOS/BSD.
752
+ memory["peak"] = usage.ru_maxrss if sys.platform == "darwin" else usage.ru_maxrss * 1024
753
+ return memory
754
+
755
+
696
756
  def _backend_exception_request_payload(candidate: object | None) -> dict[str, object]:
697
757
  mapping = _dict_from_object(candidate)
698
758
  payload: dict[str, object] = {
debugbundle/relay.py CHANGED
@@ -15,6 +15,7 @@ ACCEPTED_EVENT_TYPES = frozenset(
15
15
  "frontend_exception",
16
16
  "error_suppressed",
17
17
  "frontend_breadcrumb",
18
+ "request_event",
18
19
  "probe_event",
19
20
  }
20
21
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: debugbundle-python
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: DebugBundle SDK for Python
5
5
  Author: DebugBundle
6
6
  License-Expression: AGPL-3.0-only
@@ -59,8 +59,28 @@ debugbundle.flush()
59
59
 
60
60
  ## Status
61
61
 
62
- This repository currently contains the full Phase 18 Python SDK scope in eleven implementation slices: core SDK surface, buffering, redaction, duplicate suppression, probe buffering, vanilla runtime hooks, framework integrations for Django, Flask, and FastAPI, remote config polling and capture-policy enforcement, optional `structlog` and `loguru` auto-detection when `capture_logging()` is enabled, contract-aligned `EventEnvelope` emission for log, request, exception, suppression, and probe payloads, explicit public wrapper signatures and a validated buildable typed package artifact, real HTTP integration coverage against a lightweight mock ingestion server, vendored machine-readable schema validation for all event types the Python SDK currently emits, a standalone CI workflow that validates Ruff, mypy, pytest, and package builds for the Python 3.10+ support floor actually used by the package, an enforced per-file coverage gate that keeps every shipped Python SDK module at or above the required 80% minimum, and request-local framework correlation binding so `X-DebugBundle-Trace-Id` flows through Django, Flask, and FastAPI into the emitted event correlation metadata for cross-context linking.
62
+ This repository currently contains the full Phase 18 Python SDK scope in eleven implementation slices: core SDK surface, buffering, redaction, duplicate suppression, probe buffering, vanilla runtime hooks, framework integrations for Django, Flask, and FastAPI, remote config polling and capture-policy enforcement, optional `structlog` and `loguru` auto-detection when `capture_logging()` is enabled, contract-aligned `EventEnvelope` emission for log, request, exception, suppression, and probe payloads, explicit public wrapper signatures and a validated buildable typed package artifact, real HTTP integration coverage against a lightweight mock ingestion server, vendored machine-readable schema validation for all event types the Python SDK currently emits, a standalone CI workflow that validates Ruff, mypy, pytest, and package builds for the Python 3.10+ support floor actually used by the package, an enforced per-file coverage gate that keeps every shipped Python SDK module at or above the required 80% minimum, request-local framework correlation binding so `X-DebugBundle-Trace-Id` flows through Django, Flask, and FastAPI into the emitted event correlation metadata for cross-context linking, and safe backend runtime process facts on exception payloads without reading environment variables.
63
+
64
+ ## Runtime Context
65
+
66
+ Backend exception events now include safe runtime process facts when the host exposes them, including:
67
+
68
+ - Python version
69
+ - platform
70
+ - architecture
71
+ - pid
72
+ - cwd
73
+ - uptime
74
+ - hostname
75
+ - thread id
76
+ - best-effort memory metadata
77
+
78
+ The SDK does not read or emit environment variables in this runtime block.
63
79
 
64
80
  ## Docs
65
81
 
66
82
  https://debugbundle.com/docs/sdk-python
83
+
84
+ ## License
85
+
86
+ AGPL-3.0-only
@@ -1,10 +1,10 @@
1
1
  debugbundle/__init__.py,sha256=mqibduUrdcr_fnb6k3Gwf93H7iqVBS8zd6SceX-U3Q4,5011
2
- debugbundle/config.py,sha256=tmXJc16v9yzldiyp1Fwo2s0j-Ek-wbKx__BeKaNw9ec,6097
3
- debugbundle/core.py,sha256=CTx3MmJv0x3fZr0IqTqliv0slTqmia9QVb6eEm4RPTQ,32628
2
+ debugbundle/config.py,sha256=2dLHEsh79mUaa6p7pkrQM849khwSBPg68Aq9RaeXf-8,6105
3
+ debugbundle/core.py,sha256=KIXboK-n1zbgmTCMO1kf-v_jtAA4SOFQvd0BahEt29s,34204
4
4
  debugbundle/logger_integrations.py,sha256=RuTNaD9RRVmiE-BBkksAXWVEGaMzLrWavVpQdgGZBpE,4564
5
5
  debugbundle/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  debugbundle/redaction.py,sha256=QTaPkSsYv54yR1mz8SB6Q4vWjvp7Ddcui4WXaH2RVz8,736
7
- debugbundle/relay.py,sha256=q7WjESsIGoaHETQGhWuT-4KdBmXAocuoCLXuEaz9f60,8678
7
+ debugbundle/relay.py,sha256=TUzlUsTtDKDVVHj0RvYgQVmxy-Jl3Sp8BMBT033mGDM,8703
8
8
  debugbundle/suppression.py,sha256=XMn0GfF_-WZk2wHWk3KfbO5_u5QhEunues5h3jOInLs,4098
9
9
  debugbundle/transport.py,sha256=oOk0xazHxq9h4CneJdRODKtwDciwikvpHVJM_6iBYXU,1791
10
10
  debugbundle/trigger_token.py,sha256=YUwIWnnxu1klAVaB8Ltgk_PwWW_PPjq9rzmEbWXeFeM,4455
@@ -16,8 +16,8 @@ debugbundle/integrations/flask.py,sha256=cgyHbsAH96gpNPf_5IGJYzp2va28JdDgXROBsF-
16
16
  debugbundle/integrations/relay_django.py,sha256=_2TiH-oS0DOwThyfMJZ6ZJr5MkXEekEDaBUfPapMxt8,1523
17
17
  debugbundle/integrations/relay_fastapi.py,sha256=Z2spWy3wufVrBjYwRDDOL5Dsjgwcd5g72L23_sdulvo,1512
18
18
  debugbundle/integrations/relay_flask.py,sha256=WHk_ALOtT0xUuI1eINWFyLig9eRjSmIBpQ39xdkV608,1329
19
- debugbundle_python-0.1.0.dist-info/licenses/LICENSE,sha256=AKZZ5DQAHrOKGwt24VoRd-SXJLM9OloxlsX8ZgENdEY,735
20
- debugbundle_python-0.1.0.dist-info/METADATA,sha256=LtOnh1fp34Nt1M6Cl-K3DO9IJNEjyj6q3OXmAU9VFv4,3148
21
- debugbundle_python-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
22
- debugbundle_python-0.1.0.dist-info/top_level.txt,sha256=RCB9STTFnl1OKdojxz-xhaks2zkRFs1meZXsKnm18LM,12
23
- debugbundle_python-0.1.0.dist-info/RECORD,,
19
+ debugbundle_python-0.1.2.dist-info/licenses/LICENSE,sha256=AKZZ5DQAHrOKGwt24VoRd-SXJLM9OloxlsX8ZgENdEY,735
20
+ debugbundle_python-0.1.2.dist-info/METADATA,sha256=sJOxeZhAm37kzC-TtO0SWrIZ5FEckB8oSNGZ78RCOsY,3589
21
+ debugbundle_python-0.1.2.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
22
+ debugbundle_python-0.1.2.dist-info/top_level.txt,sha256=RCB9STTFnl1OKdojxz-xhaks2zkRFs1meZXsKnm18LM,12
23
+ debugbundle_python-0.1.2.dist-info/RECORD,,