gnu_backtrace.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import re
  2. import sentry_sdk
  3. from sentry_sdk.integrations import Integration
  4. from sentry_sdk.scope import add_global_event_processor
  5. from sentry_sdk.utils import capture_internal_exceptions
  6. from typing import TYPE_CHECKING
  7. if TYPE_CHECKING:
  8. from typing import Any
  9. from sentry_sdk._types import Event
  10. # function is everything between index at @
  11. # and then we match on the @ plus the hex val
  12. FUNCTION_RE = r"[^@]+?"
  13. HEX_ADDRESS = r"\s+@\s+0x[0-9a-fA-F]+"
  14. FRAME_RE = r"""
  15. ^(?P<index>\d+)\.\s+(?P<function>{FUNCTION_RE}){HEX_ADDRESS}(?:\s+in\s+(?P<package>.+))?$
  16. """.format(
  17. FUNCTION_RE=FUNCTION_RE,
  18. HEX_ADDRESS=HEX_ADDRESS,
  19. )
  20. FRAME_RE = re.compile(FRAME_RE, re.MULTILINE | re.VERBOSE)
  21. class GnuBacktraceIntegration(Integration):
  22. identifier = "gnu_backtrace"
  23. @staticmethod
  24. def setup_once() -> None:
  25. @add_global_event_processor
  26. def process_gnu_backtrace(event: "Event", hint: "dict[str, Any]") -> "Event":
  27. with capture_internal_exceptions():
  28. return _process_gnu_backtrace(event, hint)
  29. def _process_gnu_backtrace(event: "Event", hint: "dict[str, Any]") -> "Event":
  30. if sentry_sdk.get_client().get_integration(GnuBacktraceIntegration) is None:
  31. return event
  32. exc_info = hint.get("exc_info", None)
  33. if exc_info is None:
  34. return event
  35. exception = event.get("exception", None)
  36. if exception is None:
  37. return event
  38. values = exception.get("values", None)
  39. if values is None:
  40. return event
  41. for exception in values:
  42. frames = exception.get("stacktrace", {}).get("frames", [])
  43. if not frames:
  44. continue
  45. msg = exception.get("value", None)
  46. if not msg:
  47. continue
  48. additional_frames = []
  49. new_msg = []
  50. for line in msg.splitlines():
  51. match = FRAME_RE.match(line)
  52. if match:
  53. additional_frames.append(
  54. (
  55. int(match.group("index")),
  56. {
  57. "package": match.group("package") or None,
  58. "function": match.group("function") or None,
  59. "platform": "native",
  60. },
  61. )
  62. )
  63. else:
  64. # Put garbage lines back into message, not sure what to do with them.
  65. new_msg.append(line)
  66. if additional_frames:
  67. additional_frames.sort(key=lambda x: -x[0])
  68. for _, frame in additional_frames:
  69. frames.append(frame)
  70. new_msg.append("<stacktrace parsed and removed by GnuBacktraceIntegration>")
  71. exception["value"] = "\n".join(new_msg)
  72. return event