Exemple #1
0
 def test_get_hash_with_only_required_vars(self):
     interface = Stacktrace(frames=[{
         'lineno': 1,
         'filename': 'foo.py',
     }])
     result = interface.get_hash()
     self.assertEquals(result, ['foo.py', 1])
Exemple #2
0
 def test_serialize_returns_frames(self):
     interface = Stacktrace(frames=[{
         'lineno': 1,
         'filename': 'foo.py',
     }])
     result = interface.serialize()
     assert 'frames' in result
Exemple #3
0
 def test_get_composite_hash_uses_exception_if_present(self):
     interface = Stacktrace(
         frames=[{"context_line": "foo bar", "lineno": 1, "filename": "foo.py", "function": "bar"}]
     )
     interface_exc = Exception(type="exception", value="bar")
     result = interface.get_composite_hash({"sentry.interfaces.Exception": interface_exc})
     self.assertEquals(result[-1], "exception")
Exemple #4
0
 def test_serialize_returns_frames(self):
     interface = Stacktrace(frames=[{
         'lineno': 1,
         'filename': 'foo.py',
     }])
     result = interface.serialize()
     self.assertTrue('frames' in result)
 def test_get_composite_hash_uses_exception_value_if_no_type_or_stack(self):
     interface = Stacktrace(frames=[])
     interface_exc = Exception(value='bar')
     result = interface.get_composite_hash({
         'sentry.interfaces.Exception': interface_exc,
     })
     self.assertEquals(result[-1], 'bar')
Exemple #6
0
 def test_get_hash_with_only_required_vars(self):
     interface = Stacktrace(frames=[{
         'lineno': 1,
         'filename': 'foo.py',
     }])
     result = interface.get_hash()
     self.assertEquals(result, ['foo.py', 1])
Exemple #7
0
 def test_get_hash_ignores_filename_if_http(self):
     interface = Stacktrace(frames=[{
         'context_line': 'hello world',
         'filename': 'http://foo.com/foo.py',
     }])
     result = interface.get_hash()
     self.assertEquals(result, ['hello world'])
Exemple #8
0
 def test_get_hash_ignores_filename_if_https(self):
     interface = Stacktrace(frames=[{
         'context_line': 'hello world',
         'filename': 'https://foo.com/foo.py',
     }])
     result = interface.get_hash()
     self.assertEquals(result, ['hello world'])
Exemple #9
0
 def test_get_traceback_response(self, get_stacktrace):
     event = mock.Mock(spec=Event())
     event.message = "foo"
     get_stacktrace.return_value = "bar"
     interface = Stacktrace(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")
Exemple #10
0
 def test_get_hash_sanitizes_block_functions(self):
     # This is Ruby specific
     interface = Stacktrace(frames=[{
         'filename': 'foo.py',
         'function': 'block in _conditional_callback_around_233',
     }])
     result = interface.get_hash()
     self.assertEquals(result, ['foo.py', 'block'])
Exemple #11
0
 def test_get_traceback_response(self, get_stacktrace):
     event = mock.Mock(spec=Event())
     event.message = 'foo'
     get_stacktrace.return_value = 'bar'
     interface = Stacktrace(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')
Exemple #12
0
 def test_get_traceback_response(self, get_stacktrace):
     event = mock.Mock(spec=Event)
     event.message = 'foo'
     get_stacktrace.return_value = 'bar'
     interface = Stacktrace(frames=[])
     result = interface.get_traceback(event)
     get_stacktrace.assert_called_once_with(event)
     self.assertEquals(result, 'foo\n\nbar')
Exemple #13
0
 def test_get_traceback_response(self, get_stacktrace):
     event = mock.Mock(spec=Event())
     event.message = 'foo'
     get_stacktrace.return_value = 'bar'
     interface = Stacktrace(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')
Exemple #14
0
 def test_get_hash_uses_module_over_filename(self):
     interface = Stacktrace(frames=[{
         'lineno': 1,
         'filename': 'foo.py',
         'module': 'foo'
     }])
     result = interface.get_hash()
     self.assertEquals(result, ['foo', 1])
Exemple #15
0
 def test_to_html_response(self, get_traceback):
     event = mock.Mock(spec=Event())
     event.message = 'foo'
     get_traceback.return_value = 'bar'
     interface = Stacktrace(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 #16
0
 def test_to_html_response(self, get_traceback):
     event = mock.Mock(spec=Event())
     event.message = 'foo'
     get_traceback.return_value = 'bar'
     interface = Stacktrace(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 #17
0
 def test_get_hash_uses_function_over_lineno(self):
     interface = Stacktrace(frames=[{
         'lineno': 1,
         'filename': 'foo.py',
         'function': 'bar'
     }])
     result = interface.get_hash()
     self.assertEquals(result, ['foo.py', 'bar'])
Exemple #18
0
 def test_to_string_returns_stacktrace(self, get_stacktrace):
     event = mock.Mock(spec=Event())
     interface = Stacktrace(frames=[])
     result = interface.to_string(event)
     get_stacktrace.assert_called_once_with(event,
                                            system_frames=False,
                                            max_frames=5)
     self.assertEquals(result, get_stacktrace.return_value)
Exemple #19
0
 def test_get_stacktrace_with_module(self):
     event = mock.Mock(spec=Event())
     interface = Stacktrace(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 #20
0
 def test_get_composite_hash_uses_exception_value_if_no_type_or_stack(self):
     interface = Stacktrace(frames=[])
     interface_exc = Exception(value='bar')
     result = interface.get_composite_hash({
         'sentry.interfaces.Exception':
         interface_exc,
     })
     self.assertEquals(result[-1], 'bar')
Exemple #21
0
 def test_get_traceback_response(self, get_stacktrace):
     event = mock.Mock(spec=Event)
     event.message = 'foo'
     get_stacktrace.return_value = 'bar'
     interface = Stacktrace(frames=[])
     result = interface.get_traceback(event)
     get_stacktrace.assert_called_once_with(event)
     self.assertEquals(result, 'foo\n\nbar')
Exemple #22
0
 def test_to_html_response(self, get_traceback):
     event = mock.Mock(spec=Event)
     event.message = 'foo'
     get_traceback.return_value = 'bar'
     interface = Stacktrace(frames=[])
     result = interface.to_html(event)
     get_traceback.assert_called_once_with(event)
     self.assertTrue('<div id="traceback" class="module">' in result)
Exemple #23
0
 def test_to_html_response(self, get_traceback):
     event = mock.Mock(spec=Event)
     event.message = 'foo'
     get_traceback.return_value = 'bar'
     interface = Stacktrace(frames=[])
     result = interface.to_html(event)
     get_traceback.assert_called_once_with(event)
     self.assertTrue('<div id="traceback" class="module">' in result)
Exemple #24
0
 def test_get_hash_uses_function_over_lineno(self):
     interface = Stacktrace(frames=[{
         'lineno': 1,
         'filename': 'foo.py',
         'function': 'bar'
     }])
     result = interface.get_hash()
     self.assertEquals(result, ['foo.py', 'bar'])
Exemple #25
0
 def test_get_hash_uses_module_over_filename(self):
     interface = Stacktrace(frames=[{
         'lineno': 1,
         'filename': 'foo.py',
         'module': 'foo'
     }])
     result = interface.get_hash()
     self.assertEquals(result, ['foo', 1])
Exemple #26
0
 def test_get_hash_sanitizes_erb_templates(self):
     # This is Ruby specific
     interface = Stacktrace(frames=[{
         'filename': 'foo.html.erb',
         'function': '_foo_html_erb__3327151541118998292_70361296749460',
     }])
     result = interface.get_hash()
     self.assertEquals(result, [
         'foo.html.erb', '_foo_html_erb__<anon>_<anon>',
     ])
Exemple #27
0
    def test_requires_filename(self):
        with self.assertRaises(AssertionError):
            Stacktrace(frames=[{}]).validate()

        Stacktrace(frames=[{
            'filename': 'foo.py',
        }]).validate()
        Stacktrace(frames=[{
            'lineno': 1,
            'filename': 'foo.py',
        }]).validate()
Exemple #28
0
 def test_requires_filename_and_lineno(self):
     self.assertRaises(AssertionError, Stacktrace, frames=[{
         'lineno': 1,
     }])
     Stacktrace(frames=[{
         'filename': 'foo.py',
     }])
     Stacktrace(frames=[{
         'lineno': 1,
         'filename': 'foo.py',
     }])
Exemple #29
0
 def test_to_html_render_call(self, render_to_string, get_traceback):
     event = mock.Mock(spec=Event)
     get_traceback.return_value = 'bar'
     interface = Stacktrace(frames=[])
     result = interface.to_html(event)
     get_traceback.assert_called_once_with(event)
     render_to_string.assert_called_once_with('sentry/partial/interfaces/stacktrace.html', {
         'event': event,
         'frames': [],
         'stacktrace': 'bar',
     })
     self.assertEquals(result, render_to_string.return_value)
Exemple #30
0
 def test_get_composite_hash_uses_exception_if_present(self):
     interface = Stacktrace(frames=[{
         'context_line': 'foo bar',
         'lineno': 1,
         'filename': 'foo.py',
         'function': 'bar'
     }])
     interface_exc = Exception(type='exception', value='bar')
     result = interface.get_composite_hash({
         'sentry.interfaces.Exception': interface_exc,
     })
     self.assertEquals(result[-1], 'exception')
Exemple #31
0
 def test_to_html_render_call(self, render_to_string, get_traceback):
     event = mock.Mock(spec=Event)
     get_traceback.return_value = 'bar'
     interface = Stacktrace(frames=[])
     result = interface.to_html(event)
     get_traceback.assert_called_once_with(event)
     render_to_string.assert_called_once_with('sentry/partial/interfaces/stacktrace.html', {
         'event': event,
         'frames': [],
         'stacktrace': 'bar',
     })
     self.assertEquals(result, render_to_string.return_value)
Exemple #32
0
 def test_get_stacktrace_with_filename_function_lineno_and_context(self):
     event = mock.Mock(spec=Event())
     interface = Stacktrace(
         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 #33
0
 def test_get_stacktrace_with_filename_and_function(self):
     event = mock.Mock(spec=Event())
     interface = Stacktrace(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 #34
0
 def test_to_html_render_call(self, render_to_string, get_traceback):
     event = mock.Mock(spec=Event())
     get_traceback.return_value = 'bar'
     interface = Stacktrace(frames=[{'lineno': 1, 'filename': 'foo.py'}])
     result = interface.to_html(event)
     get_traceback.assert_called_once_with(event, newest_first=False)
     render_to_string.assert_called_once_with('sentry/partial/interfaces/stacktrace.html', {
         'event': event,
         'frames': [{'function': None, 'abs_path': None, 'start_lineno': None, 'lineno': 1, 'context': [], 'vars': [], 'in_app': True, 'filename': 'foo.py'}],
         'stacktrace': 'bar',
         'system_frames': 0,
         'newest_first': False,
     })
     self.assertEquals(result, render_to_string.return_value)
Exemple #35
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(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(interface.frames[0], 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',
         'system_frames': 0,
         'newest_first': False,
         'is_public': False,
     })
     self.assertEquals(result, render_to_string.return_value)
Exemple #36
0
 def test_legacy_interface(self):
     # Simple test to ensure legacy data works correctly with the ``Frame``
     # objects
     event = self.event
     interface = Stacktrace(**event.data['sentry.interfaces.Stacktrace'])
     assert len(interface.frames) == 5
     assert interface == event.interfaces['sentry.interfaces.Stacktrace']
Exemple #37
0
 def test_ignores_results_with_empty_path(self):
     interface = Stacktrace(frames=[{
         'lineno': 1,
         'filename': 'http://foo.com',
     }])
     frame = interface.frames[0]
     assert frame.filename == 'http://foo.com'
     assert frame.abs_path == frame.filename
Exemple #38
0
 def test_coerces_url_filenames(self):
     interface = Stacktrace(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 #39
0
 def interface(self):
     return Stacktrace(frames=[{
         'filename': 'foo/bar.py'
     }, {
         'filename': 'foo/baz.py',
         'lineno': 1,
         'in_app': True,
     }])
Exemple #40
0
 def test_allows_abs_path_without_filename(self):
     interface = Stacktrace(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
Exemple #41
0
 def test_get_stacktrace_with_filename_function_lineno_and_context(self):
     event = mock.Mock(spec=Event())
     interface = Stacktrace(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 #42
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(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,
         })
     self.assertEquals(result, render_to_string.return_value)
Exemple #43
0
    def test_get_hash_sanitizes_versioned_filenames(self):
        # This is Ruby specific
        interface = Stacktrace(frames=[{
            'filename': '/data/foo/releases/20140114151955/app/views/foo.html.erb',
            'context_line': '<% if @hotels.size > 0 %>',
        }])
        result = interface.get_hash()
        self.assertEquals(result, [
            '/data/foo/releases/<version>/app/views/foo.html.erb',
            '<% if @hotels.size > 0 %>',
        ])

        interface = Stacktrace(frames=[{
            'filename': '20140114151955/app/views/foo.html.erb',
            'context_line': '<% if @hotels.size > 0 %>',
        }])
        result = interface.get_hash()
        self.assertEquals(result, [
            '<version>/app/views/foo.html.erb',
            '<% if @hotels.size > 0 %>',
        ])
Exemple #44
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(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 #45
0
 def test_get_hash_uses_context_line_over_function(self):
     interface = Stacktrace(
         frames=[{"context_line": "foo bar", "lineno": 1, "filename": "foo.py", "function": "bar"}]
     )
     result = interface.get_hash()
     self.assertEquals(result, ["foo.py", "foo bar"])
Exemple #46
0
 def test_serialize_returns_frames(self):
     interface = Stacktrace(frames=[{"lineno": 1, "filename": "foo.py"}])
     result = interface.serialize()
     assert "frames" in result
Exemple #47
0
 def test_get_stacktrace_with_module(self):
     event = mock.Mock(spec=Event())
     interface = Stacktrace(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 #48
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 import Stacktrace

    try:
        stacktrace = Stacktrace(**data['sentry.interfaces.Stacktrace'])
    except KeyError:
        logger.debug('No stacktrace for event %r', data['event_id'])
        return

    # build list of frames that we can actually grab source for
    frames = [
        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

    file_list = set()
    sourcemap_capable = set()
    source_code = {}
    sourcemaps = {}

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

    while file_list:
        filename = file_list.pop()

        # 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:
            continue

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

        # TODO: we're currently running splitlines twice
        sourcemap = discover_sourcemap(result, logger=logger)
        source_code[filename] = (result.body.splitlines(), sourcemap)
        if sourcemap:
            logger.debug('Found sourcemap %r for minified script %r', sourcemap, result.url)

        # pull down sourcemap
        if sourcemap and sourcemap not in sourcemaps:
            index = fetch_sourcemap(sourcemap, logger=logger)
            if not index:
                continue

            sourcemaps[sourcemap] = index

            # queue up additional source files for download
            for source in index.sources:
                if source not in source_code:
                    file_list.add(urljoin(result.url, source))

    has_changes = False
    for frame in frames:
        try:
            source, sourcemap = 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 in sourcemaps and frame.colno is not None:
            state = find_source(sourcemaps[sourcemap], frame.lineno, frame.colno)
            # TODO: is this urljoin right? (is it relative to the sourcemap or the originating file)
            abs_path = urljoin(sourcemap, 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:
                pass
            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
                frame.function = state.name
                frame.abs_path = abs_path
                frame.filename = state.src

        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:
        data['sentry.interfaces.Stacktrace'] = stacktrace.serialize()
Exemple #49
0
    def convert_legacy_kwargs(self, kwargs):
        from sentry.interfaces import Http, User, Exception, Stacktrace, Template
        from sentry.utils.template_info import get_template_info

        data = kwargs.pop('data', None) or {}
        sentry = data.pop('__sentry__', None) or {}

        result = {
            'event_id': kwargs.pop('message_id', None),
            'level': kwargs.pop('level', None),
            'logger': kwargs.pop('logger', None),
            'server_name': kwargs.pop('server_name', None),
            'message': kwargs.pop('message', ''),
            'culprit': kwargs.pop('view', None),
            'timestamp': kwargs.pop('timestamp', None),
        }

        result = dict((k, v) for k, v in result.iteritems() if v is not None)

        class_name = kwargs.pop('class_name', None)
        if class_name:
            result['message'] = '%s: %s' % (class_name, result['message'])

        if 'url' in data or 'url' in kwargs and 'META' in data:
            meta = data.pop('META', {})
            if 'GET' in data:
                del data['GET']
            result['sentry.interfaces.Http'] = Http(
                url=data.pop('url', None) or kwargs['url'],
                method=meta.get('REQUEST_METHOD'),
                query_string=meta.get('QUERY_STRING'),
                data=data.pop('POST', None),
                cookies=data.pop('COOKIES', None),
                env=meta,
            ).serialize()

        if 'user' in sentry:
            user = sentry['user']
            result['sentry.interfaces.User'] = User(
                **user
            ).serialize()

        if 'exception' in sentry:
            exc = sentry['exception']
            result['sentry.interfaces.Exception'] = Exception(
                type=exc[0],
                value=u' '.join(itertools.imap(unicode, exc[1])),
            ).serialize()

        if 'frames' in sentry:
            frames = []
            keys = ('filename', 'function', 'vars', 'pre_context', 'context_line', 'post_context', 'lineno')
            for frame in sentry['frames']:
                if 'vars' in frame:
                    frame['vars'] = dict(frame['vars'])
                frames.append(dict((k, v) for k, v in frame.iteritems() if k in keys))

            if frames:
                result['sentry.interfaces.Stacktrace'] = Stacktrace(
                    frames=frames,
                ).serialize()

        if 'template' in sentry:
            template = sentry['template']
            print get_template_info(template)
            result['sentry.interfaces.Template'] = Template(
                **get_template_info(template)
            ).serialize()

        result['extra'] = data
        return result
Exemple #50
0
 def test_get_stacktrace_with_only_filename(self):
     event = mock.Mock(spec=Event())
     interface = Stacktrace(frames=[{'filename': 'foo'}, {'filename': 'bar'}])
     result = interface.get_stacktrace(event)
     self.assertEquals(result, 'Stacktrace (most recent call last):\n\n  File "foo"\n  File "bar"')
Exemple #51
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 import Stacktrace

    try:
        stacktraces = [
            Stacktrace(**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)
            continue

        sourcemap = discover_sourcemap(result)

        # TODO: we're currently running splitlines twice
        if not sourcemap:
            source_code[filename] = (result.body.splitlines(), None)
            for f in frames:
                if 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_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)
                    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 = 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 in sourmap_idxs and frame.colno is not None:
            index, relative_to = sourmap_idxs[sourcemap]
            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
                frame.function = last_state.name if last_state else state.name
                frame.abs_path = abs_path
                frame.filename = state.src
                frame.module = generate_module(state.src) or '<unknown module>'
        elif sourcemap 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.serialize()

        # Attempt to fix the culrpit now that we have 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 #52
0
 def test_get_stacktrace_with_filename_and_function(self):
     event = mock.Mock(spec=Event())
     interface = Stacktrace(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 #53
0
 def test_get_stacktrace_with_filename_function_lineno_and_context(self):
     event = mock.Mock(spec=Event())
     interface = Stacktrace(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 #54
0
 def test_get_hash_uses_module_over_filename(self):
     interface = Stacktrace(frames=[{"lineno": 1, "filename": "foo.py", "module": "foo"}])
     result = interface.get_hash()
     self.assertEquals(result, ["foo", 1])
Exemple #55
0
 def test_to_string_returns_stacktrace(self, get_stacktrace):
     event = mock.Mock(spec=Event)
     interface = Stacktrace(frames=[])
     result = interface.to_string(event)
     get_stacktrace.assert_called_once_with(event)
     self.assertEquals(result, get_stacktrace.return_value)
Exemple #56
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 import Stacktrace

    try:
        stacktraces = [
            Stacktrace(**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)
            continue

        sourcemap = discover_sourcemap(result)
        source_code[filename] = (result.body.splitlines(), sourcemap)

        # TODO: we're currently running splitlines twice
        if sourcemap:
            logger.debug('Found sourcemap %r for minified script %r',
                         sourcemap, result.url)
        elif sourcemap in sourmap_idxs or not sourcemap:
            continue

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

        sourmap_idxs[sourcemap] = index

        # queue up additional source files for download
        for source in index.sources:
            next_filename = urljoin(result.url, source)
            if next_filename not in done_file_list:
                pending_file_list.add(next_filename)

    has_changes = False
    for frame in frames:
        try:
            source, sourcemap = 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 in sourmap_idxs and frame.colno is not None:
            state = find_source(sourmap_idxs[sourcemap], frame.lineno,
                                frame.colno)
            # TODO: is this urljoin right? (is it relative to the sourcemap or the originating file)
            abs_path = urljoin(sourcemap, 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
                frame.function = state.name
                frame.abs_path = abs_path
                frame.filename = state.src

        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.serialize()