about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/sentry_sdk/monitor.py
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/sentry_sdk/monitor.py
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-4a52a71956a8d46fcb7294ac71734504bb09bcc2.tar.gz
two version of R2R are here HEAD master
Diffstat (limited to '.venv/lib/python3.12/site-packages/sentry_sdk/monitor.py')
-rw-r--r--.venv/lib/python3.12/site-packages/sentry_sdk/monitor.py124
1 files changed, 124 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/sentry_sdk/monitor.py b/.venv/lib/python3.12/site-packages/sentry_sdk/monitor.py
new file mode 100644
index 00000000..68d9017b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sentry_sdk/monitor.py
@@ -0,0 +1,124 @@
+import os
+import time
+from threading import Thread, Lock
+
+import sentry_sdk
+from sentry_sdk.utils import logger
+
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+    from typing import Optional
+
+
+MAX_DOWNSAMPLE_FACTOR = 10
+
+
+class Monitor:
+    """
+    Performs health checks in a separate thread once every interval seconds
+    and updates the internal state. Other parts of the SDK only read this state
+    and act accordingly.
+    """
+
+    name = "sentry.monitor"
+
+    def __init__(self, transport, interval=10):
+        # type: (sentry_sdk.transport.Transport, float) -> None
+        self.transport = transport  # type: sentry_sdk.transport.Transport
+        self.interval = interval  # type: float
+
+        self._healthy = True
+        self._downsample_factor = 0  # type: int
+
+        self._thread = None  # type: Optional[Thread]
+        self._thread_lock = Lock()
+        self._thread_for_pid = None  # type: Optional[int]
+        self._running = True
+
+    def _ensure_running(self):
+        # type: () -> None
+        """
+        Check that the monitor has an active thread to run in, or create one if not.
+
+        Note that this might fail (e.g. in Python 3.12 it's not possible to
+        spawn new threads at interpreter shutdown). In that case self._running
+        will be False after running this function.
+        """
+        if self._thread_for_pid == os.getpid() and self._thread is not None:
+            return None
+
+        with self._thread_lock:
+            if self._thread_for_pid == os.getpid() and self._thread is not None:
+                return None
+
+            def _thread():
+                # type: (...) -> None
+                while self._running:
+                    time.sleep(self.interval)
+                    if self._running:
+                        self.run()
+
+            thread = Thread(name=self.name, target=_thread)
+            thread.daemon = True
+            try:
+                thread.start()
+            except RuntimeError:
+                # Unfortunately at this point the interpreter is in a state that no
+                # longer allows us to spawn a thread and we have to bail.
+                self._running = False
+                return None
+
+            self._thread = thread
+            self._thread_for_pid = os.getpid()
+
+        return None
+
+    def run(self):
+        # type: () -> None
+        self.check_health()
+        self.set_downsample_factor()
+
+    def set_downsample_factor(self):
+        # type: () -> None
+        if self._healthy:
+            if self._downsample_factor > 0:
+                logger.debug(
+                    "[Monitor] health check positive, reverting to normal sampling"
+                )
+            self._downsample_factor = 0
+        else:
+            if self.downsample_factor < MAX_DOWNSAMPLE_FACTOR:
+                self._downsample_factor += 1
+            logger.debug(
+                "[Monitor] health check negative, downsampling with a factor of %d",
+                self._downsample_factor,
+            )
+
+    def check_health(self):
+        # type: () -> None
+        """
+        Perform the actual health checks,
+        currently only checks if the transport is rate-limited.
+        TODO: augment in the future with more checks.
+        """
+        self._healthy = self.transport.is_healthy()
+
+    def is_healthy(self):
+        # type: () -> bool
+        self._ensure_running()
+        return self._healthy
+
+    @property
+    def downsample_factor(self):
+        # type: () -> int
+        self._ensure_running()
+        return self._downsample_factor
+
+    def kill(self):
+        # type: () -> None
+        self._running = False
+
+    def __del__(self):
+        # type: () -> None
+        self.kill()