Просмотр исходного кода

difs: Support processing event with proguard mapping

Ben Lau 3 лет назад
Родитель
Сommit
73425c6b61
5 измененных файлов с 106 добавлено и 6 удалено
  1. 6 0
      difs/models.py
  2. 72 3
      difs/stacktrace_processor.py
  3. 5 2
      difs/tasks.py
  4. 18 0
      difs/tests.py
  5. 5 1
      files/admin.py

+ 6 - 0
difs/models.py

@@ -19,3 +19,9 @@ class DebugInformationFile(CreatedModel):
     file = models.ForeignKey("files.File", on_delete=models.CASCADE)
 
     data = models.JSONField(null=True, blank=True)
+
+    def is_proguard_mapping(self):
+        try:
+            return self.data["symbol_type"] == "proguard"
+        except Exception:
+            return False

+ 72 - 3
difs/stacktrace_processor.py

@@ -1,6 +1,8 @@
 import copy
 import logging
-from symbolic import Archive, SymCache, parse_addr
+from symbolic import (
+    Archive, SymCache, parse_addr, ProguardMapper
+)
 from symbolic.demangle import demangle_name
 
 alternative_arch = {
@@ -39,7 +41,7 @@ def digest_symbol(symbol):
 
 
 def getLogger():
-    return logging.getLogger("glitchtip.difs")  # FIXME
+    return logging.getLogger("glitchtip.difs")
 
 
 class StacktraceProcessor:
@@ -51,6 +53,14 @@ class StacktraceProcessor:
     def __init__(self):
         pass
 
+    @classmethod
+    def is_supported(cls, event_json, dif):
+        if cls.is_android_event(event_json):
+            return dif.is_proguard_mapping()
+
+        # It need more data to determine the exact condition
+        return True
+
     @classmethod
     def resolve_stacktrace(cls, event, symbol_file):
         # Process event
@@ -69,6 +79,57 @@ class StacktraceProcessor:
             getLogger().error(f"StacktraceProcessor: Invalid event: {event}")
             return
 
+        if cls.is_android_event(event):
+            return cls.resolve_proguard_stacktrace(stacktrace, symbol_file)
+
+        return cls.resolve_native_stacktrace(
+            stacktrace,
+            symbol_file,
+            arch=arch
+        )
+
+    @classmethod
+    def resolve_proguard_stacktrace(cls, stacktrace, symbol_file):
+        try:
+            mapper = ProguardMapper.open(symbol_file)
+        except Exception as e:
+            getLogger().error(
+                f"StacktraceProcessor: Open symbol file failed: {e}")
+            return
+
+        try:
+            frames = stacktrace.get("frames")
+            score = 0
+            resolved_frames = copy.copy(frames)
+            for index, frame in enumerate(frames):
+                frame = copy.copy(frame)
+                module = frame.get("module")
+                function = frame.get("function")
+                lineno = frame.get("lineno")
+                if lineno is None:
+                    continue
+                result = mapper.remap_frame(module, function, lineno)
+                if len(result) > 0:
+                    remapped_frame = result[0]
+                    frame["resolved"] = True
+                    frame["filename"] = remapped_frame.file
+                    frame["lineNo"] = remapped_frame.line
+                    frame["function"] = remapped_frame.method
+                    frame["module"] = remapped_frame.class_name
+                    score = score + 1
+
+                resolved_frames[index] = frame
+
+            return ResolvedStacktrace(
+                score=score,
+                frames=resolved_frames
+            )
+
+        except Exception as e:
+            getLogger().error(f"StacktraceProcessor: Unexpected error: {e}")
+
+    @classmethod
+    def resolve_native_stacktrace(cls, stacktrace, symbol_file, arch=None):
         # Open symbol file
         try:
             archive = Archive.open(symbol_file)
@@ -76,7 +137,8 @@ class StacktraceProcessor:
             obj = find_arch_object(archive, arch)
             sym_cache = SymCache.from_object(obj)
         except Exception as e:
-            getLogger().error(f"StacktraceProcessor: Open symbol file failed: {e}")
+            getLogger().error(
+                f"StacktraceProcessor: Open symbol file failed: {e}")
             return
 
         try:
@@ -122,3 +184,10 @@ class StacktraceProcessor:
         except Exception as e:
             getLogger().error(f"StacktraceProcessor: Unexpected error: {e}")
             pass
+
+    @classmethod
+    def is_android_event(cls, event):
+        try:
+            return event["contexts"]["os"]["name"] == "Android"
+        except Exception:
+            return False

+ 5 - 2
difs/tasks.py

@@ -8,9 +8,9 @@ from hashlib import sha1
 from symbolic import (
     Archive,
 )
-from .models import DebugInformationFile
+from difs.models import DebugInformationFile
 from events.models import Event
-from .stacktrace_processor import StacktraceProcessor
+from difs.stacktrace_processor import StacktraceProcessor
 from django.conf import settings
 
 
@@ -49,6 +49,7 @@ def difs_assemble(project_slug, name, checksum, chunks, debug_id):
     except Exception as e:
         getLogger().error(f"difs_assemble: {e}")
 
+
 def difs_run_resolve_stacktrace(event_id):
     if settings.GLITCHTIP_ENABLE_DIFS:
         difs_resolve_stacktrace.delay(event_id)
@@ -72,6 +73,8 @@ def difs_resolve_stacktrace(event_id):
         resolved_stracktrackes = []
 
         for dif in difs:
+            if StacktraceProcessor.is_supported(event_json, dif) is False:
+                continue
             blobs = dif.file.blobs.all()
             with difs_concat_file_blobs_to_disk(blobs) as symbol_file:
                 remapped_stacktrace = StacktraceProcessor.resolve_stacktrace(

+ 18 - 0
difs/tests.py

@@ -16,6 +16,24 @@ import contextlib
 from unittest.mock import patch, MagicMock
 
 
+class DebugInformationFileModelTestCase(GlitchTipTestCase):
+
+    def test_is_proguard(self):
+        dif = baker.make(
+            "difs.DebugInformationFile"
+        )
+
+        self.assertEqual(dif.is_proguard_mapping(), False)
+
+        dif = baker.make(
+            "difs.DebugInformationFile",
+            data={
+                "symbol_type": "proguard"
+            }
+        )
+        self.assertEqual(dif.is_proguard_mapping(), True)
+
+
 class DifsAssembleAPITestCase(GlitchTipTestCase):
     def setUp(self):
         self.create_user_and_project()

+ 5 - 1
files/admin.py

@@ -1,9 +1,13 @@
 from django.contrib import admin
-from .models import FileBlob
+from .models import FileBlob, File
 
 
 class FileBlobAdmin(admin.ModelAdmin):
     pass
 
+class FileAdmin(admin.ModelAdmin):
+    pass
+
 
 admin.site.register(FileBlob, FileBlobAdmin)
+admin.site.register(File, FileAdmin)