from django.utils.encoding import force_str from sentry.constants import MAX_CULPRIT_LENGTH from sentry.culprit import generate_culprit from sentry.stacktraces.functions import get_function_name_for_frame from sentry.stacktraces.processing import get_crash_frame_from_event_data from sentry.utils.safe import get_path, trim, truncatechars from .base import BaseEvent def get_crash_location(data): frame = get_crash_frame_from_event_data( data, frame_filter=lambda x: x.get("function") not in (None, "", ""), ) if frame is not None: func = get_function_name_for_frame(frame, data.get("platform")) return frame.get("filename") or frame.get("abs_path"), func class ErrorEvent(BaseEvent): key = "error" def get_metadata(self, data): # Check for undocumented interface where exception has no values. Go SDK does this. # https://docs.sentry.io/development/sdk-dev/event-payloads/exception/ # exception can be an list instead of a dictionary if isinstance(data.get("exception"), list): if len(data["exception"]) == 0: return {} # Force documented interface data["exception"] = {"values": data["exception"]} exception = get_path(data, "exception", "values", -1) if not exception: return {} loc = get_crash_location(data) rv = {"value": trim(get_path(exception, "value", default=""), 1024)} # If the exception mechanism indicates a synthetic exception we do not # want to record the type and value into the metadata. if not get_path(exception, "mechanism", "synthetic"): rv["type"] = trim(get_path(exception, "type", default="Error"), 128) # Attach crash location if available if loc is not None: fn, func = loc if fn: rv["filename"] = fn if func: rv["function"] = func return rv def get_title(self, metadata): ty = metadata.get("type") if ty is None: return metadata.get("function") or "" if not metadata.get("value"): return ty try: return "{}: {}".format(ty, truncatechars(metadata["value"].splitlines()[0])) except AttributeError: # GlitchTip modification # Exception value is specified as a string, sometimes it isn't. This is a fallback. return "{}: {}".format(ty, str(metadata["value"])) def get_location(self, data): loc_string = force_str( data.get("culprit") or data.get("transaction") or generate_culprit(data) or "" ) return truncatechars(loc_string, MAX_CULPRIT_LENGTH)