Repository: getsentry/sentry

Issue:
In-App for Cocoa needs to support Multiple Images
Currently the in_app flag only covers a single image: the application. However for people with multiple frameworks we need to have a second mode where we detect the application images based on the path.



Discussion:

Resolving patch:
diff --git a/src/sentry/lang/native/plugin.py b/src/sentry/lang/native/plugin.py
--- a/src/sentry/lang/native/plugin.py
+++ b/src/sentry/lang/native/plugin.py
@@ -11,6 +11,15 @@
 
 logger = logging.getLogger(__name__)
 
+APP_BUNDLE_PATHS = (
+    '/var/containers/Bundle/Application/',
+    '/private/var/containers/Bundle/Application/',
+)
+
+NON_APP_FRAMEWORKS = (
+    '/Frameworks/libswiftCore.dylib',
+)
+
 
 def append_error(data, err):
     data.setdefault('errors', []).append(err)
@@ -34,6 +43,19 @@ def exception_from_apple_error_or_diagnosis(error, diagnosis=None):
         }
 
 
+def is_in_app(frame, app_uuid=None):
+    if app_uuid is not None:
+        frame_uuid = frame.get('uuid')
+        if frame_uuid == app_uuid:
+            return True
+    object_name = frame.get('object_name', '')
+    if not object_name.startswith(APP_BUNDLE_PATHS):
+        return False
+    if object_name.endswith(NON_APP_FRAMEWORKS):
+        return False
+    return True
+
+
 def inject_apple_backtrace(data, frames, diagnosis=None, error=None,
                            system=None):
     # TODO:
@@ -49,12 +71,6 @@ def inject_apple_backtrace(data, frames, diagnosis=None, error=None,
     longest_addr = 0
     for frame in reversed(frames):
         fn = frame.get('filename')
-        in_app = False
-
-        if app_uuid is not None:
-            frame_uuid = frame.get('uuid')
-            if frame_uuid == app_uuid:
-                in_app = True
 
         # We only record the offset if we found a symbol but we did not
         # find a line number.  In that case it's the offset in bytes from
@@ -66,7 +82,7 @@ def inject_apple_backtrace(data, frames, diagnosis=None, error=None,
             offset = frame['instruction_addr'] - frame['symbol_addr']
 
         cframe = {
-            'in_app': in_app,
+            'in_app': is_in_app(frame, app_uuid),
             'abs_path': fn,
             'filename': fn and posixpath.basename(fn) or None,
             # This can come back as `None` from the symbolizer, in which
diff --git a/src/sentry/lang/native/symbolizer.py b/src/sentry/lang/native/symbolizer.py
--- a/src/sentry/lang/native/symbolizer.py
+++ b/src/sentry/lang/native/symbolizer.py
@@ -75,26 +75,33 @@ def __enter__(self):
     def __exit__(self, *args):
         return self.symsynd_symbolizer.driver.__exit__(*args)
 
+    def _process_frame(self, frame, img):
+        rv = trim_frame(frame)
+        if img is not None:
+            rv['object_name'] = img['name']
+            rv['uuid'] = img['uuid']
+        return rv
+
     def symbolize_frame(self, frame, system_info=None):
+        img = self.images.get(frame['object_addr'])
+
         # Step one: try to symbolize with cached dsym files.
         new_frame = self.symsynd_symbolizer.symbolize_frame(frame)
         if new_frame is not None:
-            return trim_frame(new_frame)
+            return self._process_frame(new_frame, img)
 
         # If that does not work, look up system symbols.
-        img = self.images.get(frame['object_addr'])
         if img is not None:
             symbol = find_system_symbol(img, frame['instruction_addr'],
                                         system_info)
             if symbol is not None:
                 symbol = demangle_symbol(symbol) or symbol
                 rv = dict(frame, symbol_name=symbol, filename=None,
-                          line=0, column=0, uuid=img['uuid'])
-                return trim_frame(rv)
+                          line=0, column=0, uuid=img['uuid'],
+                          object_name=img['object_name'])
+                return self._process_frame(rv, img)
+
+        return self._process_frame(frame, img)
 
     def symbolize_backtrace(self, backtrace, system_info=None):
-        rv = []
-        for frame in backtrace:
-            new_frame = self.symbolize_frame(frame, system_info)
-            rv.append(new_frame or frame)
-        return rv
+        return [self.symbolize_frame(frm, system_info) for frm in backtrace]


Test patch: