|
@@ -6,9 +6,11 @@ from collections import defaultdict
|
|
|
from typing import Any
|
|
|
|
|
|
import sentry_sdk
|
|
|
+from symbolic.proguard import ProguardMapper
|
|
|
|
|
|
from sentry import features, options
|
|
|
from sentry.issues.grouptype import (
|
|
|
+ GroupType,
|
|
|
PerformanceDBMainThreadGroupType,
|
|
|
PerformanceFileIOMainThreadGroupType,
|
|
|
)
|
|
@@ -30,23 +32,29 @@ from ..types import Span
|
|
|
|
|
|
|
|
|
class BaseIOMainThreadDetector(PerformanceDetector):
|
|
|
- __slots__ = ("spans_involved", "stored_problems")
|
|
|
+ __slots__ = ("stored_problems",)
|
|
|
+
|
|
|
+ SPAN_PREFIX: str # abstract
|
|
|
+ group_type: type[GroupType] # abstract
|
|
|
+
|
|
|
+ def _is_io_on_main_thread(self, span: Span) -> bool:
|
|
|
+ raise NotImplementedError
|
|
|
+
|
|
|
+ def _fingerprint(self, span_list: list[Span]) -> str:
|
|
|
+ raise NotImplementedError
|
|
|
|
|
|
def __init__(self, settings: dict[DetectorType, Any], event: dict[str, Any]) -> None:
|
|
|
super().__init__(settings, event)
|
|
|
|
|
|
- self.spans_involved = {}
|
|
|
- self.most_recent_start_time = {}
|
|
|
- self.most_recent_hash = {}
|
|
|
self.stored_problems = {}
|
|
|
- self.mapper = None
|
|
|
- self.parent_to_blocked_span = defaultdict(list)
|
|
|
+ self.mapper: ProguardMapper | None = None
|
|
|
+ self.parent_to_blocked_span: dict[str, list[Span]] = defaultdict(list)
|
|
|
|
|
|
def visit_span(self, span: Span):
|
|
|
if self._is_io_on_main_thread(span) and span.get("op", "").lower().startswith(
|
|
|
self.SPAN_PREFIX
|
|
|
):
|
|
|
- parent_span_id = span.get("parent_span_id")
|
|
|
+ parent_span_id = span["parent_span_id"]
|
|
|
self.parent_to_blocked_span[parent_span_id].append(span)
|
|
|
|
|
|
def on_complete(self):
|
|
@@ -65,7 +73,7 @@ class BaseIOMainThreadDetector(PerformanceDetector):
|
|
|
offender_spans = [span for span in span_list if "span_id" in span]
|
|
|
self.stored_problems[fingerprint] = PerformanceProblem(
|
|
|
fingerprint=fingerprint,
|
|
|
- op=span_list[0].get("op"),
|
|
|
+ op=span_list[0].get("op", ""),
|
|
|
desc=span_list[0].get("description", ""),
|
|
|
parent_span_ids=[parent_span_id],
|
|
|
type=self.group_type,
|
|
@@ -107,7 +115,7 @@ class FileIOMainThreadDetector(BaseIOMainThreadDetector):
|
|
|
Checks for a file io span on the main thread
|
|
|
"""
|
|
|
|
|
|
- __slots__ = ("spans_involved", "stored_problems")
|
|
|
+ __slots__ = ("stored_problems",)
|
|
|
|
|
|
IGNORED_EXTENSIONS = {".nib", ".plist"}
|
|
|
SPAN_PREFIX = "file"
|
|
@@ -148,7 +156,7 @@ class FileIOMainThreadDetector(BaseIOMainThreadDetector):
|
|
|
self.mapper = mapper
|
|
|
return
|
|
|
|
|
|
- def _deobfuscate_module(self, module: str) -> str:
|
|
|
+ def _deobfuscate_module(self, module: str) -> str | None:
|
|
|
if self.mapper is not None:
|
|
|
return self.mapper.remap_class(module)
|
|
|
else:
|
|
@@ -163,7 +171,7 @@ class FileIOMainThreadDetector(BaseIOMainThreadDetector):
|
|
|
else:
|
|
|
return frame.get("function", "")
|
|
|
|
|
|
- def _fingerprint(self, span_list) -> str:
|
|
|
+ def _fingerprint(self, span_list: list[Span]) -> str:
|
|
|
call_stack_strings = []
|
|
|
overall_stack = []
|
|
|
# only prepare deobfuscation once we need to fingerprint cause its expensive
|
|
@@ -202,7 +210,7 @@ class DBMainThreadDetector(BaseIOMainThreadDetector):
|
|
|
Checks for a DB span on the main thread
|
|
|
"""
|
|
|
|
|
|
- __slots__ = ("spans_involved", "stored_problems")
|
|
|
+ __slots__ = ("stored_problems",)
|
|
|
|
|
|
SPAN_PREFIX = "db"
|
|
|
type = DetectorType.DB_MAIN_THREAD
|
|
@@ -212,9 +220,6 @@ class DBMainThreadDetector(BaseIOMainThreadDetector):
|
|
|
def __init__(self, settings: dict[DetectorType, Any], event: dict[str, Any]) -> None:
|
|
|
super().__init__(settings, event)
|
|
|
|
|
|
- self.spans_involved = {}
|
|
|
- self.most_recent_start_time = {}
|
|
|
- self.most_recent_hash = {}
|
|
|
self.stored_problems = {}
|
|
|
self.mapper = None
|
|
|
self.parent_to_blocked_span = defaultdict(list)
|