From 4a3c98c74fa5b5dd1f174ec8f60220cdfad0d9c4 Mon Sep 17 00:00:00 2001 From: Klaas van Schelven Date: Wed, 7 Feb 2024 23:07:49 +0100 Subject: [PATCH] implement capture_stacktrace; use it for capturing unexpected situations with envelope handling --- ingest/views.py | 6 ++++-- sentry_sdk_extensions/__init__.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 sentry_sdk_extensions/__init__.py diff --git a/ingest/views.py b/ingest/views.py index 92154ab..2cb4ada 100644 --- a/ingest/views.py +++ b/ingest/views.py @@ -17,12 +17,14 @@ from issues.models import Issue, IssueStateManager from issues.utils import get_hash_for_data from issues.regressions import issue_is_regression +import sentry_sdk_extensions from events.models import Event from releases.models import create_release_if_needed from bugsink.registry import get_pc_registry from bugsink.period_counter import PeriodCounter from alerts.tasks import send_new_issue_alert, send_regression_alert + from .negotiation import IgnoreClientContentNegotiation from .parsers import EnvelopeParser from .models import DecompressedEvent @@ -147,11 +149,11 @@ class IngestEnvelopeAPIView(BaseIngestAPIView): if len(request.data) != 3: # multi-part envelopes trigger an error too - print("!= 3") + sentry_sdk_extensions.capture_stacktrace("Invalid envelope (not 3 parts)") return Response({"message": "Missing headers / unsupported type"}, status=status.HTTP_501_NOT_IMPLEMENTED) if request.data[1].get("type") != "event": - print("!= event") + sentry_sdk_extensions.capture_stacktrace("Invalid envelope (not an event)") return Response({"message": "Only events are supported"}, status=status.HTTP_501_NOT_IMPLEMENTED) # TODO think about a good order to handle this in. Namely: if no project Header is provided, you are basically diff --git a/sentry_sdk_extensions/__init__.py b/sentry_sdk_extensions/__init__.py new file mode 100644 index 0000000..f28f143 --- /dev/null +++ b/sentry_sdk_extensions/__init__.py @@ -0,0 +1,28 @@ +from sentry_sdk.utils import capture_internal_exceptions, current_stacktrace +import sentry_sdk + + +def capture_stacktrace(message): + """ + Capture the current stacktrace and send it to Sentry; the standard sentry_sdk does not provide this; it either + allows for sending arbitrary messages (but without local variables on your stacktrace) or it allows for sending + exceptions (but you have to raise an exception to capture the stacktrace). + """ + client_options = sentry_sdk.client.get_options() + event = {} + with capture_internal_exceptions(): + stacktrace = current_stacktrace(client_options["with_locals"]) + stacktrace["frames"].pop() # Remove the last frame, which is the present function + event["threads"] = { + "values": [ + { + "stacktrace": stacktrace, + "crashed": False, + "current": True, + } + ] + } + + event["level"] = "error" + event["logentry"] = {"message": message} + sentry_sdk.capture_event(event)