Exemple #1
0
    def to_python(cls, data, slim_frames=True, rust_renormalized=RUST_RENORMALIZED_DEFAULT):
        if not rust_renormalized:
            is_valid, errors = validate_and_default_interface(data, cls.path)
            if not is_valid:
                raise InterfaceValidationError("Invalid exception")

            if not (data.get('type') or data.get('value')):
                raise InterfaceValidationError("No 'type' or 'value' present")

        if get_path(data, 'stacktrace', 'frames', filter=True):
            stacktrace = Stacktrace.to_python(
                data['stacktrace'],
                slim_frames=slim_frames,
                rust_renormalized=rust_renormalized
            )
        else:
            stacktrace = None

        if get_path(data, 'raw_stacktrace', 'frames', filter=True):
            raw_stacktrace = Stacktrace.to_python(
                data['raw_stacktrace'], slim_frames=slim_frames, raw=True,
                rust_renormalized=rust_renormalized
            )
        else:
            raw_stacktrace = None

        type = data.get('type')
        value = data.get('value')

        if not rust_renormalized:
            if isinstance(value, six.string_types):
                if type is None:
                    m = _type_value_re.match(value)
                    if m:
                        type = m.group(1)
                        value = m.group(2).strip()
            elif value is not None:
                value = json.dumps(value)

            value = trim(value, 4096)

        if data.get('mechanism'):
            mechanism = Mechanism.to_python(data['mechanism'],
                                            rust_renormalized=rust_renormalized)
        else:
            mechanism = None

        kwargs = {
            'type': trim(type, 128),
            'value': value,
            'module': trim(data.get('module'), 128),
            'mechanism': mechanism,
            'stacktrace': stacktrace,
            'thread_id': trim(data.get('thread_id'), 40),
            'raw_stacktrace': raw_stacktrace,
        }

        return cls(**kwargs)
Exemple #2
0
    def to_python(cls, data, has_system_frames=None, slim_frames=True):
        if not (data.get('type') or data.get('value')):
            raise InterfaceValidationError("No 'type' or 'value' present")

        if data.get('stacktrace') and data['stacktrace'].get('frames'):
            stacktrace = Stacktrace.to_python(
                data['stacktrace'],
                has_system_frames=has_system_frames,
                slim_frames=slim_frames,
            )
        else:
            stacktrace = None

        if data.get('raw_stacktrace') and data['raw_stacktrace'].get('frames'):
            raw_stacktrace = Stacktrace.to_python(
                data['raw_stacktrace'],
                has_system_frames=has_system_frames,
                slim_frames=slim_frames,
                raw=True
            )
        else:
            raw_stacktrace = None

        type = data.get('type')
        value = data.get('value')
        if not type and ':' in value.split(' ', 1)[0]:
            type, value = value.split(':', 1)
            # in case of TypeError: foo (no space)
            value = value.strip()

        if value is not None and not isinstance(value, six.string_types):
            value = json.dumps(value)
        value = trim(value, 4096)

        mechanism = data.get('mechanism')
        if mechanism is not None:
            if not isinstance(mechanism, dict):
                raise InterfaceValidationError('Bad value for mechanism')
            mechanism = trim(data.get('mechanism'), 4096)
            mechanism.setdefault('type', 'generic')

        kwargs = {
            'type': trim(type, 128),
            'value': value,
            'module': trim(data.get('module'), 128),
            'mechanism': mechanism,
            'stacktrace': stacktrace,
            'thread_id': trim(data.get('thread_id'), 40),
            'raw_stacktrace': raw_stacktrace,
        }

        return cls(**kwargs)
Exemple #3
0
    def get_stacktrace(self, data):
        try:
            stacktrace = Stacktrace.to_python(data['stacktrace'])
        except KeyError:
            stacktrace = None

        return stacktrace
 def test_does_not_overwrite_filename(self):
     interface = Stacktrace.to_python(
         dict(frames=[{"lineno": 1, "filename": "foo.js", "abs_path": "http://foo.com/foo.js"}])
     )
     frame = interface.frames[0]
     assert frame.filename == "foo.js"
     assert frame.abs_path == "http://foo.com/foo.js"
 def test_get_stacktrace_with_filename_and_function(self):
     event = mock.Mock(spec=Event())
     interface = Stacktrace.to_python(
         dict(frames=[{"filename": "foo", "function": "biz"}, {"filename": "bar", "function": "baz"}])
     )
     result = interface.get_stacktrace(event)
     self.assertEquals(result, 'Stacktrace (most recent call last):\n\n  File "foo", in biz\n  File "bar", in baz')
    def test_over_max(self):
        values = []
        for n in xrange(5):
            values.append({
                'filename': 'frame %d' % n,
                'vars': {'foo': 'bar'},
                'context_line': 'b',
                'pre_context': ['a'],
                'post_context': ['c'],
            })
        interface = Stacktrace.to_python({'frames': values})
        slim_frame_data(interface, 4)

        assert len(interface.frames) == 5

        for value, num in zip(interface.frames[:2], xrange(2)):
            assert value.filename == 'frame %d' % num
            assert value.vars is not None
            assert value.pre_context is not None
            assert value.post_context is not None

        for value, num in zip(interface.frames[3:], xrange(3, 5)):
            assert value.filename == 'frame %d' % num
            assert value.vars is not None
            assert value.pre_context is not None
            assert value.post_context is not None

        value = interface.frames[2]
        assert value.filename == 'frame 2'
        assert not value.vars
        assert not value.pre_context
        assert not value.post_context
Exemple #7
0
def generate_culprit(data, platform=None):
    culprit = ''

    try:
        stacktraces = [
            e['stacktrace'] for e in data['sentry.interfaces.Exception']['values']
            if e.get('stacktrace')
        ]
    except KeyError:
        stacktrace = data.get('sentry.interfaces.Stacktrace')
        if stacktrace:
            stacktraces = [stacktrace]
        else:
            stacktraces = None

    if not stacktraces:
        if 'sentry.interfaces.Http' in data:
            culprit = data['sentry.interfaces.Http'].get('url', '')
    else:
        from sentry.interfaces.stacktrace import Stacktrace
        culprit = Stacktrace.to_python(stacktraces[-1]).get_culprit_string(
            platform=platform,
        )

    return truncatechars(culprit, MAX_CULPRIT_LENGTH)
Exemple #8
0
 def test_get_stacktrace_with_module(self):
     event = mock.Mock(spec=Event())
     interface = Stacktrace.to_python(dict(frames=[{'module': 'foo'}, {'module': 'bar'}]))
     result = interface.get_stacktrace(event)
     self.assertEquals(
         result, 'Stacktrace (most recent call last):\n\n  Module "foo"\n  Module "bar"'
     )
 def test_serialize_returns_frames(self):
     interface = Stacktrace.to_python(dict(frames=[{
         'lineno': 1,
         'filename': 'foo.py',
     }]))
     result = interface.to_json()
     assert 'frames' in result
Exemple #10
0
 def test_get_stacktrace_with_filename_function_lineno_and_context(self):
     event = mock.Mock(spec=Event())
     interface = Stacktrace.to_python(
         dict(
             frames=[
                 {
                     'filename': 'foo',
                     'function': 'biz',
                     'lineno': 3,
                     'context_line': '  def foo(r):'
                 },
                 {
                     'filename': 'bar',
                     'function': 'baz',
                     'lineno': 5,
                     'context_line': '    return None'
                 },
             ]
         )
     )
     result = interface.get_stacktrace(event)
     self.assertEquals(
         result,
         'Stacktrace (most recent call last):\n\n  File "foo", line 3, in biz\n    def foo(r):\n  File "bar", line 5, in baz\n    return None'
     )
 def test_legacy_interface(self):
     # Simple test to ensure legacy data works correctly with the ``Frame``
     # objects
     event = self.event
     interface = Stacktrace.to_python(event.data['sentry.interfaces.Stacktrace'])
     assert len(interface.frames) == 1
     assert interface == event.interfaces['sentry.interfaces.Stacktrace']
Exemple #12
0
    def to_python(cls, data, has_system_frames=None):
        if not (data.get('type') or data.get('value')):
            raise InterfaceValidationError("No 'type' or 'value' present")

        if data.get('stacktrace') and data['stacktrace'].get('frames'):
            stacktrace = Stacktrace.to_python(
                data['stacktrace'],
                has_system_frames=has_system_frames,
            )
        else:
            stacktrace = None

        type = data.get('type')
        value = data.get('value')
        if not type and ':' in value.split(' ', 1)[0]:
            type, value = value.split(':', 1)
            # in case of TypeError: foo (no space)
            value = value.strip()

        if value is not None and not isinstance(value, basestring):
            value = json.dumps(value)
        value = trim(value, 4096)

        kwargs = {
            'type': trim(type, 128),
            'value': value,
            'module': trim(data.get('module'), 128),
            'stacktrace': stacktrace,
        }

        return cls(**kwargs)
Exemple #13
0
    def to_python(cls, data, has_system_frames=None, slim_frames=True):
        if not (data.get("type") or data.get("value")):
            raise InterfaceValidationError("No 'type' or 'value' present")

        if data.get("stacktrace") and data["stacktrace"].get("frames"):
            stacktrace = Stacktrace.to_python(
                data["stacktrace"], has_system_frames=has_system_frames, slim_frames=slim_frames
            )
        else:
            stacktrace = None

        if data.get("raw_stacktrace") and data["raw_stacktrace"].get("frames"):
            raw_stacktrace = Stacktrace.to_python(
                data["raw_stacktrace"], has_system_frames=has_system_frames, slim_frames=slim_frames
            )
        else:
            raw_stacktrace = None

        type = data.get("type")
        value = data.get("value")
        if not type and ":" in value.split(" ", 1)[0]:
            type, value = value.split(":", 1)
            # in case of TypeError: foo (no space)
            value = value.strip()

        if value is not None and not isinstance(value, six.string_types):
            value = json.dumps(value)
        value = trim(value, 4096)

        mechanism = data.get("mechanism")
        if mechanism is not None:
            if not isinstance(mechanism, dict):
                raise InterfaceValidationError("Bad value for mechanism")
            mechanism = trim(data.get("mechanism"), 4096)
            mechanism.setdefault("type", "generic")

        kwargs = {
            "type": trim(type, 128),
            "value": value,
            "module": trim(data.get("module"), 128),
            "mechanism": mechanism,
            "stacktrace": stacktrace,
            "thread_id": trim(data.get("thread_id"), 40),
            "raw_stacktrace": raw_stacktrace,
        }

        return cls(**kwargs)
 def test_get_traceback_response(self, get_stacktrace):
     event = mock.Mock(spec=Event())
     event.message = 'foo'
     get_stacktrace.return_value = 'bar'
     interface = Stacktrace.to_python(dict(frames=[{'lineno': 1, 'filename': 'foo.py'}]))
     result = interface.get_traceback(event)
     get_stacktrace.assert_called_once_with(event, newest_first=None)
     self.assertEquals(result, 'foo\n\nbar')
 def test_allows_abs_path_without_filename(self):
     interface = Stacktrace.to_python(dict(frames=[{
         'lineno': 1,
         'abs_path': 'foo/bar/baz.py',
     }]))
     frame = interface.frames[0]
     assert frame.filename == 'foo/bar/baz.py'
     assert frame.abs_path == frame.filename
 def test_coerces_url_filenames(self):
     interface = Stacktrace.to_python(dict(frames=[{
         'lineno': 1,
         'filename': 'http://foo.com/foo.js',
     }]))
     frame = interface.frames[0]
     assert frame.filename == '/foo.js'
     assert frame.abs_path == 'http://foo.com/foo.js'
Exemple #17
0
 def test_to_html_response(self, get_traceback):
     event = mock.Mock(spec=Event())
     event.message = 'foo'
     get_traceback.return_value = 'bar'
     interface = Stacktrace.to_python(dict(frames=[{'lineno': 1, 'filename': 'foo.py'}]))
     result = interface.to_html(event)
     get_traceback.assert_called_once_with(event, newest_first=False)
     self.assertTrue('<div class="module">' in result)
Exemple #18
0
    def get_stacktraces(self, data):
        exceptions = get_path(data, 'exception', 'values', filter=True, default=())
        stacktraces = [e['stacktrace'] for e in exceptions if e.get('stacktrace')]

        if 'stacktrace' in data:
            stacktraces.append(data['stacktrace'])

        return [(s, Stacktrace.to_python(s)) for s in stacktraces]
 def test_ignores_results_with_empty_path(self):
     interface = Stacktrace.to_python(dict(frames=[{
         'lineno': 1,
         'filename': 'http://foo.com',
     }]))
     frame = interface.frames[0]
     assert frame.filename == 'http://foo.com'
     assert frame.abs_path == frame.filename
 def test_get_traceback_response(self, get_stacktrace):
     event = mock.Mock(spec=Event())
     event.message = "foo"
     get_stacktrace.return_value = "bar"
     interface = Stacktrace.to_python(dict(frames=[{"lineno": 1, "filename": "foo.py"}]))
     result = interface.get_traceback(event)
     get_stacktrace.assert_called_once_with(event, newest_first=None)
     self.assertEquals(result, "foo\n\nbar")
 def test_does_not_overwrite_filename(self):
     interface = Stacktrace.to_python(dict(frames=[{
         'lineno': 1,
         'filename': 'foo.js',
         'abs_path': 'http://foo.com/foo.js',
     }]))
     frame = interface.frames[0]
     assert frame.filename == 'foo.js'
     assert frame.abs_path == 'http://foo.com/foo.js'
 def interface(self):
     return Stacktrace.to_python(dict(frames=[
         {
             'filename': 'foo/bar.py'
         },
         {
             'filename': 'foo/baz.py',
             'lineno': 1,
             'in_app': True,
         }
     ]))
 def test_compute_hashes(self):
     interface = Stacktrace.to_python(
         dict(
             frames=[
                 {"lineno": 1, "filename": "foo.py", "in_app": True},
                 {"lineno": 1, "filename": "bar.py", "in_app": None},
             ]
         )
     )
     result = interface.compute_hashes("python")
     assert result == [["foo.py", 1, "bar.py", 1], ["foo.py", 1]]
 def test_cocoa_culprit(self):
     stacktrace = Stacktrace.to_python(dict(frames=[
         {
             'filename': 'foo/baz.c',
             'package': '/foo/bar/baz.dylib',
             'lineno': 1,
             'in_app': True,
             'function': 'fooBar',
         }
     ]))
     assert stacktrace.get_culprit_string(platform='cocoa') == 'fooBar (baz)'
Exemple #25
0
 def test_exclude_libswiftCore_from_in_app(self):
     stacktrace = Stacktrace.to_python(dict(frames=[
         {
             'filename': 'foo/baz.c',
             'package': '/foo/bar/libswiftCore.dylib',
             'lineno': 1,
             'in_app': True,
             'function': 'fooBar',
         }
     ]))
     assert stacktrace.frames[0].in_app is False
 def test_get_hash_does_not_group_different_js_errors(self):
     interface = Stacktrace.to_python({
         'frames': [{
             'context_line': '{snip}',
             'lineno': 20,
             'filename': 'https://foo.com/index.js',
             'function': '?',
         }],
     })
     result = interface.get_hash()
     assert result == []
Exemple #27
0
    def get_stacktraces(self, data):
        try:
            stacktraces = [
                Stacktrace.to_python(e['stacktrace'])
                for e in data['sentry.interfaces.Exception']['values']
                if e.get('stacktrace')
            ]
        except KeyError:
            stacktraces = None

        return stacktraces
 def test_get_hash_does_not_discard_non_urls(self):
     interface = Stacktrace.to_python({
         'frames': [{
             'context_line': '<HTML>',
             'lineno': 1,
             'abs_path': 'foo',
             'filename': 'foo',
             'function': '?',
         }],
     })
     result = interface.get_hash()
     assert result != []
 def test_get_hash_discards_seemingly_useless_stack(self):
     interface = Stacktrace.to_python({
         'frames': [{
             'context_line': '<HTML>',
             'lineno': 1,
             'abs_path': 'http://example.com/foo',
             'filename': 'foo',
             'function': '?',
         }],
     })
     result = interface.get_hash()
     assert result == []
 def test_compute_hashes(self):
     interface = Stacktrace.to_python(dict(frames=[{
         'lineno': 1,
         'filename': 'foo.py',
         'in_app': True,
     }, {
         'lineno': 1,
         'filename': 'bar.py',
         'in_app': None,
     }]))
     result = interface.compute_hashes('python')
     assert result == [['foo.py', 1, 'bar.py', 1], ['foo.py', 1]]
Exemple #31
0
    def get_stacktraces(self, data):
        try:
            stacktraces = [
                e['stacktrace']
                for e in data['sentry.interfaces.Exception']['values']
                if e.get('stacktrace')
            ]
        except KeyError:
            stacktraces = []

        if 'sentry.interfaces.Stacktrace' in data:
            stacktraces.append(data['sentry.interfaces.Stacktrace'])

        return [
            (s, Stacktrace.to_python(s))
            for s in stacktraces
        ]
Exemple #32
0
    def test_requires_filename(self):
        with self.assertRaises(InterfaceValidationError):
            Stacktrace.to_python(dict(frames=[{}]))

        Stacktrace.to_python(dict(frames=[{
            'filename': 'foo.py',
        }]))
        Stacktrace.to_python(
            dict(frames=[{
                'lineno': 1,
                'filename': 'foo.py',
            }]))
Exemple #33
0
 def test_compute_hashes_cocoa(self):
     interface = Stacktrace.to_python(
         dict(
             frames=[
                 {
                     'lineno': 1,
                     'filename': '/foo/bar/bar.m',
                     'in_app': True,
                 }, {
                     'lineno': 1,
                     'filename': '/foo/bar/baz.m',
                     'in_app': None,
                 }
             ]
         )
     )
     result = interface.compute_hashes('cocoa')
     assert result == [['bar.m', 1, 'baz.m', 1], ['bar.m', 1]]
Exemple #34
0
 def test_compute_hashes(self):
     interface = Stacktrace.to_python(
         dict(
             frames=[
                 {
                     'lineno': 1,
                     'filename': 'a/foo.py',
                     'in_app': True,
                 }, {
                     'lineno': 1,
                     'filename': 'a/bar.py',
                     'in_app': None,
                 }
             ]
         )
     )
     result = interface.compute_hashes('python')
     assert result == [['a/foo.py', 1, 'a/bar.py', 1], ['a/foo.py', 1]]
Exemple #35
0
    def test_frame_hard_limit(self):
        hard_limit = settings.SENTRY_STACKTRACE_FRAMES_HARD_LIMIT
        interface = Stacktrace.to_python(
            {
                'frames': [
                    {
                        'filename': 'Application.java',
                        'function': 'main',
                        'lineno': i,  # linenos from 1 to the hard limit + 1
                    } for i in range(1, hard_limit + 2)
                ]
            }
        )

        assert len(interface.frames) == hard_limit
        assert interface.frames[0].lineno == 1
        assert interface.frames[-1].lineno == hard_limit + 1
        # second to last frame (lineno:250) should be removed
        assert interface.frames[-2].lineno == hard_limit - 1
Exemple #36
0
 def test_to_html_render_call(self, get_frame_context, render_to_string, get_traceback):
     event = mock.Mock(spec=Event())
     get_traceback.return_value = 'bar'
     interface = Stacktrace.to_python(dict(frames=[{'lineno': 1, 'filename': 'foo.py'}]))
     result = interface.to_html(event)
     get_traceback.assert_called_once_with(event, newest_first=False)
     get_frame_context.assert_called_once_with(event=event, is_public=False)
     render_to_string.assert_called_once_with('sentry/partial/interfaces/stacktrace.html', {
         'event': event,
         'frames': [get_frame_context.return_value],
         'stacktrace': 'bar',
         'stack_id': 'stacktrace_1',
         'system_frames': 0,
         'newest_first': False,
         'is_public': False,
         'first_frame_omitted': None,
         'last_frame_omitted': None,
     })
     self.assertEquals(result, render_to_string.return_value)
Exemple #37
0
 def test_get_stacktrace_with_filename_and_function(self):
     event = mock.Mock(spec=Event())
     interface = Stacktrace.to_python(
         dict(
             frames=[
                 {
                     'filename': 'foo',
                     'function': 'biz'
                 }, {
                     'filename': 'bar',
                     'function': 'baz'
                 }
             ]
         )
     )
     result = interface.get_stacktrace(event)
     self.assertEquals(
         result,
         'Stacktrace (most recent call last):\n\n  File "foo", in biz\n  File "bar", in baz'
     )
Exemple #38
0
    def to_python(cls, data, has_system_frames=None):
        if not (data.get('type') or data.get('value')):
            raise InterfaceValidationError("No 'type' or 'value' present")

        if data.get('stacktrace') and data['stacktrace'].get('frames'):
            stacktrace = Stacktrace.to_python(
                data['stacktrace'],
                has_system_frames=has_system_frames,
            )
        else:
            stacktrace = None

        kwargs = {
            'type': trim(data.get('type'), 128),
            'value': trim(data.get('value'), 4096),
            'module': trim(data.get('module'), 128),
            'stacktrace': stacktrace,
        }

        return cls(**kwargs)
Exemple #39
0
 def test_cocoa_strict_stacktrace(self):
     stacktrace = Stacktrace.to_python(
         dict(frames=[{
             'filename': 'foo/baz.c',
             'package': '/foo/bar/libswiftCore.dylib',
             'lineno': 1,
             'in_app': False,
             'function': 'fooBar',
         }, {
             'package': '/foo/bar/MyApp',
             'in_app': True,
             'function': 'fooBar2',
         }, {
             'filename': 'Mycontroller.swift',
             'package': '/foo/bar/MyApp',
             'in_app': True,
             'function': '-[CRLCrashAsyncSafeThread crash]',
         }]))
     assert stacktrace.get_culprit_string(
         platform='cocoa') == '-[CRLCrashAsyncSafeThread crash]'
Exemple #40
0
    def test_compute_hashes_excludes_single_frame_urls(self):
        """
        Browser JS will often throw errors (from inlined code in an HTML page)
        which contain only a single frame, no function name, and have the HTML
        document as the filename.

        In this case the hash is often not usable as the context cannot be
        trusted and the URL is dynamic.
        """
        interface = Stacktrace.to_python({
            'frames': [{
                'context_line': 'hello world',
                'abs_path': 'http://foo.com/bar/',
                'lineno': 107,
                'filename': '/bar/',
                'module': '<unknown module>',
            }],
        })
        result = interface.compute_hashes()
        assert result == []
Exemple #41
0
    def test_get_hash_ignores_singular_anonymous_frame(self):
        interface = Stacktrace.to_python({
            'frames': [
                {"abs_path": "<anonymous>", "filename": "<anonymous>", "in_app": False},
                {"function": "c",
                 "abs_path": "file:///C:/Users/redacted/AppData/Local/redacted/resources/app.asar/dojo/dojo.js",
                 "in_app": False,
                 "lineno": 1188,
                 "colno": 125,
                 "filename": "/C:/Users/redacted/AppData/Local/redacted/app-2.4.1/resources/app.asar/dojo/dojo.js"},
                {"function": "Object._createDocumentViewModel",
                 "abs_path": "file:///C:/Users/redacted/AppData/Local/redacted/app-2.4.1/resources/app.asar/dojo/dojo.js",
                 "in_app": False,
                 "lineno": 1184,
                 "colno": 92,
                 "filename": "/C:/Users/redacted/AppData/Local/redacted/app-2.4.1/resources/app.asar/dojo/dojo.js"}
            ]
        })
        result = interface.get_hash(platform='javascript')

        assert result == []
Exemple #42
0
    def test_hash_without_system_frames(self):
        interface = Stacktrace.to_python(
            dict(
                frames=[
                    {
                        'lineno': 1,
                        'filename': 'foo.py',
                        'in_app': True,
                    }, {
                        'lineno': 1,
                        'filename': 'bar.py',
                        'in_app': None,
                    }
                ]
            )
        )
        result = interface.get_hash(system_frames=False)
        assert result == ['foo.py', 1]

        result = interface.get_hash(system_frames=True)
        assert result == ['foo.py', 1, 'bar.py', 1]
Exemple #43
0
    def test_hash_without_system_frames(self):
        interface = Stacktrace.to_python(
            dict(
                frames=[
                    {
                        'lineno': 1,
                        'filename': 'foo.py',
                        'in_app': True,
                    }, {
                        'lineno': 1,
                        'filename': 'bar.py',
                        'in_app': None,
                    }
                ]
            )
        )

        result = interface.compute_hashes()
        assert sorted(result) == sorted([
            ['foo.py', 1, 'bar.py', 1],
            ['foo.py', 1],
        ])
Exemple #44
0
 def test_get_stacktrace_with_filename_function_lineno_and_context(self):
     event = mock.Mock(spec=Event())
     interface = Stacktrace.to_python(
         dict(frames=[
             {
                 'filename': 'foo',
                 'function': 'biz',
                 'lineno': 3,
                 'context_line': '  def foo(r):'
             },
             {
                 'filename': 'bar',
                 'function': 'baz',
                 'lineno': 5,
                 'context_line': '    return None'
             },
         ]))
     result = interface.get_stacktrace(event)
     self.assertEquals(
         result,
         'Stacktrace (most recent call last):\n\n  File "foo", line 3, in biz\n    def foo(r):\n  File "bar", line 5, in baz\n    return None'
     )
Exemple #45
0
def generate_culprit(data):
    from sentry.interfaces.stacktrace import Stacktrace

    try:
        stacktraces = [
            e['stacktrace']
            for e in data['sentry.interfaces.Exception']['values']
            if e.get('stacktrace')
        ]
    except KeyError:
        if 'sentry.interfaces.Stacktrace' in data:
            stacktraces = [data['sentry.interfaces.Stacktrace']]
        else:
            return ''

    if not stacktraces:
        return ''

    return truncatechars(
        Stacktrace.to_python(stacktraces[-1]).get_culprit_string(),
        MAX_CULPRIT_LENGTH
    )
Exemple #46
0
    def to_python(cls, data):
        threads = []

        for thread in data.get('values') or ():
            stacktrace = thread.get('stacktrace')
            if stacktrace is not None:
                # Special case: if the thread has no frames we set the
                # stacktrace to none.  Otherwise this will fail really
                # badly.
                if not stacktrace.get('frames'):
                    stacktrace = None
                else:
                    stacktrace = Stacktrace.to_python(stacktrace,
                                                      slim_frames=True)
            threads.append({
                'stacktrace': stacktrace,
                'id': trim(thread.get('id'), 40),
                'crashed': bool(thread.get('crashed')),
                'current': bool(thread.get('current')),
                'name': trim(thread.get('name'), 200),
            })

        return cls(values=threads)
Exemple #47
0
def generate_culprit(data):
    culprit = ''

    try:
        stacktraces = [
            e['stacktrace']
            for e in data['sentry.interfaces.Exception']['values']
            if e.get('stacktrace')
        ]
    except KeyError:
        if 'sentry.interfaces.Stacktrace' in data:
            stacktraces = [data['sentry.interfaces.Stacktrace']]
        else:
            stacktraces = None

    if not stacktraces:
        if 'sentry.interfaces.Http' in data:
            culprit = data['sentry.interfaces.Http'].get('url', '')
    else:
        from sentry.interfaces.stacktrace import Stacktrace
        culprit = Stacktrace.to_python(stacktraces[-1]).get_culprit_string()

    return truncatechars(culprit, MAX_CULPRIT_LENGTH)
Exemple #48
0
    def test_over_max(self):
        values = []
        for n in range(5):
            values.append(
                {
                    'filename': 'frame %d' % n,
                    'vars': {
                        'foo': 'bar'
                    },
                    'context_line': 'b',
                    'pre_context': ['a'],
                    'post_context': ['c'],
                }
            )
        interface = Stacktrace.to_python({'frames': values})
        slim_frame_data(interface, 4)

        assert len(interface.frames) == 5

        for value, num in zip(interface.frames[:2], range(2)):
            assert value.filename == 'frame %d' % num
            assert value.vars is not None
            assert value.pre_context is not None
            assert value.post_context is not None

        for value, num in zip(interface.frames[3:], range(3, 5)):
            assert value.filename == 'frame %d' % num
            assert value.vars is not None
            assert value.pre_context is not None
            assert value.post_context is not None

        value = interface.frames[2]
        assert value.filename == 'frame 2'
        assert not value.vars
        assert not value.pre_context
        assert not value.post_context
Exemple #49
0
def get_stacktrace(value, raw=False):
    # Special case: if the thread has no frames we set the
    # stacktrace to none.  Otherwise this will fail really
    # badly.
    if value and value.get('frames'):
        return Stacktrace.to_python(value, slim_frames=True, raw=raw)
Exemple #50
0
    def to_python(cls,
                  data,
                  slim_frames=True,
                  rust_renormalized=RUST_RENORMALIZED_DEFAULT):
        if not rust_renormalized:
            is_valid, errors = validate_and_default_interface(data, cls.path)
            if not is_valid:
                raise InterfaceValidationError("Invalid exception")

            if not (data.get('type') or data.get('value')):
                raise InterfaceValidationError("No 'type' or 'value' present")

        if get_path(data, 'stacktrace', 'frames', filter=True):
            stacktrace = Stacktrace.to_python(
                data['stacktrace'],
                slim_frames=slim_frames,
                rust_renormalized=rust_renormalized)
        else:
            stacktrace = None

        if get_path(data, 'raw_stacktrace', 'frames', filter=True):
            raw_stacktrace = Stacktrace.to_python(
                data['raw_stacktrace'],
                slim_frames=slim_frames,
                raw=True,
                rust_renormalized=rust_renormalized)
        else:
            raw_stacktrace = None

        type = data.get('type')
        value = data.get('value')

        if not rust_renormalized:
            if isinstance(value, six.string_types):
                if type is None:
                    m = _type_value_re.match(value)
                    if m:
                        type = m.group(1)
                        value = m.group(2).strip()
            elif value is not None:
                value = json.dumps(value)

            value = trim(value, 4096)

        if data.get('mechanism'):
            mechanism = Mechanism.to_python(
                data['mechanism'], rust_renormalized=rust_renormalized)
        else:
            mechanism = None

        kwargs = {
            'type': trim(type, 128),
            'value': value,
            'module': trim(data.get('module'), 128),
            'mechanism': mechanism,
            'stacktrace': stacktrace,
            'thread_id': trim(data.get('thread_id'), 40),
            'raw_stacktrace': raw_stacktrace,
        }

        return cls(**kwargs)
Exemple #51
0
def get_stacktrace(value, raw=False, rust_renormalized=RUST_RENORMALIZED_DEFAULT):
    # Special case: if the thread has no frames we set the
    # stacktrace to none.  Otherwise this will fail really
    # badly.
    if value and value.get('frames'):
        return Stacktrace.to_python(value, slim_frames=True, raw=raw)
Exemple #52
0
 def test_null_values(self):
     # TODO(markus): Should eventually generate frames: [None]
     assert Stacktrace.to_python({'frames': [None]}).to_json() == \
         {'frames': [], 'frames_omitted': None, 'registers': None}
Exemple #53
0
 def test_collapse_recursion(self):
     interface = Stacktrace.to_python(
         {
             'frames': [
                 {
                     'abs_path': 'Application.java',
                     'filename': 'Application.java',
                     'function': 'main',
                     'in_app': False,
                     'lineno': 13,
                     'module': 'io.sentry.example.Application'
                 },
                 {
                     'abs_path': 'Application.java',
                     'filename': 'Application.java',
                     'function': 'normalFunc',
                     'in_app': False,
                     'lineno': 20,
                     'module': 'io.sentry.example.Application'
                 },
                 {
                     'abs_path': 'Application.java',
                     'filename': 'Application.java',
                     'function': 'recurFunc',
                     'in_app': False,
                     'lineno': 27,
                     'module': 'io.sentry.example.Application'
                 },
                 {
                     'abs_path': 'Application.java',
                     'filename': 'Application.java',
                     'function': 'recurFunc',
                     'in_app': False,
                     'lineno': 27,
                     'module': 'io.sentry.example.Application'
                 },
                 {
                     'abs_path': 'Application.java',
                     'filename': 'Application.java',
                     'function': 'recurFunc',
                     'in_app': False,
                     'lineno': 27,
                     'module': 'io.sentry.example.Application'
                 },
                 {
                     'abs_path': 'Application.java',
                     'filename': 'Application.java',
                     'function': 'recurFunc',
                     'in_app': False,
                     'lineno': 25,
                     'module': 'io.sentry.example.Application'
                 },
                 {
                     'abs_path': 'Application.java',
                     'filename': 'Application.java',
                     'function': 'throwError',
                     'in_app': False,
                     'lineno': 32,
                     'module': 'io.sentry.example.Application'
                 }
             ]
         }
     )
     result = interface.get_hash()
     self.assertEquals(result, [
         'io.sentry.example.Application', 'main',
         'io.sentry.example.Application', 'normalFunc',
         # first call to recursive function
         'io.sentry.example.Application', 'recurFunc',
         # (exact) recursive frames omitted here
         # call from *different location* in recursive function
         'io.sentry.example.Application', 'recurFunc',
         'io.sentry.example.Application', 'throwError'
     ])
Exemple #54
0
    def test_null_values_in_frames(self):
        sink = {'frames': [{}]}

        assert Stacktrace.to_python({'frames': [{}]}).to_json() == sink
        assert Stacktrace.to_python({'frames': [{'abs_path': None}]}).to_json() == sink
Exemple #55
0
def expand_javascript_source(data, **kwargs):
    """
    Attempt to fetch source code for javascript frames.

    Frames must match the following requirements:

    - lineno >= 0
    - colno >= 0
    - abs_path is the HTTP URI to the source
    - context_line is empty

    Mutates the input ``data`` with expanded context if available.
    """
    from sentry.interfaces.stacktrace import Stacktrace

    try:
        stacktraces = [
            Stacktrace.to_python(e['stacktrace'])
            for e in data['sentry.interfaces.Exception']['values']
            if e.get('stacktrace')
        ]
    except KeyError:
        stacktraces = []

    if not stacktraces:
        logger.debug('No stacktrace for event %r', data['event_id'])
        return

    # build list of frames that we can actually grab source for
    frames = []
    for stacktrace in stacktraces:
        frames.extend([
            f for f in stacktrace.frames
            if f.lineno is not None
            and f.is_url()
        ])

    if not frames:
        logger.debug('Event %r has no frames with enough context to fetch remote source', data['event_id'])
        return data

    pending_file_list = set()
    done_file_list = set()
    sourcemap_capable = set()
    source_code = {}
    sourmap_idxs = {}

    for f in frames:
        pending_file_list.add(f.abs_path)
        if f.colno is not None:
            sourcemap_capable.add(f.abs_path)

    while pending_file_list:
        filename = pending_file_list.pop()
        done_file_list.add(filename)

        # TODO: respect cache-contro/max-age headers to some extent
        logger.debug('Fetching remote source %r', filename)
        result = fetch_url(filename)

        if result == BAD_SOURCE:
            logger.debug('Bad source file %r', filename)
            continue

        # If we didn't have a colno, a sourcemap wont do us any good
        if filename not in sourcemap_capable:
            logger.debug('Not capable of sourcemap: %r', filename)
            source_code[filename] = (result.body.splitlines(), None, None)
            continue

        sourcemap = discover_sourcemap(result)

        # TODO: we're currently running splitlines twice
        if not sourcemap:
            source_code[filename] = (result.body.splitlines(), None, None)
            for f in frames:
                if not f.module and f.abs_path == filename:
                    f.module = generate_module(filename)
            continue
        else:
            logger.debug('Found sourcemap %r for minified script %r', sourcemap[:256], result.url)

        sourcemap_key = hashlib.md5(sourcemap).hexdigest()
        source_code[filename] = (result.body.splitlines(), sourcemap, sourcemap_key)

        if sourcemap in sourmap_idxs:
            continue

        # pull down sourcemap
        index = fetch_sourcemap(sourcemap)
        if not index:
            logger.debug('Failed parsing sourcemap index: %r', sourcemap[:15])
            continue

        if is_data_uri(sourcemap):
            sourmap_idxs[sourcemap_key] = (index, result.url)
        else:
            sourmap_idxs[sourcemap_key] = (index, sourcemap)

        # queue up additional source files for download
        for source in index.sources:
            next_filename = urljoin(sourcemap, source)
            if next_filename not in done_file_list:
                if index.content:
                    source_code[next_filename] = (index.content[source], None, None)
                    done_file_list.add(next_filename)
                else:
                    pending_file_list.add(next_filename)

    last_state = None
    state = None
    has_changes = False
    for frame in frames:
        try:
            source, sourcemap, sourcemap_key = source_code[frame.abs_path]
        except KeyError:
            # we must've failed pulling down the source
            continue

        # may have had a failure pulling down the sourcemap previously
        if sourcemap_key in sourmap_idxs and frame.colno is not None:
            index, relative_to = sourmap_idxs[sourcemap_key]
            last_state = state
            state = find_source(index, frame.lineno, frame.colno)
            abs_path = urljoin(relative_to, state.src)
            logger.debug('Mapping compressed source %r to mapping in %r', frame.abs_path, abs_path)
            try:
                source, _, _ = source_code[abs_path]
            except KeyError:
                frame.data = {
                    'sourcemap': sourcemap,
                }
                logger.debug('Failed mapping path %r', abs_path)
            else:
                # Store original data in annotation
                frame.data = {
                    'orig_lineno': frame.lineno,
                    'orig_colno': frame.colno,
                    'orig_function': frame.function,
                    'orig_abs_path': frame.abs_path,
                    'orig_filename': frame.filename,
                    'sourcemap': sourcemap,
                }

                # SourceMap's return zero-indexed lineno's
                frame.lineno = state.src_line + 1
                frame.colno = state.src_col
                # The offending function is always the previous function in the stack
                # Honestly, no idea what the bottom most frame is, so we're ignoring that atm
                if last_state:
                    frame.function = last_state.name or frame.function
                else:
                    frame.function = state.name or frame.function
                frame.abs_path = abs_path
                frame.filename = state.src
                frame.module = generate_module(state.src)
        elif sourcemap_key in sourmap_idxs:
            frame.data = {
                'sourcemap': sourcemap,
            }

        has_changes = True

        # TODO: theoretically a minified source could point to another mapped, minified source
        frame.pre_context, frame.context_line, frame.post_context = get_source_context(
            source=source, lineno=frame.lineno)

    if has_changes:
        logger.debug('Updating stacktraces with expanded source context')
        for exception, stacktrace in itertools.izip(data['sentry.interfaces.Exception']['values'], stacktraces):
            exception['stacktrace'] = stacktrace.to_json()

    # Attempt to fix the culrpit now that we have potentially useful information
    culprit_frame = stacktraces[0].frames[-1]
    if culprit_frame.module and culprit_frame.function:
        data['culprit'] = truncatechars(generate_culprit(culprit_frame), MAX_CULPRIT_LENGTH)
Exemple #56
0
 def test_get_stacktrace_with_module(self):
     event = mock.Mock(spec=Event())
     interface = Stacktrace.to_python(dict(frames=[{'module': 'foo'}, {'module': 'bar'}]))
     result = interface.get_stacktrace(event)
     self.assertEquals(result, 'Stacktrace (most recent call last):\n\n  Module "foo"\n  Module "bar"')
Exemple #57
0
 def test_under_max(self):
     interface = Stacktrace.to_python({'frames': [{'filename': 'foo'}]})
     slim_frame_data(interface, 4)
     assert len(interface.frames) == 1
     assert not interface.frames_omitted