diff --git a/raven/base.py b/raven/base.py index f258aa2be..68810e50c 100644 --- a/raven/base.py +++ b/raven/base.py @@ -29,7 +29,8 @@ from raven.utils import six, json, get_versions, get_auth_header, merge_dicts from raven.utils.encoding import to_unicode from raven.utils.serializer import transform -from raven.utils.stacks import get_stack_info, iter_stack_frames, get_culprit +from raven.utils.stacks import get_stack_info, iter_stack_frames, \ + get_culprit, slim_frame_data from raven.transport.registry import TransportRegistry, default_transports __all__ = ('Client',) @@ -322,11 +323,13 @@ def build_msg(self, event_type, data=None, date=None, frames, transformer=self.transform, capture_locals=self.capture_locals, + frame_allowance=None, ) data.update({ 'stacktrace': stack_info, }) + in_app_info = False if self.include_paths: for frame in self._iter_frames(data): if frame.get('in_app') is not None: @@ -336,6 +339,7 @@ def build_msg(self, event_type, data=None, date=None, if not path: continue + in_app_info = True if path.startswith('raven.'): frame['in_app'] = False else: @@ -344,6 +348,8 @@ def build_msg(self, event_type, data=None, date=None, not any(path.startswith(x) for x in self.exclude_paths) ) + slim_frame_data(self._iter_frames(data), in_app_info=in_app_info) + if not culprit: if 'stacktrace' in data: culprit = get_culprit(data['stacktrace']['frames']) diff --git a/raven/events.py b/raven/events.py index e3dc25d62..03c871595 100644 --- a/raven/events.py +++ b/raven/events.py @@ -63,6 +63,7 @@ def capture(self, exc_info=None, **kwargs): iter_traceback_frames(exc_traceback), transformer=self.transform, capture_locals=self.client.capture_locals, + frame_allowance=None, ) exc_module = getattr(exc_type, '__module__', None) diff --git a/raven/utils/stacks.py b/raven/utils/stacks.py index 62791ff66..2a70c5eee 100644 --- a/raven/utils/stacks.py +++ b/raven/utils/stacks.py @@ -187,25 +187,52 @@ def get_frame_locals(frame, transformer=transform, max_var_size=4096): return f_vars -def slim_frame_data(frames, frame_allowance=25): +def slim_frame_data(frames, frame_allowance=25, in_app_info=False): """ Removes various excess metadata from middle frames which go beyond ``frame_allowance``. Returns ``frames``. """ - frames_len = len(frames) - - if frames_len <= frame_allowance: - return frames - + def _strip(frames): + for frame in frames: + frame.pop('vars', None) + frame.pop('pre_context', None) + frame.pop('post_context', None) + + # We have frames marked as in app, so collect everything not in app + # and strip those. + if in_app_info: + in_app_frames = [] + framework_frames = [] + + for frame in frames: + if frame.get('in_app'): + in_app_frames.append(frame) + else: + framework_frames.append(frame) + + # Fewer frames than our limit, just do nothing + if len(in_app_frames) + len(framework_frames) < frame_allowance: + return + + # App frames alone area already over limit. + if len(in_app_frames) > frame_allowance: + _strip(in_app_frames[:-frame_allowance]) + _strip(framework_frames) + return + + _strip(framework_frames[:-frame_allowance - len(in_app_frames)]) + return + + # If we don't know what's in the app, we just throw away the data in + # the first few frames. half_max = int(frame_allowance / 2) + if not in_app_info: + frames = list(frames) + for n in range(half_max, len(frames) - half_max): + _strip(frames[n]) - for n in range(half_max, frames_len - half_max): - # remove heavy components - frames[n].pop('vars', None) - frames[n].pop('pre_context', None) - frames[n].pop('post_context', None) return frames @@ -288,8 +315,9 @@ def get_stack_info(frames, transformer=transform, capture_locals=True, }) result.append(frame_result) - stackinfo = { - 'frames': slim_frame_data(result, frame_allowance=frame_allowance), - } + if frame_allowance is not None: + result = slim_frame_data(result, frame_allowance=frame_allowance) - return stackinfo + return { + 'frames': result + }