From 69193c1ebd0bb6b0efa34cc9a2310720caa89bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Manuel=20Dom=C3=ADnguez?= Date: Tue, 29 Aug 2023 16:29:25 +0200 Subject: [PATCH 1/3] Change Sentry error reporting plug-in - Use the tool's name (tool id without version) as issue title. This should merge reports for all versions of a tool. Report any other extra information in the contexts. - Submit Galaxy Job error reports with level "error" rather than "info". - Do not include the user's email in the "job" context. It is redundant because it was already being included in the "user" context. - Move the user's feedback message to a new "feedback" context. - Report the user's information as actual Sentry user information rather than a "user" context. - Change existing tags. Use "tool" for `job.tool_id`, `tool.name` for the tool's name (tool id without version) and `tool.version` for the tool's version. - Add a tag informing of whether the user provided feedback or not so that intentional bug reports can be quickly found. --- .../tools/error_reports/plugins/sentry.py | 110 ++++++++++-------- 1 file changed, 60 insertions(+), 50 deletions(-) diff --git a/lib/galaxy/tools/error_reports/plugins/sentry.py b/lib/galaxy/tools/error_reports/plugins/sentry.py index 96622b9361f6..803c63f4e3cb 100644 --- a/lib/galaxy/tools/error_reports/plugins/sentry.py +++ b/lib/galaxy/tools/error_reports/plugins/sentry.py @@ -1,5 +1,6 @@ -"""The module describes the ``sentry`` error plugin plugin.""" +"""The module describes the ``sentry`` error plugin.""" import logging +from typing import Dict try: import sentry_sdk @@ -13,19 +14,7 @@ log = logging.getLogger(__name__) SENTRY_SDK_IMPORT_MESSAGE = "The Python sentry-sdk package is required to use this feature, please install it" -ERROR_TEMPLATE = """Galaxy Job Error: {tool_id} v{tool_version} - -Command Line: -{command_line} - -Stderr: -{stderr} - -Stdout: -{stdout} - -The user provided the following information: -{message}""" +ERROR_TEMPLATE = "Galaxy Job Error: {tool_name}" class SentryPlugin(ErrorPlugin): @@ -41,8 +30,18 @@ def __init__(self, **kwargs): assert sentry_sdk, SENTRY_SDK_IMPORT_MESSAGE def submit_report(self, dataset, job, tool, **kwargs): - """Submit the error report to sentry""" - extra = { + """Submit the error report to Sentry.""" + tool_name = ( + job.tool_id + if not job.tool_id.endswith(f"/{job.tool_version}") + else job.tool_id[: -len(job.tool_version) - 1] + ) # strip the tool's version from its long id + + # Add contexts to the report. + contexts: Dict[str, dict] = dict() + + # - "job" context + contexts["job"] = { "info": job.info, "id": job.id, "command_line": job.command_line, @@ -56,23 +55,8 @@ def submit_report(self, dataset, job, tool, **kwargs): "tool_version": job.tool_version, "tool_xml": tool.config_file if tool else None, } - if self.redact_user_details_in_bugreport: - extra["email"] = "redacted" - else: - if "email" in kwargs: - extra["email"] = kwargs["email"] - - # User submitted message - extra["message"] = kwargs.get("message", "") - - # Construct the error message to send to sentry. The first line - # will be the issue title, everything after that becomes the - # "message" - error_message = ERROR_TEMPLATE.format(**extra) - - # Update context with user information in a sentry-specific manner - context = {} + # - "request" context # Getting the url allows us to link to the dataset info page in case # anything is missing from this report. try: @@ -85,32 +69,58 @@ def submit_report(self, dataset, job, tool, **kwargs): except AttributeError: # The above does not work when handlers are separate from the web handlers url = None + contexts["request"] = {"url": url} + # - "feedback" context + # The User Feedback API https://docs.sentry.io/api/projects/submit-user-feedback/ would be a better approach for + # this. + if "message" in kwargs: + contexts["feedback"] = { + "message": kwargs["message"], + } + + for name, context in contexts.items(): + sentry_sdk.set_context(name, context) + + # Add user information to the report. user = job.get_user() - if self.redact_user_details_in_bugreport: - if user: - # Opaque identifier - context["user"] = {"id": user.id} - else: - if user: - # User information here also places email links + allows seeing - # a list of affected users in the tags/filtering. - context["user"] = { - "name": user.username, + sentry_user = { + "id": user.id if user else None, + # TODO: What about anonymous users? + } + if user and not self.redact_user_details_in_bugreport: + sentry_user.update( + { + "username": user.username, "email": user.email, } + ) + sentry_sdk.set_user(sentry_user) + + # Add tags to the report. + tags = { + "tool": job.tool_id, + "tool.name": tool_name, + "tool.version": job.tool_version, + "feedback": "yes" if "message" in kwargs else "no", + } + for name, value in tags.items(): + sentry_sdk.set_tag(name, value) - context["request"] = {"url": url} + # Construct the error message to send to sentry. The first line + # will be the issue title, everything after that becomes the + # "message". + error_message = ERROR_TEMPLATE.format( + tool_name=tool_name, + ) - for key, value in context.items(): - sentry_sdk.set_context(key, value) - sentry_sdk.set_context("job", extra) - sentry_sdk.set_tag("tool_id", job.tool_id) - sentry_sdk.set_tag("tool_version", job.tool_version) + # Send the report as an error. + sentry_sdk.set_level("error") - # Send the message, using message because + # Send the report. response = sentry_sdk.capture_message(error_message) - return (f"Submitted bug report to Sentry. Your guru meditation number is {response}", "success") + + return f"Submitted bug report to Sentry. Your guru meditation number is {response}", "success" __all__ = ("SentryPlugin",) From b0da7374a71c300e768d6fc1e62ad0ee3594b08b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Manuel=20Dom=C3=ADnguez?= Date: Wed, 13 Sep 2023 16:33:58 +0200 Subject: [PATCH 2/3] Remove "request" context The request context's "url" field is filled with the text "*deprecated attribute, URL not filled in by server*". --- lib/galaxy/tools/error_reports/plugins/sentry.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/lib/galaxy/tools/error_reports/plugins/sentry.py b/lib/galaxy/tools/error_reports/plugins/sentry.py index 803c63f4e3cb..12b0395409ff 100644 --- a/lib/galaxy/tools/error_reports/plugins/sentry.py +++ b/lib/galaxy/tools/error_reports/plugins/sentry.py @@ -7,7 +7,6 @@ except ImportError: sentry_sdk = None -from galaxy import web from galaxy.util import string_as_bool from . import ErrorPlugin @@ -56,21 +55,6 @@ def submit_report(self, dataset, job, tool, **kwargs): "tool_xml": tool.config_file if tool else None, } - # - "request" context - # Getting the url allows us to link to the dataset info page in case - # anything is missing from this report. - try: - url = web.url_for( - controller="dataset", - action="show_params", - dataset_id=self.app.security.encode_id(dataset.id), - qualified=True, - ) - except AttributeError: - # The above does not work when handlers are separate from the web handlers - url = None - contexts["request"] = {"url": url} - # - "feedback" context # The User Feedback API https://docs.sentry.io/api/projects/submit-user-feedback/ would be a better approach for # this. From feca4ce2ad59fb9884649cb66b3f8e28f4455100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Manuel=20Dom=C3=ADnguez?= Date: Wed, 13 Sep 2023 16:39:59 +0200 Subject: [PATCH 3/3] Ignore anonymous users --- lib/galaxy/tools/error_reports/plugins/sentry.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/galaxy/tools/error_reports/plugins/sentry.py b/lib/galaxy/tools/error_reports/plugins/sentry.py index 12b0395409ff..21b914e0be01 100644 --- a/lib/galaxy/tools/error_reports/plugins/sentry.py +++ b/lib/galaxy/tools/error_reports/plugins/sentry.py @@ -70,7 +70,6 @@ def submit_report(self, dataset, job, tool, **kwargs): user = job.get_user() sentry_user = { "id": user.id if user else None, - # TODO: What about anonymous users? } if user and not self.redact_user_details_in_bugreport: sentry_user.update(