summaryrefslogtreecommitdiffstats
path: root/third_party/python/sentry-sdk/sentry_sdk/integrations/stdlib.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/python/sentry-sdk/sentry_sdk/integrations/stdlib.py
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/python/sentry-sdk/sentry_sdk/integrations/stdlib.py')
-rw-r--r--third_party/python/sentry-sdk/sentry_sdk/integrations/stdlib.py230
1 files changed, 230 insertions, 0 deletions
diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/stdlib.py b/third_party/python/sentry-sdk/sentry_sdk/integrations/stdlib.py
new file mode 100644
index 0000000000..56cece70ac
--- /dev/null
+++ b/third_party/python/sentry-sdk/sentry_sdk/integrations/stdlib.py
@@ -0,0 +1,230 @@
+import os
+import subprocess
+import sys
+import platform
+
+from sentry_sdk.hub import Hub
+from sentry_sdk.integrations import Integration
+from sentry_sdk.scope import add_global_event_processor
+from sentry_sdk.tracing import EnvironHeaders
+from sentry_sdk.utils import capture_internal_exceptions, safe_repr
+
+from sentry_sdk._types import MYPY
+
+if MYPY:
+ from typing import Any
+ from typing import Callable
+ from typing import Dict
+ from typing import Optional
+ from typing import List
+
+ from sentry_sdk._types import Event, Hint
+
+
+try:
+ from httplib import HTTPConnection # type: ignore
+except ImportError:
+ from http.client import HTTPConnection
+
+
+_RUNTIME_CONTEXT = {
+ "name": platform.python_implementation(),
+ "version": "%s.%s.%s" % (sys.version_info[:3]),
+ "build": sys.version,
+}
+
+
+class StdlibIntegration(Integration):
+ identifier = "stdlib"
+
+ @staticmethod
+ def setup_once():
+ # type: () -> None
+ _install_httplib()
+ _install_subprocess()
+
+ @add_global_event_processor
+ def add_python_runtime_context(event, hint):
+ # type: (Event, Hint) -> Optional[Event]
+ if Hub.current.get_integration(StdlibIntegration) is not None:
+ contexts = event.setdefault("contexts", {})
+ if isinstance(contexts, dict) and "runtime" not in contexts:
+ contexts["runtime"] = _RUNTIME_CONTEXT
+
+ return event
+
+
+def _install_httplib():
+ # type: () -> None
+ real_putrequest = HTTPConnection.putrequest
+ real_getresponse = HTTPConnection.getresponse
+
+ def putrequest(self, method, url, *args, **kwargs):
+ # type: (HTTPConnection, str, str, *Any, **Any) -> Any
+ hub = Hub.current
+ if hub.get_integration(StdlibIntegration) is None:
+ return real_putrequest(self, method, url, *args, **kwargs)
+
+ host = self.host
+ port = self.port
+ default_port = self.default_port
+
+ real_url = url
+ if not real_url.startswith(("http://", "https://")):
+ real_url = "%s://%s%s%s" % (
+ default_port == 443 and "https" or "http",
+ host,
+ port != default_port and ":%s" % port or "",
+ url,
+ )
+
+ span = hub.start_span(op="http", description="%s %s" % (method, real_url))
+
+ span.set_data("method", method)
+ span.set_data("url", real_url)
+
+ rv = real_putrequest(self, method, url, *args, **kwargs)
+
+ for key, value in hub.iter_trace_propagation_headers():
+ self.putheader(key, value)
+
+ self._sentrysdk_span = span
+
+ return rv
+
+ def getresponse(self, *args, **kwargs):
+ # type: (HTTPConnection, *Any, **Any) -> Any
+ span = getattr(self, "_sentrysdk_span", None)
+
+ if span is None:
+ return real_getresponse(self, *args, **kwargs)
+
+ rv = real_getresponse(self, *args, **kwargs)
+
+ span.set_data("status_code", rv.status)
+ span.set_http_status(int(rv.status))
+ span.set_data("reason", rv.reason)
+ span.finish()
+
+ return rv
+
+ HTTPConnection.putrequest = putrequest
+ HTTPConnection.getresponse = getresponse
+
+
+def _init_argument(args, kwargs, name, position, setdefault_callback=None):
+ # type: (List[Any], Dict[Any, Any], str, int, Optional[Callable[[Any], Any]]) -> Any
+ """
+ given (*args, **kwargs) of a function call, retrieve (and optionally set a
+ default for) an argument by either name or position.
+
+ This is useful for wrapping functions with complex type signatures and
+ extracting a few arguments without needing to redefine that function's
+ entire type signature.
+ """
+
+ if name in kwargs:
+ rv = kwargs[name]
+ if setdefault_callback is not None:
+ rv = setdefault_callback(rv)
+ if rv is not None:
+ kwargs[name] = rv
+ elif position < len(args):
+ rv = args[position]
+ if setdefault_callback is not None:
+ rv = setdefault_callback(rv)
+ if rv is not None:
+ args[position] = rv
+ else:
+ rv = setdefault_callback and setdefault_callback(None)
+ if rv is not None:
+ kwargs[name] = rv
+
+ return rv
+
+
+def _install_subprocess():
+ # type: () -> None
+ old_popen_init = subprocess.Popen.__init__
+
+ def sentry_patched_popen_init(self, *a, **kw):
+ # type: (subprocess.Popen[Any], *Any, **Any) -> None
+
+ hub = Hub.current
+ if hub.get_integration(StdlibIntegration) is None:
+ return old_popen_init(self, *a, **kw) # type: ignore
+
+ # Convert from tuple to list to be able to set values.
+ a = list(a)
+
+ args = _init_argument(a, kw, "args", 0) or []
+ cwd = _init_argument(a, kw, "cwd", 9)
+
+ # if args is not a list or tuple (and e.g. some iterator instead),
+ # let's not use it at all. There are too many things that can go wrong
+ # when trying to collect an iterator into a list and setting that list
+ # into `a` again.
+ #
+ # Also invocations where `args` is not a sequence are not actually
+ # legal. They just happen to work under CPython.
+ description = None
+
+ if isinstance(args, (list, tuple)) and len(args) < 100:
+ with capture_internal_exceptions():
+ description = " ".join(map(str, args))
+
+ if description is None:
+ description = safe_repr(args)
+
+ env = None
+
+ for k, v in hub.iter_trace_propagation_headers():
+ if env is None:
+ env = _init_argument(a, kw, "env", 10, lambda x: dict(x or os.environ))
+ env["SUBPROCESS_" + k.upper().replace("-", "_")] = v
+
+ with hub.start_span(op="subprocess", description=description) as span:
+ if cwd:
+ span.set_data("subprocess.cwd", cwd)
+
+ rv = old_popen_init(self, *a, **kw) # type: ignore
+
+ span.set_tag("subprocess.pid", self.pid)
+ return rv
+
+ subprocess.Popen.__init__ = sentry_patched_popen_init # type: ignore
+
+ old_popen_wait = subprocess.Popen.wait
+
+ def sentry_patched_popen_wait(self, *a, **kw):
+ # type: (subprocess.Popen[Any], *Any, **Any) -> Any
+ hub = Hub.current
+
+ if hub.get_integration(StdlibIntegration) is None:
+ return old_popen_wait(self, *a, **kw)
+
+ with hub.start_span(op="subprocess.wait") as span:
+ span.set_tag("subprocess.pid", self.pid)
+ return old_popen_wait(self, *a, **kw)
+
+ subprocess.Popen.wait = sentry_patched_popen_wait # type: ignore
+
+ old_popen_communicate = subprocess.Popen.communicate
+
+ def sentry_patched_popen_communicate(self, *a, **kw):
+ # type: (subprocess.Popen[Any], *Any, **Any) -> Any
+ hub = Hub.current
+
+ if hub.get_integration(StdlibIntegration) is None:
+ return old_popen_communicate(self, *a, **kw)
+
+ with hub.start_span(op="subprocess.communicate") as span:
+ span.set_tag("subprocess.pid", self.pid)
+ return old_popen_communicate(self, *a, **kw)
+
+ subprocess.Popen.communicate = sentry_patched_popen_communicate # type: ignore
+
+
+def get_subprocess_traceparent_headers():
+ # type: () -> EnvironHeaders
+ return EnvironHeaders(os.environ, prefix="SUBPROCESS_")