gnu_backtrace.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  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():
  25. # type: () -> None
  26. @add_global_event_processor
  27. def process_gnu_backtrace(event, hint):
  28. # type: (Event, dict[str, Any]) -> Event
  29. with capture_internal_exceptions():
  30. return _process_gnu_backtrace(event, hint)
  31. def _process_gnu_backtrace(event, hint):
  32. # type: (Event, dict[str, Any]) -> Event
  33. if sentry_sdk.get_client().get_integration(GnuBacktraceIntegration) is None:
  34. return event
  35. exc_info = hint.get("exc_info", None)
  36. if exc_info is None:
  37. return event
  38. exception = event.get("exception", None)
  39. if exception is None:
  40. return event
  41. values = exception.get("values", None)
  42. if values is None:
  43. return event
  44. for exception in values:
  45. frames = exception.get("stacktrace", {}).get("frames", [])
  46. if not frames:
  47. continue
  48. msg = exception.get("value", None)
  49. if not msg:
  50. continue
  51. additional_frames = []
  52. new_msg = []
  53. for line in msg.splitlines():
  54. match = FRAME_RE.match(line)
  55. if match:
  56. additional_frames.append(
  57. (
  58. int(match.group("index")),
  59. {
  60. "package": match.group("package") or None,
  61. "function": match.group("function") or None,
  62. "platform": "native",
  63. },
  64. )
  65. )
  66. else:
  67. # Put garbage lines back into message, not sure what to do with them.
  68. new_msg.append(line)
  69. if additional_frames:
  70. additional_frames.sort(key=lambda x: -x[0])
  71. for _, frame in additional_frames:
  72. frames.append(frame)
  73. new_msg.append("<stacktrace parsed and removed by GnuBacktraceIntegration>")
  74. exception["value"] = "\n".join(new_msg)
  75. return event