From 5408d282650a08a23345cf8afe55e5456658d859 Mon Sep 17 00:00:00 2001 From: Jesse Schwartzentruber Date: Tue, 7 Oct 2025 13:46:56 -0400 Subject: [PATCH 1/2] feat: add Sentry support for collecting events in automation --- setup.cfg | 3 +++ src/fuzzfetch/core.py | 40 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 72e0454b..e1b996d3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -36,6 +36,9 @@ console_scripts = dev = pre-commit tox +sentry = + psutil + sentry_sdk [options.package_data] fuzzfetch = diff --git a/src/fuzzfetch/core.py b/src/fuzzfetch/core.py index 1d128675..ccc46329 100644 --- a/src/fuzzfetch/core.py +++ b/src/fuzzfetch/core.py @@ -14,12 +14,21 @@ from logging import DEBUG, INFO, WARNING, basicConfig, getLogger from pathlib import Path from platform import system -from shutil import copy +from shutil import copy, disk_usage from tempfile import mkstemp from typing import TYPE_CHECKING, Any from pytz import timezone +try: + from psutil import virtual_memory + from sentry_sdk import Event, Hint + from sentry_sdk import init as sentry_init + + HAVE_SENTRY = True +except ImportError: + HAVE_SENTRY = False + from .args import FetcherArgs from .download import download_url, get_url, resolve_url from .errors import FetcherException @@ -42,6 +51,25 @@ BUG_URL = "https://github.com/MozillaSecurity/fuzzfetch/issues/" +def _add_system_context(event: Event, hint: Hint) -> Event: + event.setdefault("contexts", {}) + event["contexts"]["system_stats"] = { + "free_memory_mb": virtual_memory().available // 1024 // 1024, + "free_disk_mb": disk_usage("/").free // 1024 // 1024, + } + + # add crashing module as a tag + exc_info = hint.get("exc_info") + if exc_info: + _, _, tb = exc_info + if tb: + mod_name = tb.tb_frame.f_globals.get("__name__") + if mod_name: + event.setdefault("tags", {})["origin_module"] = mod_name + + return event + + class Fetcher: """Fetcher fetches build artifacts from TaskCluster and unpacks them""" @@ -731,6 +759,16 @@ def main(cls) -> int: Run with --help for usage """ + if ( + HAVE_SENTRY + and "SENTRY_DSN" in os.environ + and "PYTEST_CURRENT_TEST" not in os.environ + ): + sentry_init( + dsn=os.environ["SENTRY_DSN"], + before_send=_add_system_context, + ) + log_level = INFO log_fmt = "%(message)s" if bool(os.getenv("DEBUG")): From af8f49d9bd38e2de0d4749c8deea034ef12761a3 Mon Sep 17 00:00:00 2001 From: Jesse Schwartzentruber Date: Tue, 7 Oct 2025 16:04:18 -0400 Subject: [PATCH 2/2] chore: add specific checks around mozinfo.json fetch --- src/fuzzfetch/core.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/fuzzfetch/core.py b/src/fuzzfetch/core.py index ccc46329..a1b6def2 100644 --- a/src/fuzzfetch/core.py +++ b/src/fuzzfetch/core.py @@ -316,9 +316,13 @@ def moz_info(self) -> dict[str, str | bool | int]: """Return the build's mozinfo""" if "moz_info" not in self._memo: try: - self._memo["moz_info"] = get_url( - self.artifact_url("mozinfo.json") - ).json() + resp = get_url(self.artifact_url("mozinfo.json")) + self._memo["moz_info"] = resp.json() + if ( + not isinstance(self._memo["moz_info"], dict) + or "crashreporter" not in self._memo["moz_info"] + ): + LOG.error("malformed response fetching mozinfo.json: %r", resp) except FetcherException: # If mozinfo doesn't exist, set the default topsrcdir self._memo["moz_info"] = {"topsrcdir": "/builds/worker/checkouts/gecko"}