def _emit(self, record, **kwargs): data = {} for k, v in record.__dict__.iteritems(): if '.' not in k and k not in ('culprit',): continue data[k] = v stack = getattr(record, 'stack', None) if stack is True: stack = iter_stack_frames() if stack: frames = [] started = False last_mod = '' for frame in iter_stack_frames(): if not started: f_globals = getattr(frame, 'f_globals', {}) module_name = f_globals.get('__name__', '') if last_mod.startswith('logging') and not module_name.startswith('logging'): started = True else: last_mod = module_name continue frames.append(frame) stack = frames extra = getattr(record, 'data', {}) # Add in all of the data from the record that we aren't already capturing for k in record.__dict__.keys(): if k in ('stack', 'name', 'args', 'msg', 'levelno', 'exc_text', 'exc_info', 'data', 'created', 'levelname', 'msecs', 'relativeCreated'): continue extra[k] = record.__dict__[k] date = datetime.datetime.utcfromtimestamp(record.created) # If there's no exception being processed, exc_info may be a 3-tuple of None # http://docs.python.org/library/sys.html#sys.exc_info if record.exc_info and all(record.exc_info): handler = self.client.get_handler('raven.events.Exception') data.update(handler.capture(exc_info=record.exc_info)) data['checksum'] = handler.get_hash(data) data['level'] = record.levelno data['logger'] = record.name return self.client.capture('Message', message=record.msg, params=record.args, stack=stack, data=data, extra=extra, date=date, **kwargs)
def _add_exception_info(self, data, record): """Adds sentry interfaces Exception and Stacktrace. See http://sentry.readthedocs.org/en/latest/developer/interfaces/index.html for more information on Sentry interfaces.""" type_, value, tb = record.exc_info data[SENTRY_INTERFACES_EXCEPTION] = {"type": str(type_), "value": str(value), "module": record.module } stack = inspect.getinnerframes(tb) # This next python statement copied pretty much verbatim from # raven-python (https://github.com/getsentry/raven-python). # # raven-python is: # # Copyright (c) 2009 David Cramer and individual contributors. # All rights reserved. frames = varmap( lambda k, v: shorten( v, string_length=self.string_max_length, list_length=self.list_max_length), get_stack_info(iter_stack_frames(stack))) # end of copied code data['sentry.interfaces.Stacktrace'] = { 'frames': frames } return data
def _emit(self, record, **kwargs): data = {} for k, v in record.__dict__.iteritems(): if '.' not in k and k not in ('culprit',): continue data[k] = v stack = getattr(record, 'stack', None) if stack is True: stack = iter_stack_frames() if stack: frames = [] started = False last_mod = '' for item in stack: if isinstance(item, (list, tuple)): frame, lineno = item else: frame, lineno = item, item.f_lineno if not started: f_globals = getattr(frame, 'f_globals', {}) module_name = f_globals.get('__name__', '') if (last_mod and last_mod.startswith('logging')) \ and not module_name.startswith('logging'): started = True else: last_mod = module_name continue frames.append((frame, lineno)) stack = frames extra = getattr(record, 'data', {}) # Add in all of the data from the record that we aren't already capturing for k in record.__dict__.keys(): if k in ('stack', 'name', 'args', 'msg', 'levelno', 'exc_text', 'exc_info', 'data', 'created', 'levelname', 'msecs', 'relativeCreated'): continue if k.startswith('_'): continue extra[k] = record.__dict__[k] date = datetime.datetime.utcfromtimestamp(record.created) # If there's no exception being processed, exc_info may be a 3-tuple of None # http://docs.python.org/library/sys.html#sys.exc_info if record.exc_info and all(record.exc_info): handler = self.client.get_handler('raven.events.Exception') data.update(handler.capture(exc_info=record.exc_info)) data['checksum'] = handler.get_hash(data) data['level'] = record.levelno data['logger'] = record.name return self.client.capture('Message', message=record.msg, params=record.args, stack=stack, data=data, extra=extra, date=date, **kwargs)
def _emit(self, record, **kwargs): data = {} for k, v in record.__dict__.iteritems(): if '.' not in k: continue data[k] = v stack = getattr(record, 'stack', None) if stack is True: stack = iter_stack_frames() if stack: frames = [] started = False last_mod = '' for frame in iter_stack_frames(): if not started: f_globals = getattr(frame, 'f_globals', {}) module_name = f_globals.get('__name__', '') if last_mod.startswith('logging') and not module_name.startswith('logging'): started = True else: last_mod = module_name continue frames.append(frame) stack = frames extra = getattr(record, 'data', {}) date = datetime.datetime.utcfromtimestamp(record.created) # If there's no exception being processed, exc_info may be a 3-tuple of None # http://docs.python.org/library/sys.html#sys.exc_info if record.exc_info and all(record.exc_info): handler = self.client.get_handler('raven.events.Exception') data.update(handler.capture(exc_info=record.exc_info)) data['level'] = record.levelno data['logger'] = record.name return self.client.capture('Message', message=record.msg, params=record.args, stack=stack, data=data, extra=extra, date=date, **kwargs)
def _emit(self, record, **kwargs): data, extra = extract_extra(record) stack = getattr(record, 'stack', None) if stack is True: stack = iter_stack_frames() if stack: stack = self._get_targetted_stack(stack, record) date = datetime.datetime.utcfromtimestamp(record.created) event_type = 'raven.events.Message' handler_kwargs = { 'params': record.args, } try: handler_kwargs['message'] = text_type(record.msg) except UnicodeDecodeError: # Handle binary strings where it should be unicode... handler_kwargs['message'] = repr(record.msg)[1:-1] try: handler_kwargs['formatted'] = text_type(record.message) except UnicodeDecodeError: # Handle binary strings where it should be unicode... handler_kwargs['formatted'] = repr(record.message)[1:-1] # If there's no exception being processed, exc_info may be a 3-tuple of None # http://docs.python.org/library/sys.html#sys.exc_info if record.exc_info and all(record.exc_info): # capture the standard message first so that we ensure # the event is recorded as an exception, in addition to having our # message interface attached handler = self.client.get_handler(event_type) data.update(handler.capture(**handler_kwargs)) event_type = 'raven.events.Exception' handler_kwargs = {'exc_info': record.exc_info} data['level'] = record.levelno data['logger'] = record.name kwargs['tags'] = tags = {} if self.tags: tags.update(self.tags) tags.update(getattr(record, 'tags', {})) kwargs.update(handler_kwargs) sample_rate = extra.pop('sample_rate', None) return self.client.capture(event_type, stack=stack, data=data, extra=extra, date=date, sample_rate=sample_rate, **kwargs)
def emit(self, record): if record.levelno <= logging.ERROR and self.can_record(record): request = None exc_info = None for frame_info in getouterframes(currentframe()): frame = frame_info[0] if not request: request = frame.f_locals.get('request', None) if not request: view = frame.f_locals.get('self', None) try: request = getattr(view, 'request', None) except RuntimeError: request = None if not exc_info: exc_info = frame.f_locals.get('exc_info', None) if not hasattr(exc_info, '__getitem__'): exc_info = None if request and exc_info: break if exc_info: record.exc_info = exc_info record.stack = iter_stack_frames(getinnerframes(exc_info[2])) if request: try: body_pos = request.stdin.tell() request.stdin.seek(0) body = request.stdin.read() request.stdin.seek(body_pos) http = dict(headers=request.environ, url=request.getURL(), method=request.method, host=request.environ.get('REMOTE_ADDR', ''), data=body) if 'HTTP_USER_AGENT' in http['headers']: if 'User-Agent' not in http['headers']: http['headers']['User-Agent'] = http['headers'][ 'HTTP_USER_AGENT'] if 'QUERY_STRING' in http['headers']: http['query_string'] = http['headers']['QUERY_STRING'] setattr(record, 'request', http) user = request.get('AUTHENTICATED_USER', None) if user is not None and user != nobody: user_dict = { 'id': user.getId(), 'email': user.getProperty('email') or '' } else: user_dict = {} setattr(record, 'user', user_dict) except (AttributeError, KeyError): logger.warning('Could not extract data from request', exc_info=True) return super(ZopeSentryHandler, self).emit(record)
def emit(self, record): if record.levelno <= logging.ERROR and self.can_record(record): request = None exc_info = None for frame_info in getouterframes(currentframe()): frame = frame_info[0] if not request: request = frame.f_locals.get('request', None) if not request: view = frame.f_locals.get('self', None) try: request = getattr(view, 'request', None) except RuntimeError: request = None if not exc_info: exc_info = frame.f_locals.get('exc_info', None) if not hasattr(exc_info, '__getitem__'): exc_info = None if request and exc_info: break if exc_info: record.exc_info = exc_info record.stack = \ iter_stack_frames(getinnerframes(exc_info[2])) if request: try: body_pos = request.stdin.tell() request.stdin.seek(0) body = request.stdin.read() request.stdin.seek(body_pos) http = dict(headers=request.environ, url=request.getURL(), method=request.method, host=request.environ.get('REMOTE_ADDR', ''), data=body) if 'HTTP_USER_AGENT' in http['headers']: if 'User-Agent' not in http['headers']: http['headers']['User-Agent'] = \ http['headers']['HTTP_USER_AGENT'] if 'QUERY_STRING' in http['headers']: http['query_string'] = http['headers']['QUERY_STRING'] setattr(record, 'request', http) user = request.get('AUTHENTICATED_USER', None) if user is not None and user != nobody: user_dict = { 'id': user.getId(), 'email': user.getProperty('email') or '', } else: user_dict = {} setattr(record, 'user', user_dict) except (AttributeError, KeyError): logger.warning('Could not extract data from request', exc_info=True) return super(ZopeSentryHandler, self).emit(record)
def _emit(self, record, **kwargs): data, extra = extract_extra(record) stack = getattr(record, 'stack', None) if stack is True: stack = iter_stack_frames() if stack: stack = self._get_targetted_stack(stack, record) date = datetime.datetime.utcfromtimestamp(record.created) event_type = 'raven.events.Message' handler_kwargs = { 'params': record.args, } try: handler_kwargs['message'] = text_type(record.msg) except UnicodeDecodeError: # Handle binary strings where it should be unicode... handler_kwargs['message'] = repr(record.msg)[1:-1] try: handler_kwargs['formatted'] = text_type(record.message) except UnicodeDecodeError: # Handle binary strings where it should be unicode... handler_kwargs['formatted'] = repr(record.message)[1:-1] # If there's no exception being processed, exc_info may be a 3-tuple of None # http://docs.python.org/library/sys.html#sys.exc_info if record.exc_info and all(record.exc_info): # capture the standard message first so that we ensure # the event is recorded as an exception, in addition to having our # message interface attached handler = self.client.get_handler(event_type) data.update(handler.capture(**handler_kwargs)) event_type = 'raven.events.Exception' handler_kwargs = {'exc_info': record.exc_info} data['level'] = record.levelno data['logger'] = record.name kwargs['tags'] = tags = {} if self.tags: tags.update(self.tags) tags.update(getattr(record, 'tags', {})) kwargs.update(handler_kwargs) sample_rate = extra.pop('sample_rate', None) return self.client.capture( event_type, stack=stack, data=data, extra=extra, date=date, sample_rate=sample_rate, **kwargs)
def test_explicit_stack(self): self.logger.info('This is a test of stacks', extra={'stack': iter_stack_frames()}) self.assertEquals(len(self.client.events), 1) event = self.client.events.pop(0) self.assertEquals(event['culprit'], 'tests.handlers.logging.tests.test_explicit_stack') self.assertEquals(event['message'], 'This is a test of stacks') self.assertFalse('sentry.interfaces.Exception' in event) self.assertTrue('sentry.interfaces.Message' in event) msg = event['sentry.interfaces.Message'] self.assertEquals(msg['message'], 'This is a test of stacks') self.assertEquals(msg['params'], ()) self.assertTrue('sentry.interfaces.Stacktrace' in event)
def _emit(self, record, **kwargs): data = { 'user': {'id': self.client.name} } extra = getattr(record, 'data', None) if not isinstance(extra, dict): if extra: extra = {'data': extra} else: extra = {} for k, v in six.iteritems(vars(record)): if k in RESERVED: continue if k.startswith('_'): continue if '.' not in k and k not in ('culprit', 'server_name'): extra[k] = v else: data[k] = v stack = getattr(record, 'stack', None) if stack is True: stack = iter_stack_frames() if stack: stack = self._get_targetted_stack(stack, record) date = datetime.datetime.utcfromtimestamp(record.created) event_type = 'raven.events.Message' handler_kwargs = { 'params': record.args, } try: handler_kwargs['message'] = six.text_type(record.msg) except UnicodeDecodeError: # Handle binary strings where it should be unicode... handler_kwargs['message'] = repr(record.msg)[1:-1] try: handler_kwargs['formatted'] = six.text_type(record.message) except UnicodeDecodeError: # Handle binary strings where it should be unicode... handler_kwargs['formatted'] = repr(record.message)[1:-1] # If there's no exception being processed, exc_info may be a 3-tuple of None # http://docs.python.org/library/sys.html#sys.exc_info try: exc_info = self._exc_info(record) except Exception, ex: log.info('Unable to retrieve exception info - %s', ex, exc_info=True) exc_info = None
def test_explicit_stack(self): record = self.make_record('This is a test of stacks', extra={'stack': iter_stack_frames()}) self.handler.emit(record) self.assertEqual(len(self.client.events), 1) event = self.client.events.pop(0) assert 'stacktrace' in event self.assertTrue('message' in event, event) self.assertEqual(event['message'], 'This is a test of stacks') assert 'exception' not in event self.assertTrue('sentry.interfaces.Message' in event) msg = event['sentry.interfaces.Message'] self.assertEqual(msg['message'], 'This is a test of stacks') self.assertEqual(msg['params'], ())
def test_stack_explicit_frames(self): frames = inspect.stack() self.client.create_from_text('test', stack=iter_stack_frames(frames)) self.assertEquals(len(self.client.events), 1) event = self.client.events.pop(0) self.assertEquals(event['message'], 'test') data = event['data']['__sentry__'] self.assertTrue('frames' in data) self.assertEquals(len(frames), len(data['frames'])) for frame, frame_i in zip(frames, data['frames']): self.assertEquals(frame[0].f_code.co_filename, frame_i['filename']) self.assertEquals(frame[0].f_code.co_name, frame_i['function'])
def test_explicit_stack(self): self.logger.info("This is a test of stacks", extra={"stack": iter_stack_frames()}) self.assertEquals(len(self.client.events), 1) event = self.client.events.pop(0) self.assertTrue("culprit" in event, event) self.assertEquals(event["culprit"], "tests.handlers.logging.tests.test_explicit_stack") self.assertTrue("message" in event, event) self.assertEquals(event["message"], "This is a test of stacks") self.assertFalse("sentry.interfaces.Exception" in event) self.assertTrue("sentry.interfaces.Message" in event) msg = event["sentry.interfaces.Message"] self.assertEquals(msg["message"], "This is a test of stacks") self.assertEquals(msg["params"], ()) self.assertTrue("sentry.interfaces.Stacktrace" in event)
def test_explicit_stack(self): self.logger.info('This is a test of stacks', extra={'stack': iter_stack_frames()}) self.assertEquals(len(self.client.events), 1) event = self.client.events.pop(0) self.assertTrue('culprit' in event, event) self.assertEquals(event['culprit'], 'tests.handlers.logging.tests.test_explicit_stack') self.assertTrue('message' in event, event) self.assertEquals(event['message'], 'This is a test of stacks') self.assertFalse('sentry.interfaces.Exception' in event) self.assertTrue('sentry.interfaces.Message' in event) msg = event['sentry.interfaces.Message'] self.assertEquals(msg['message'], 'This is a test of stacks') self.assertEquals(msg['params'], ()) self.assertTrue('sentry.interfaces.Stacktrace' in event)
def test_stack_explicit_frames(self): def bar(): return inspect.stack() frames = bar() self.client.captureMessage("test", stack=iter_stack_frames(frames)) self.assertEquals(len(self.client.events), 1) event = self.client.events.pop(0) self.assertEquals(event["message"], "test") self.assertTrue("sentry.interfaces.Stacktrace" in event) self.assertEquals(len(frames), len(event["sentry.interfaces.Stacktrace"]["frames"])) for frame, frame_i in zip(frames, event["sentry.interfaces.Stacktrace"]["frames"]): self.assertEquals(frame[0].f_code.co_filename, frame_i["abs_path"]) self.assertEquals(frame[0].f_code.co_name, frame_i["function"])
def test_stack_explicit_frames(self): def bar(): return inspect.stack() frames = bar() self.client.captureMessage('test', stack=iter_stack_frames(frames)) self.assertEquals(len(self.client.events), 1) event = self.client.events.pop(0) self.assertEquals(event['message'], 'test') assert 'stacktrace' in event self.assertEquals(len(frames), len(event['stacktrace']['frames'])) for frame, frame_i in zip(frames, event['stacktrace']['frames']): self.assertEquals(frame[0].f_code.co_filename, frame_i['abs_path']) self.assertEquals(frame[0].f_code.co_name, frame_i['function'])
def test_stack_explicit_frames(self): def bar(): return inspect.stack() frames = bar() self.client.create_from_text('test', stack=iter_stack_frames(frames)) self.assertEquals(len(self.client.events), 1) event = self.client.events.pop(0) self.assertEquals(event['message'], 'test') data = event['data']['__sentry__'] self.assertTrue('frames' in data) self.assertEquals(len(frames), len(data['frames'])) for frame, frame_i in zip(frames, data['frames']): self.assertEquals(frame[0].f_code.co_filename, frame_i['filename']) self.assertEquals(frame[0].f_code.co_name, frame_i['function'])
def raven_log(self, event): f = event["log_failure"] stack = None extra = dict() tb = f.getTracebackObject() if not tb: # include the current stack for at least some context stack = list(iter_stack_frames())[4:] # approx. extra = dict(no_failure_tb=True) extra.update( log_format=event.get('log_format'), log_namespace=event.get('log_namespace'), client_info=event.get('client_info'), ) reactor.callFromThread( self.raven_client.captureException, exc_info=(f.type, f.value, tb), stack=stack, extra=extra, ) # just in case del tb
def _add_exception_info(self, data, record): """Adds sentry interfaces Exception and Stacktrace. See http://sentry.readthedocs.org/en/latest/developer/interfaces/index.html for more information on Sentry interfaces.""" type_, value, _ = record.exc_info data[SENTRY_INTERFACES_EXCEPTION] = {"type": str(type_), "value": str(value), "module": record.module } # This next python statement copied pretty much verbatim from # raven-python (https://github.com/getsentry/raven-python). # # raven-python is: # # Copyright (c) 2009 David Cramer and individual contributors. # All rights reserved. frames = varmap( lambda k, v: shorten( v, string_length=self.string_max_length, list_length=self.list_max_length), get_stack_info(iter_stack_frames())) # end of copied code # filter out unwanted frames.. # don't know how to do this earlier, so we just do a # post-processing step and filter out unwanted frames frames = [frame for frame in frames if frame['module'] not in self.EXCLUDE_MODULES] data['sentry.interfaces.Stacktrace'] = { 'frames': frames } return data
def raven_log(self, event): f = event["log_failure"] stack = None extra = dict() tb = f.getTracebackObject() if not tb: # include the current stack for at least some # context. sentry's expecting that "Frames should be # sorted from oldest to newest." stack = reversed(list(iter_stack_frames())[5:]) # approx. extra = dict(no_failure_tb=True) extra.update( log_format=event.get('log_format'), log_namespace=event.get('log_namespace'), client_info=event.get('client_info'), ) reactor.callFromThread( self.raven_client.captureException, exc_info=(f.type, f.value, tb), stack=stack, extra=extra, ) # just in case del tb
def test_logger(self): client = TempStoreClient(include_paths=['tests', 'raven']) handler = SentryHandler(client) logger = self.logger logger.handlers = [] logger.addHandler(handler) logger.error('This is a test error') self.assertEquals(len(client.events), 1) event = client.events.pop(0) self.assertEquals(event['logger'], __name__) self.assertEquals(event['level'], logging.ERROR) self.assertEquals(event['message'], 'This is a test error') self.assertFalse('sentry.interfaces.Stacktrace' in event) self.assertFalse('sentry.interfaces.Exception' in event) self.assertTrue('sentry.interfaces.Message' in event) msg = event['sentry.interfaces.Message'] self.assertEquals(msg['message'], 'This is a test error') self.assertEquals(msg['params'], ()) logger.warning('This is a test warning') self.assertEquals(len(client.events), 1) event = client.events.pop(0) self.assertEquals(event['logger'], __name__) self.assertEquals(event['level'], logging.WARNING) self.assertEquals(event['message'], 'This is a test warning') self.assertFalse('sentry.interfaces.Stacktrace' in event) self.assertFalse('sentry.interfaces.Exception' in event) self.assertTrue('sentry.interfaces.Message' in event) msg = event['sentry.interfaces.Message'] self.assertEquals(msg['message'], 'This is a test warning') self.assertEquals(msg['params'], ()) logger.info('This is a test info with a url', extra=dict(data=dict(url='http://example.com', ), )) self.assertEquals(len(client.events), 1) event = client.events.pop(0) self.assertEquals(event['extra']['url'], 'http://example.com') self.assertFalse('sentry.interfaces.Stacktrace' in event) self.assertFalse('sentry.interfaces.Exception' in event) self.assertTrue('sentry.interfaces.Message' in event) msg = event['sentry.interfaces.Message'] self.assertEquals(msg['message'], 'This is a test info with a url') self.assertEquals(msg['params'], ()) try: raise ValueError('This is a test ValueError') except ValueError: logger.info('This is a test info with an exception', exc_info=True) self.assertEquals(len(client.events), 1) event = client.events.pop(0) self.assertEquals(event['message'], 'This is a test info with an exception') self.assertTrue('sentry.interfaces.Stacktrace' in event) self.assertTrue('sentry.interfaces.Exception' in event) exc = event['sentry.interfaces.Exception'] self.assertEquals(exc['type'], 'ValueError') self.assertEquals(exc['value'], 'This is a test ValueError') self.assertTrue('sentry.interfaces.Message' in event) msg = event['sentry.interfaces.Message'] self.assertEquals(msg['message'], 'This is a test info with an exception') self.assertEquals(msg['params'], ()) # test stacks logger.info('This is a test of stacks', extra={'stack': True}) self.assertEquals(len(client.events), 1) event = client.events.pop(0) self.assertTrue('sentry.interfaces.Stacktrace' in event) frames = event['sentry.interfaces.Stacktrace']['frames'] self.assertNotEquals(len(frames), 1) frame = frames[0] self.assertEquals(frame['module'], __name__) self.assertFalse('sentry.interfaces.Exception' in event) self.assertTrue('sentry.interfaces.Message' in event) msg = event['sentry.interfaces.Message'] self.assertEquals(msg['message'], 'This is a test of stacks') self.assertEquals(msg['params'], ()) self.assertEquals(event['culprit'], 'tests.handlers.logging.tests.test_logger') self.assertEquals(event['message'], 'This is a test of stacks') # test no stacks logger.info('This is a test of no stacks', extra={'stack': False}) self.assertEquals(len(client.events), 1) event = client.events.pop(0) self.assertEquals(event.get('culprit'), None) self.assertEquals(event['message'], 'This is a test of no stacks') self.assertFalse('sentry.interfaces.Stacktrace' in event) self.assertFalse('sentry.interfaces.Exception' in event) self.assertTrue('sentry.interfaces.Message' in event) msg = event['sentry.interfaces.Message'] self.assertEquals(msg['message'], 'This is a test of no stacks') self.assertEquals(msg['params'], ()) # test args logger.info('This is a test of %s', 'args') self.assertEquals(len(client.events), 1) event = client.events.pop(0) self.assertEquals(event['message'], 'This is a test of args') self.assertFalse('sentry.interfaces.Stacktrace' in event) self.assertFalse('sentry.interfaces.Exception' in event) self.assertTrue('sentry.interfaces.Message' in event) msg = event['sentry.interfaces.Message'] self.assertEquals(msg['message'], 'This is a test of %s') self.assertEquals(msg['params'], ('args', )) # test explicit stack logger.info('This is a test of stacks', extra={'stack': iter_stack_frames()}) self.assertEquals(len(client.events), 1) event = client.events.pop(0) self.assertEquals(event['culprit'], 'tests.handlers.logging.tests.test_logger') self.assertEquals(event['message'], 'This is a test of stacks') self.assertFalse('sentry.interfaces.Exception' in event) self.assertTrue('sentry.interfaces.Message' in event) msg = event['sentry.interfaces.Message'] self.assertEquals(msg['message'], 'This is a test of stacks') self.assertEquals(msg['params'], ()) self.assertTrue('sentry.interfaces.Stacktrace' in event)
def _emit(self, record, **kwargs): data = {} extra = getattr(record, 'data', None) if not isinstance(extra, dict): if extra: extra = {'data': extra} else: extra = {} for k, v in six.iteritems(vars(record)): if k in RESERVED: continue if k.startswith('_'): continue if '.' not in k and k not in ('culprit', 'server_name', 'fingerprint'): extra[k] = v else: data[k] = v stack = getattr(record, 'stack', None) if stack is True: stack = iter_stack_frames() if stack: stack = self._get_targetted_stack(stack, record) date = datetime.datetime.utcfromtimestamp(record.created) event_type = 'raven.events.Message' handler_kwargs = { 'params': record.args, } try: handler_kwargs['message'] = six.text_type(record.msg) except UnicodeDecodeError: # Handle binary strings where it should be unicode... handler_kwargs['message'] = repr(record.msg)[1:-1] try: handler_kwargs['formatted'] = six.text_type(record.message) except UnicodeDecodeError: # Handle binary strings where it should be unicode... handler_kwargs['formatted'] = repr(record.message)[1:-1] # If there's no exception being processed, exc_info may be a 3-tuple of None # http://docs.python.org/library/sys.html#sys.exc_info if record.exc_info and all(record.exc_info): # capture the standard message first so that we ensure # the event is recorded as an exception, in addition to having our # message interface attached handler = self.client.get_handler(event_type) data.update(handler.capture(**handler_kwargs)) event_type = 'raven.events.Exception' handler_kwargs = {'exc_info': record.exc_info} # HACK: discover a culprit when we normally couldn't elif not (data.get('stacktrace') or data.get('culprit')) and (record.name or record.funcName): culprit = label_from_frame({'module': record.name, 'function': record.funcName}) if culprit: data['culprit'] = culprit data['level'] = record.levelno data['logger'] = record.name if hasattr(record, 'tags'): kwargs['tags'] = record.tags elif self.tags: kwargs['tags'] = self.tags kwargs.update(handler_kwargs) return self.client.capture( event_type, stack=stack, data=data, extra=extra, date=date, **kwargs)
def base_kwargs(extra=None): kwargs = {'stack': iter_stack_frames(get_stacks())} if extra is not None: kwargs['extra'] = extra return kwargs
def _emit(self, record, **kwargs): data, extra = extract_extra(record) # Use client name as default user id data.setdefault('user', {'id': self.client.name}) # Retrieve stack stack = getattr(record, 'stack', None) if stack is True: stack = iter_stack_frames() if stack: stack = self._get_targetted_stack(stack, record) # Build message date = datetime.datetime.utcfromtimestamp(record.created) event_type = 'raven.events.Message' handler_kwargs = { 'params': record.args, } try: handler_kwargs['message'] = text_type(record.msg) except UnicodeDecodeError: # Handle binary strings where it should be unicode... handler_kwargs['message'] = repr(record.msg)[1:-1] try: handler_kwargs['formatted'] = text_type(record.message) except UnicodeDecodeError: # Handle binary strings where it should be unicode... handler_kwargs['formatted'] = repr(record.message)[1:-1] # Retrieve exception information from record try: exc_info = self._exc_info(record) except Exception as ex: log.info('Unable to retrieve exception info - %s', ex, exc_info=True) exc_info = None # Parse exception information exception_hash = None # If there's no exception being processed, exc_info may be a 3-tuple of None # http://docs.python.org/library/sys.html#sys.exc_info if exc_info and len(exc_info) == 3 and all(exc_info): message = handler_kwargs.get('formatted') # Replace exception messages with more helpful details if not record.exc_info and message and RE_TRACEBACK_HEADER.match(message): # Generate new record title handler_kwargs['formatted'] = '%s\n\n%s' % ( self._generate_title(record, exc_info), message ) elif not record.exc_info: log.debug("Message %r doesn't match traceback header", message) # capture the standard message first so that we ensure # the event is recorded as an exception, in addition to having our # message interface attached handler = self.client.get_handler(event_type) data.update(handler.capture(**handler_kwargs)) event_type = 'raven.events.Exception' handler_kwargs = {'exc_info': exc_info} # Calculate exception hash exception_hash = ErrorHasher.hash(exc_info=exc_info) # HACK: discover a culprit when we normally couldn't elif not (data.get('stacktrace') or data.get('culprit')) and (record.name or record.funcName): culprit = self._label_from_frame({'module': record.name, 'function': record.funcName}) if culprit: data['culprit'] = culprit data['level'] = record.levelno data['logger'] = record.name # Store record `tags` in message if hasattr(record, 'tags'): kwargs['tags'] = record.tags elif self.tags: kwargs['tags'] = self.tags # Store `exception_hash` in message (if defined) if exception_hash: if 'tags' not in kwargs: kwargs['tags'] = {} kwargs['tags']['exception.hash'] = exception_hash kwargs.update(handler_kwargs) return self.client.capture( event_type, stack=stack, data=data, extra=extra, date=date, **kwargs )
def _emit(self, record, **kwargs): data = {} extra = getattr(record, 'data', None) if not isinstance(extra, dict): if extra: extra = {'data': extra} else: extra = {} for k, v in iteritems(vars(record)): if k in RESERVED: continue if k.startswith('_'): continue if '.' not in k and k not in ('culprit', 'server_name', 'fingerprint'): extra[k] = v else: data[k] = v stack = getattr(record, 'stack', None) if stack is True: stack = iter_stack_frames() if stack: stack = self._get_targetted_stack(stack, record) date = datetime.datetime.utcfromtimestamp(record.created) event_type = 'raven.events.Message' handler_kwargs = {'params': record.args} try: handler_kwargs['message'] = text_type(record.msg) except UnicodeDecodeError: handler_kwargs['message'] = repr(record.msg)[1:-1] try: handler_kwargs['formatted'] = text_type(record.message) except UnicodeDecodeError: handler_kwargs['formatted'] = repr(record.message)[1:-1] if record.exc_info and all(record.exc_info): handler = self.client.get_handler(event_type) data.update(handler.capture(**handler_kwargs)) event_type = 'raven.events.Exception' handler_kwargs = {'exc_info': record.exc_info} elif not (data.get('stacktrace') or data.get('culprit')) and (record.name or record.funcName): culprit = label_from_frame({ 'module': record.name, 'function': record.funcName }) if culprit: data['culprit'] = culprit data['level'] = record.levelno data['logger'] = record.name if hasattr(record, 'tags'): kwargs['tags'] = record.tags elif self.tags: kwargs['tags'] = self.tags kwargs.update(handler_kwargs) return self.client.capture(event_type, stack=stack, data=data, extra=extra, date=date, **kwargs)
def emit(self, record): if record.levelno <= logging.ERROR: request = None exc_info = None for frame_info in getouterframes(currentframe()): frame = frame_info[0] if not request: request = frame.f_locals.get("request", None) # i.e. collective.solr sets request as string if isinstance(request, basestring): request = None if not request: view = frame.f_locals.get("self", None) try: request = getattr(view, "request", None) except RuntimeError: request = None if not exc_info: exc_info = frame.f_locals.get("exc_info", None) if not hasattr(exc_info, "__getitem__"): exc_info = None if request and exc_info: break if exc_info: record.exc_info = exc_info record.stack = iter_stack_frames(getinnerframes(exc_info[2])) if request: try: body_pos = request.stdin.tell() request.stdin.seek(0) body = request.stdin.read() request.stdin.seek(body_pos) # not all request.environ keys are json serializable envCopy = {} for key in request.environ: try: json.dumps(request.environ[key]) envCopy[key] = request.environ[key] except (TypeError, UnicodeDecodeError, UnicodeEncodeError): pass http = dict( headers=envCopy, url=request.getURL(), method=request.method, host=request.environ.get("REMOTE_ADDR", ""), data=body, ) if "HTTP_USER_AGENT" in http["headers"]: if "User-Agent" not in http["headers"]: http["headers"]["User-Agent"] = http["headers"]["HTTP_USER_AGENT"] if "QUERY_STRING" in http["headers"]: http["query_string"] = http["headers"]["QUERY_STRING"] setattr(record, "sentry.interfaces.Http", http) user = request.get("AUTHENTICATED_USER", None) if user is not None and user != nobody: email = "" if hasattr(user, "getProperty") and user.getProperty("email"): email = user.getProperty("email") user_dict = dict(id=user.getId(), is_authenticated=True, email=email) else: user_dict = {"is_authenticated": False} setattr(record, "sentry.interfaces.User", user_dict) except (AttributeError, KeyError): logger.warning("Could not extract data from request", exc_info=True) return super(ZopeSentryHandler, self).emit(record)
def capture(self, event_type, data=None, date=None, time_spent=None, event_id=None, extra=None, stack=None, **kwargs): """ Captures and processes an event and pipes it off to SentryClient.send. To use structured data (interfaces) with capture: >>> capture('Message', message='foo', data={ >>> 'sentry.interfaces.Http': { >>> 'url': '...', >>> 'data': {}, >>> 'query_string': '...', >>> 'method': 'POST', >>> }, >>> 'logger': 'logger.name', >>> 'site': 'site.name', >>> }, extra={ >>> 'key': 'value', >>> }) The finalized ``data`` structure contains the following (some optional) builtin values: >>> { >>> # the culprit and version information >>> 'culprit': 'full.module.name', # or /arbitrary/path >>> >>> # all detectable installed modules >>> 'modules': { >>> 'full.module.name': 'version string', >>> }, >>> >>> # arbitrary data provided by user >>> 'extra': { >>> 'key': 'value', >>> } >>> } :param event_type: the module path to the Event class. Builtins can use shorthand class notation and exclude the full module path. :param tags: a list of tuples (key, value) specifying additional tags for event :param data: the data base, useful for specifying structured data interfaces. Any key which contains a '.' will be assumed to be a data interface. :param date: the datetime of this event :param time_spent: a float value representing the duration of the event :param event_id: a 32-length unique string identifying this event :param extra: a dictionary of additional standard metadata :param culprit: a string representing the cause of this event (generally a path to a function) :return: a 32-length string identifying this event """ if data is None: data = {} if extra is None: extra = {} if date is None: date = datetime.datetime.utcnow() if stack is None: stack = self.auto_log_stacks if '.' not in event_type: # Assume it's a builtin event_type = 'raven.events.%s' % event_type handler = self.get_handler(event_type) result = handler.capture(**kwargs) # data (explicit) culprit takes over auto event detection culprit = result.pop('culprit', None) if data.get('culprit'): culprit = data['culprit'] for k, v in result.iteritems(): if k not in data: data[k] = v else: data[k].update(v) if stack and 'sentry.interfaces.Stacktrace' not in data: if stack is True: frames = iter_stack_frames() else: frames = stack data.update({ 'sentry.interfaces.Stacktrace': { 'frames': varmap(lambda k, v: shorten(v), get_stack_info(frames)) }, }) if 'sentry.interfaces.Stacktrace' in data and not culprit: culprit = get_culprit(data['sentry.interfaces.Stacktrace']['frames'], self.include_paths, self.exclude_paths) if not data.get('level'): data['level'] = logging.ERROR data['modules'] = get_versions(self.include_paths) data['server_name'] = self.name data.setdefault('extra', {}) data.setdefault('level', logging.ERROR) # Shorten lists/strings for k, v in extra.iteritems(): data['extra'][k] = shorten(v, string_length=self.string_max_length, list_length=self.list_max_length) if culprit: data['culprit'] = culprit checksum = hashlib.md5() for bit in handler.get_hash(data): checksum.update(to_unicode(bit) or '') data['checksum'] = checksum = checksum.hexdigest() # create ID client-side so that it can be passed to application event_id = uuid.uuid4().hex data['event_id'] = event_id # Run the data through processors for processor in self.get_processors(): data.update(processor.process(data)) # Make sure all data is coerced data = transform(data) if not date: date = datetime.datetime.utcnow() data['message'] = handler.to_string(data) data.update({ 'timestamp': date, 'time_spent': time_spent, 'event_id': event_id, 'project': self.project, }) self.send(**data) return (event_id, checksum)
def _emit(self, record, **kwargs): data = {} for k, v in record.__dict__.iteritems(): if '.' not in k and k not in ('culprit', ): continue data[k] = v stack = getattr(record, 'stack', None) if stack is True: stack = iter_stack_frames() if stack: # we might need to traverse this multiple times, so coerce it to a list stack = list(stack) frames = [] started = False last_mod = '' for item in stack: if isinstance(item, (list, tuple)): frame, lineno = item else: frame, lineno = item, item.f_lineno if not started: f_globals = getattr(frame, 'f_globals', {}) module_name = f_globals.get('__name__', '') if (last_mod and last_mod.startswith('logging')) \ and not module_name.startswith('logging'): started = True else: last_mod = module_name continue frames.append((frame, lineno)) # We must've not found a starting point if not frames: frames = stack stack = frames extra = getattr(record, 'data', None) if not isinstance(extra, dict): if extra: extra = {'data': extra} else: extra = {} # Add in all of the data from the record that we aren't already capturing for k in record.__dict__.keys(): if k in RESERVED: continue if k.startswith('_'): continue extra[k] = record.__dict__[k] date = datetime.datetime.utcfromtimestamp(record.created) event_type = 'raven.events.Message' handler_kwargs = {'message': record.msg, 'params': record.args} # If there's no exception being processed, exc_info may be a 3-tuple of None # http://docs.python.org/library/sys.html#sys.exc_info if record.exc_info and all(record.exc_info): # capture the standard message first so that we ensure # the event is recorded as an exception, in addition to having our # message interface attached handler = self.client.get_handler(event_type) data.update(handler.capture(**handler_kwargs)) # ensure message is propagated, otherwise the exception will overwrite it data['message'] = handler.to_string(data) event_type = 'raven.events.Exception' handler_kwargs = {'exc_info': record.exc_info} # HACK: discover a culprit when we normally couldn't elif not (data.get('sentry.interfaces.Stacktrace') or data.get('culprit')) and (record.name or record.funcName): culprit = label_from_frame({ 'module': record.name, 'function': record.funcName }) if culprit: data['culprit'] = culprit data['level'] = record.levelno data['logger'] = record.name if hasattr(record, 'tags'): kwargs['tags'] = record.tags kwargs.update(handler_kwargs) return self.client.capture(event_type, stack=stack, data=data, extra=extra, date=date, **kwargs)
def process(self, **kwargs): """ Processes the message before passing it on to the server. This includes: - extracting stack frames (for non exceptions) - identifying module versions - coercing data - generating message identifiers You may pass the ``stack`` parameter to specify an explicit stack, or simply to tell Raven that you want to capture the stacktrace. To automatically grab the stack from a non-exception: >>> client.process(message='test', stack=True) To capture an explicit stack (e.g. something from a different threadframe?): >>> import inspect >>> from raven.utils import iter_stack_frames >>> client.process(message='test', stack=iter_stack_frames(inspect.stack())) """ if kwargs.get('data'): # Ensure we're not changing the original data which was passed # to Sentry data = kwargs.get('data').copy() else: data = {} if '__sentry__' not in data: data['__sentry__'] = {} get_stack = kwargs.pop('stack', self.auto_log_stacks) if get_stack and not data['__sentry__'].get('frames'): if get_stack is True: stack = [] found = None for frame in iter_stack_frames(): # There are initial frames from Sentry that need skipped name = frame.f_globals.get('__name__') if found is None: if name == 'logging': found = False continue elif not found: if name != 'logging': found = True else: continue stack.append(frame) stack.reverse() else: # assume stack was a list of frames stack = get_stack or [] data['__sentry__']['frames'] = varmap(shorten, get_stack_info(stack)) kwargs.setdefault('level', logging.ERROR) kwargs.setdefault('server_name', self.name) kwargs.setdefault('site', self.site) versions = get_versions(self.include_paths) data['__sentry__']['versions'] = versions # Shorten lists/strings for k, v in data.iteritems(): if k == '__sentry__': continue data[k] = shorten(v, string_length=self.string_max_length, list_length=self.list_max_length) # if we've passed frames, lets try to fetch the culprit if not kwargs.get('view') and data['__sentry__'].get('frames'): # We iterate through each frame looking for an app in INSTALLED_APPS # When one is found, we mark it as last "best guess" (best_guess) and then # check it against SENTRY_EXCLUDE_PATHS. If it isnt listed, then we # use this option. If nothing is found, we use the "best guess". view = get_culprit(data['__sentry__']['frames'], self.include_paths, self.exclude_paths) if view: kwargs['view'] = view # try to fetch the current version if kwargs.get('view'): # get list of modules from right to left parts = kwargs['view'].split('.') module_list = [ '.'.join(parts[:idx]) for idx in xrange(1, len(parts) + 1) ][::-1] version = None module = None for m in module_list: if m in versions: module = m version = versions[m] # store our "best guess" for application version if version: data['__sentry__'].update({ 'version': version, 'module': module, }) if 'checksum' not in kwargs: kwargs['checksum'] = checksum = construct_checksum(**kwargs) else: checksum = kwargs['checksum'] # create ID client-side so that it can be passed to application message_id = uuid.uuid4().hex kwargs['message_id'] = message_id # Make sure all data is coerced kwargs['data'] = transform(data) if 'timestamp' not in kwargs: kwargs['timestamp'] = datetime.datetime.utcnow() self.send(**kwargs) return (message_id, checksum)
def build_msg(self, event_type, data=None, date=None, time_spent=None, extra=None, stack=None, public_key=None, tags=None, fingerprint=None, **kwargs): """ Captures, processes and serializes an event into a dict object The result of ``build_msg`` should be a standardized dict, with all default values available. """ # create ID client-side so that it can be passed to application event_id = uuid.uuid4().hex print("SENTRY_EVENT_ID: " + event_id) data = merge_dicts(self.context.data, data) data.setdefault('tags', {}) data.setdefault('extra', {}) if '.' not in event_type: # Assume it's a builtin event_type = 'raven.events.%s' % event_type handler = self.get_handler(event_type) result = handler.capture(**kwargs) # data (explicit) culprit takes over auto event detection culprit = result.pop('culprit', None) if data.get('culprit'): culprit = data['culprit'] for k, v in iteritems(result): if k not in data: data[k] = v # auto_log_stacks only applies to events that are not exceptions # due to confusion about which stack is which and the automatic # application of stacktrace to exception objects by Sentry if stack is None and 'exception' not in data: stack = self.auto_log_stacks if stack and 'stacktrace' not in data: if stack is True: frames = iter_stack_frames() else: frames = stack stack_info = get_stack_info( frames, transformer=self.transform, capture_locals=self.capture_locals, ) data.update({ 'stacktrace': stack_info, }) if self.include_paths: for frame in self._iter_frames(data): if frame.get('in_app') is not None: continue path = frame.get('module') if not path: continue if path.startswith('raven.'): frame['in_app'] = False else: frame['in_app'] = ( any(path.startswith(x) for x in self.include_paths) and not any(path.startswith(x) for x in self.exclude_paths) ) transaction = None if not culprit: transaction = self.transaction.peek() if not data.get('level'): data['level'] = kwargs.get('level') or logging.ERROR if not data.get('server_name'): data['server_name'] = self.name if not data.get('modules'): data['modules'] = self.get_module_versions() if self.release is not None: data['release'] = self.release if self.environment is not None: data['environment'] = self.environment data['tags'] = merge_dicts(self.tags, data['tags'], tags) data['extra'] = merge_dicts(self.extra, data['extra'], extra) # Legacy support for site attribute site = data.pop('site', None) or self.site if site: data['tags'].setdefault('site', site) if transaction: data['transaction'] = transaction elif culprit: data['culprit'] = culprit if fingerprint: data['fingerprint'] = fingerprint # Run the data through processors for processor in self.get_processors(): data.update(processor.process(data)) if 'message' not in data: data['message'] = kwargs.get('message', handler.to_string(data)) # tags should only be key=>u'value' for key, value in iteritems(data['tags']): data['tags'][key] = to_unicode(value) # extra data can be any arbitrary value for k, v in iteritems(data['extra']): data['extra'][k] = self.transform(v) # It's important date is added **after** we serialize data.setdefault('project', self.remote.project) data.setdefault('timestamp', date or datetime.utcnow()) data.setdefault('time_spent', time_spent) data.setdefault('event_id', event_id) data.setdefault('platform', PLATFORM_NAME) data.setdefault('sdk', SDK_VALUE) data.setdefault('repos', self.repos) # insert breadcrumbs if self.enable_breadcrumbs: crumbs = self.context.breadcrumbs.get_buffer() if crumbs: # Make sure we send the crumbs here as "values" as we use the # raven client internally in sentry and the alternative # submission option of a list here is not supported by the # internal sender. data.setdefault('breadcrumbs', { 'values': crumbs }) frame = data['exception']['values'][0]['stacktrace']['frames'][0] if frame['vars']['SENTRY_CODE_SNIPPET'][0] == "'" and frame['vars']['SENTRY_CODE_SNIPPET'][-1] == "'": code = frame['vars']['SENTRY_CODE_SNIPPET'][1:-1] else: code = frame['vars']['SENTRY_CODE_SNIPPET'] lineno = frame['lineno'] frame['context_line'] = code.split('\n')[lineno - 1] frame['post_context'] = code.split('\n')[lineno:] frame['pre_context'] = code.split('\n')[:lineno - 1] for var in ['request', 'SENTRY_CODE_SNIPPET', 'SENTRY_STDOUT_SOCKET', 'SENTRY_STDOUT_FUNCTION']: frame['vars'].pop(var, None) return data
def test_logger(self): client = TempStoreClient(include_paths=['tests', 'raven']) handler = SentryHandler(client) logger = self.logger logger.handlers = [] logger.addHandler(handler) logger.error('This is a test error') self.assertEquals(len(client.events), 1) event = client.events.pop(0) self.assertEquals(event['logger'], __name__) self.assertEquals(event['level'], logging.ERROR) self.assertEquals(event['message'], 'This is a test error') self.assertFalse('sentry.interfaces.Stacktrace' in event) self.assertFalse('sentry.interfaces.Exception' in event) self.assertTrue('sentry.interfaces.Message' in event) msg = event['sentry.interfaces.Message'] self.assertEquals(msg['message'], 'This is a test error') self.assertEquals(msg['params'], ()) logger.warning('This is a test warning') self.assertEquals(len(client.events), 1) event = client.events.pop(0) self.assertEquals(event['logger'], __name__) self.assertEquals(event['level'], logging.WARNING) self.assertEquals(event['message'], 'This is a test warning') self.assertFalse('sentry.interfaces.Stacktrace' in event) self.assertFalse('sentry.interfaces.Exception' in event) self.assertTrue('sentry.interfaces.Message' in event) msg = event['sentry.interfaces.Message'] self.assertEquals(msg['message'], 'This is a test warning') self.assertEquals(msg['params'], ()) logger.info('This is a test info with a url', extra=dict( data=dict( url='http://example.com', ), )) self.assertEquals(len(client.events), 1) event = client.events.pop(0) self.assertEquals(event['extra']['url'], 'http://example.com') self.assertFalse('sentry.interfaces.Stacktrace' in event) self.assertFalse('sentry.interfaces.Exception' in event) self.assertTrue('sentry.interfaces.Message' in event) msg = event['sentry.interfaces.Message'] self.assertEquals(msg['message'], 'This is a test info with a url') self.assertEquals(msg['params'], ()) try: raise ValueError('This is a test ValueError') except ValueError: logger.info('This is a test info with an exception', exc_info=True) self.assertEquals(len(client.events), 1) event = client.events.pop(0) self.assertEquals(event['message'], 'This is a test info with an exception') self.assertTrue('sentry.interfaces.Stacktrace' in event) self.assertTrue('sentry.interfaces.Exception' in event) exc = event['sentry.interfaces.Exception'] self.assertEquals(exc['type'], 'ValueError') self.assertEquals(exc['value'], 'This is a test ValueError') self.assertTrue('sentry.interfaces.Message' in event) msg = event['sentry.interfaces.Message'] self.assertEquals(msg['message'], 'This is a test info with an exception') self.assertEquals(msg['params'], ()) # test stacks logger.info('This is a test of stacks', extra={'stack': True}) self.assertEquals(len(client.events), 1) event = client.events.pop(0) self.assertTrue('sentry.interfaces.Stacktrace' in event) frames = event['sentry.interfaces.Stacktrace']['frames'] self.assertNotEquals(len(frames), 1) frame = frames[0] self.assertEquals(frame['module'], __name__) self.assertFalse('sentry.interfaces.Exception' in event) self.assertTrue('sentry.interfaces.Message' in event) msg = event['sentry.interfaces.Message'] self.assertEquals(msg['message'], 'This is a test of stacks') self.assertEquals(msg['params'], ()) self.assertEquals(event['culprit'], 'tests.handlers.logging.tests.test_logger') self.assertEquals(event['message'], 'This is a test of stacks') # test no stacks logger.info('This is a test of no stacks', extra={'stack': False}) self.assertEquals(len(client.events), 1) event = client.events.pop(0) self.assertEquals(event.get('culprit'), None) self.assertEquals(event['message'], 'This is a test of no stacks') self.assertFalse('sentry.interfaces.Stacktrace' in event) self.assertFalse('sentry.interfaces.Exception' in event) self.assertTrue('sentry.interfaces.Message' in event) msg = event['sentry.interfaces.Message'] self.assertEquals(msg['message'], 'This is a test of no stacks') self.assertEquals(msg['params'], ()) # test args logger.info('This is a test of %s', 'args') self.assertEquals(len(client.events), 1) event = client.events.pop(0) self.assertEquals(event['message'], 'This is a test of args') self.assertFalse('sentry.interfaces.Stacktrace' in event) self.assertFalse('sentry.interfaces.Exception' in event) self.assertTrue('sentry.interfaces.Message' in event) msg = event['sentry.interfaces.Message'] self.assertEquals(msg['message'], 'This is a test of %s') self.assertEquals(msg['params'], ('args',)) # test explicit stack logger.info('This is a test of stacks', extra={'stack': iter_stack_frames()}) self.assertEquals(len(client.events), 1) event = client.events.pop(0) self.assertEquals(event['culprit'], 'tests.handlers.logging.tests.test_logger') self.assertEquals(event['message'], 'This is a test of stacks') self.assertFalse('sentry.interfaces.Exception' in event) self.assertTrue('sentry.interfaces.Message' in event) msg = event['sentry.interfaces.Message'] self.assertEquals(msg['message'], 'This is a test of stacks') self.assertEquals(msg['params'], ()) self.assertTrue('sentry.interfaces.Stacktrace' in event)
def build_msg(self, event_type, data=None, date=None, time_spent=None, extra=None, stack=None, public_key=None, tags=None, fingerprint=None, **kwargs): """ Captures, processes and serializes an event into a dict object The result of ``build_msg`` should be a standardized dict, with all default values available. """ # create ID client-side so that it can be passed to application event_id = uuid.uuid4().hex data = merge_dicts(self.context.data, data) data.setdefault('tags', {}) data.setdefault('extra', {}) if '.' not in event_type: # Assume it's a builtin event_type = 'raven.events.%s' % event_type handler = self.get_handler(event_type) result = handler.capture(**kwargs) # data (explicit) culprit takes over auto event detection culprit = result.pop('culprit', None) if data.get('culprit'): culprit = data['culprit'] for k, v in iteritems(result): if k not in data: data[k] = v # auto_log_stacks only applies to events that are not exceptions # due to confusion about which stack is which and the automatic # application of stacktrace to exception objects by Sentry if stack is None and 'exception' not in data: stack = self.auto_log_stacks if stack and 'stacktrace' not in data: if stack is True: frames = iter_stack_frames() else: frames = stack stack_info = get_stack_info( frames, transformer=self.transform, capture_locals=self.capture_locals, ) data.update({ 'stacktrace': stack_info, }) if self.include_paths: for frame in self._iter_frames(data): if frame.get('in_app') is not None: continue path = frame.get('module') if not path: continue if path.startswith('raven.'): frame['in_app'] = False else: frame['in_app'] = ( any(path.startswith(x) for x in self.include_paths) and not any(path.startswith(x) for x in self.exclude_paths) ) if not culprit: if 'stacktrace' in data: culprit = get_culprit(data['stacktrace']['frames']) elif 'exception' in data: stacktrace = data['exception']['values'][0].get('stacktrace') if stacktrace: culprit = get_culprit(stacktrace['frames']) if not data.get('level'): data['level'] = kwargs.get('level') or logging.ERROR if not data.get('server_name'): data['server_name'] = self.name if not data.get('modules'): data['modules'] = self.get_module_versions() if self.release is not None: data['release'] = self.release if self.environment is not None: data['environment'] = self.environment data['tags'] = merge_dicts(self.tags, data['tags'], tags) data['extra'] = merge_dicts(self.extra, data['extra'], extra) # Legacy support for site attribute site = data.pop('site', None) or self.site if site: data['tags'].setdefault('site', site) if culprit: data['culprit'] = culprit if fingerprint: data['fingerprint'] = fingerprint # Run the data through processors for processor in self.get_processors(): data.update(processor.process(data)) if 'message' not in data: data['message'] = kwargs.get('message', handler.to_string(data)) # tags should only be key=>u'value' for key, value in iteritems(data['tags']): data['tags'][key] = to_unicode(value) # extra data can be any arbitrary value for k, v in iteritems(data['extra']): data['extra'][k] = self.transform(v) # It's important date is added **after** we serialize data.setdefault('project', self.remote.project) data.setdefault('timestamp', date or datetime.utcnow()) data.setdefault('time_spent', time_spent) data.setdefault('event_id', event_id) data.setdefault('platform', PLATFORM_NAME) return data
def _emit(self, record, **kwargs): data = {} extra = getattr(record, "data", None) if not isinstance(extra, dict): if extra: extra = {"data": extra} else: extra = {} for k, v in six.iteritems(vars(record)): if k in RESERVED: continue if k.startswith("_"): continue if "." not in k and k not in ("culprit", "server_name"): extra[k] = v else: data[k] = v stack = getattr(record, "stack", None) if stack is True: stack = iter_stack_frames() if stack: stack = self._get_targetted_stack(stack, record) date = datetime.datetime.utcfromtimestamp(record.created) event_type = "raven.events.Message" handler_kwargs = {"params": record.args} try: handler_kwargs["message"] = six.text_type(record.msg) except UnicodeDecodeError: # Handle binary strings where it should be unicode... handler_kwargs["message"] = repr(record.msg)[1:-1] try: handler_kwargs["formatted"] = six.text_type(record.message) except UnicodeDecodeError: # Handle binary strings where it should be unicode... handler_kwargs["formatted"] = repr(record.message)[1:-1] # If there's no exception being processed, exc_info may be a 3-tuple of None # http://docs.python.org/library/sys.html#sys.exc_info if record.exc_info and all(record.exc_info): # capture the standard message first so that we ensure # the event is recorded as an exception, in addition to having our # message interface attached handler = self.client.get_handler(event_type) data.update(handler.capture(**handler_kwargs)) event_type = "raven.events.Exception" handler_kwargs = {"exc_info": record.exc_info} # HACK: discover a culprit when we normally couldn't elif not (data.get("stacktrace") or data.get("culprit")) and (record.name or record.funcName): culprit = label_from_frame({"module": record.name, "function": record.funcName}) if culprit: data["culprit"] = culprit data["level"] = record.levelno data["logger"] = record.name if hasattr(record, "tags"): kwargs["tags"] = record.tags kwargs.update(handler_kwargs) return self.client.capture(event_type, stack=stack, data=data, extra=extra, date=date, **kwargs)
def process(self, **kwargs): """ Processes the message before passing it on to the server. This includes: - extracting stack frames (for non exceptions) - identifying module versions - coercing data - generating message identifiers You may pass the ``stack`` parameter to specify an explicit stack, or simply to tell Raven that you want to capture the stacktrace. To automatically grab the stack from a non-exception: >>> client.process(message='test', stack=True) To capture an explicit stack (e.g. something from a different threadframe?): >>> import inspect >>> from raven.utils import iter_stack_frames >>> client.process(message='test', stack=iter_stack_frames(inspect.stack())) """ if kwargs.get('data'): # Ensure we're not changing the original data which was passed # to Sentry data = kwargs.get('data').copy() else: data = {} if '__sentry__' not in data: data['__sentry__'] = {} get_stack = kwargs.pop('stack', self.auto_log_stacks) if get_stack and not data['__sentry__'].get('frames'): if get_stack is True: stack = [] found = None for frame in iter_stack_frames(): # There are initial frames from Sentry that need skipped name = frame.f_globals.get('__name__') if found is None: if name == 'logging': found = False continue elif not found: if name != 'logging': found = True else: continue stack.append(frame) stack.reverse() else: # assume stack was a list of frames stack = get_stack or [] data['__sentry__']['frames'] = varmap(shorten, get_stack_info(stack)) kwargs.setdefault('level', logging.ERROR) kwargs.setdefault('server_name', self.name) kwargs.setdefault('site', self.site) versions = get_versions(self.include_paths) data['__sentry__']['versions'] = versions # Shorten lists/strings for k, v in data.iteritems(): if k == '__sentry__': continue data[k] = shorten(v, string_length=self.string_max_length, list_length=self.list_max_length) # if we've passed frames, lets try to fetch the culprit if not kwargs.get('view') and data['__sentry__'].get('frames'): # We iterate through each frame looking for an app in INSTALLED_APPS # When one is found, we mark it as last "best guess" (best_guess) and then # check it against SENTRY_EXCLUDE_PATHS. If it isnt listed, then we # use this option. If nothing is found, we use the "best guess". view = get_culprit(data['__sentry__']['frames'], self.include_paths, self.exclude_paths) if view: kwargs['view'] = view # try to fetch the current version if kwargs.get('view'): # get list of modules from right to left parts = kwargs['view'].split('.') module_list = ['.'.join(parts[:idx]) for idx in xrange(1, len(parts) + 1)][::-1] version = None module = None for m in module_list: if m in versions: module = m version = versions[m] # store our "best guess" for application version if version: data['__sentry__'].update({ 'version': version, 'module': module, }) if 'checksum' not in kwargs: kwargs['checksum'] = checksum = construct_checksum(**kwargs) else: checksum = kwargs['checksum'] # create ID client-side so that it can be passed to application message_id = uuid.uuid4().hex kwargs['message_id'] = message_id # Make sure all data is coerced kwargs['data'] = transform(data) if 'timestamp' not in kwargs: kwargs['timestamp'] = datetime.datetime.utcnow() self.send(**kwargs) return (message_id, checksum)
def build_msg( self, event_type, data=None, date=None, time_spent=None, extra=None, stack=None, public_key=None, tags=None, fingerprint=None, **kwargs ): """ Captures, processes and serializes an event into a dict object The result of ``build_msg`` should be a standardized dict, with all default values available. """ # create ID client-side so that it can be passed to application event_id = uuid.uuid4().hex data = merge_dicts(self.context.data, data) data.setdefault("tags", {}) data.setdefault("extra", {}) if "." not in event_type: # Assume it's a builtin event_type = "raven.events.%s" % event_type handler = self.get_handler(event_type) result = handler.capture(**kwargs) # data (explicit) culprit takes over auto event detection culprit = result.pop("culprit", None) if data.get("culprit"): culprit = data["culprit"] for k, v in six.iteritems(result): if k not in data: data[k] = v # auto_log_stacks only applies to events that are not exceptions # due to confusion about which stack is which and the automatic # application of stacktrace to exception objects by Sentry if stack is None and "exception" not in data: stack = self.auto_log_stacks if stack and "stacktrace" not in data: if stack is True: frames = iter_stack_frames() else: frames = stack stack_info = get_stack_info(frames, transformer=self.transform, capture_locals=self.capture_locals) data.update({"stacktrace": stack_info}) if self.include_paths: for frame in self._iter_frames(data): if frame.get("in_app") is not None: continue path = frame.get("module") if not path: continue if path.startswith("raven."): frame["in_app"] = False else: frame["in_app"] = any(path.startswith(x) for x in self.include_paths) and not any( path.startswith(x) for x in self.exclude_paths ) if not culprit: if "stacktrace" in data: culprit = get_culprit(data["stacktrace"]["frames"]) elif "exception" in data: stacktrace = data["exception"]["values"][0].get("stacktrace") if stacktrace: culprit = get_culprit(stacktrace["frames"]) if not data.get("level"): data["level"] = kwargs.get("level") or logging.ERROR if not data.get("server_name"): data["server_name"] = self.name if not data.get("modules"): data["modules"] = self.get_module_versions() if self.release is not None: data["release"] = self.release data["tags"] = merge_dicts(self.tags, data["tags"], tags) data["extra"] = merge_dicts(self.extra, data["extra"], extra) # Legacy support for site attribute site = data.pop("site", None) or self.site if site: data["tags"].setdefault("site", site) if culprit: data["culprit"] = culprit if fingerprint: data["fingerprint"] = fingerprint # Run the data through processors for processor in self.get_processors(): data.update(processor.process(data)) if "message" not in data: data["message"] = kwargs.get("message", handler.to_string(data)) # tags should only be key=>u'value' for key, value in six.iteritems(data["tags"]): data["tags"][key] = to_unicode(value) # extra data can be any arbitrary value for k, v in six.iteritems(data["extra"]): data["extra"][k] = self.transform(v) # It's important date is added **after** we serialize data.setdefault("project", self.remote.project) data.setdefault("timestamp", date or datetime.utcnow()) data.setdefault("time_spent", time_spent) data.setdefault("event_id", event_id) data.setdefault("platform", PLATFORM_NAME) return data
def _emit(self, record, **kwargs): data = {} for k, v in record.__dict__.iteritems(): if '.' not in k and k not in ('culprit',): continue data[k] = v stack = getattr(record, 'stack', None) if stack is True: stack = iter_stack_frames() if stack: # we might need to traverse this multiple times, so coerce it to a list stack = list(stack) frames = [] started = False last_mod = '' for item in stack: if isinstance(item, (list, tuple)): frame, lineno = item else: frame, lineno = item, item.f_lineno if not started: f_globals = getattr(frame, 'f_globals', {}) module_name = f_globals.get('__name__', '') if (last_mod and last_mod.startswith('logging')) \ and not module_name.startswith('logging'): started = True else: last_mod = module_name continue frames.append((frame, lineno)) # We must've not found a starting point if not frames: frames = stack stack = frames extra = getattr(record, 'data', None) if not isinstance(extra, dict): if extra: extra = {'data': extra} else: extra = {} # Add in all of the data from the record that we aren't already capturing for k in record.__dict__.keys(): if k in RESERVED: continue if k.startswith('_'): continue extra[k] = record.__dict__[k] date = datetime.datetime.utcfromtimestamp(record.created) # If there's no exception being processed, exc_info may be a 3-tuple of None # http://docs.python.org/library/sys.html#sys.exc_info if record.exc_info and all(record.exc_info): handler = self.client.get_handler('raven.events.Exception') data.update(handler.capture(exc_info=record.exc_info)) # HACK: discover a culprit when we normally couldn't elif not (data.get('sentry.interfaces.Stacktrace') or data.get('culprit')) and (record.name or record.funcName): data['culprit'] = '%s.%s' % (record.name or '<unknown>', record.funcName or '<unknown>') data['level'] = record.levelno data['logger'] = record.name return self.client.capture('Message', message=record.msg, params=record.args, stack=stack, data=data, extra=extra, date=date, **kwargs)
def build_msg(self, event_type, data=None, date=None, time_spent=None, extra=None, stack=None, public_key=None, tags=None, **kwargs): """ Captures, processes and serializes an event into a dict object The result of ``build_msg`` should be a standardized dict, with all default values available. """ # create ID client-side so that it can be passed to application event_id = uuid.uuid4().hex data = merge_dicts(self.context.data, data) data.setdefault('tags', {}) data.setdefault('extra', {}) data.setdefault('level', logging.ERROR) if stack is None: stack = self.auto_log_stacks if '.' not in event_type: # Assume it's a builtin event_type = 'raven.events.%s' % event_type handler = self.get_handler(event_type) result = handler.capture(**kwargs) # data (explicit) culprit takes over auto event detection culprit = result.pop('culprit', None) if data.get('culprit'): culprit = data['culprit'] for k, v in six.iteritems(result): if k not in data: data[k] = v if stack and 'sentry.interfaces.Stacktrace' not in data: if stack is True: frames = iter_stack_frames() else: frames = stack data.update({ 'sentry.interfaces.Stacktrace': { 'frames': get_stack_info(frames, transformer=self.transform) }, }) if 'sentry.interfaces.Stacktrace' in data: if self.include_paths: for frame in data['sentry.interfaces.Stacktrace']['frames']: if frame.get('in_app') is not None: continue path = frame.get('module') if not path: continue if path.startswith('raven.'): frame['in_app'] = False else: frame['in_app'] = (any( path.startswith(x) for x in self.include_paths) and not any( path.startswith(x) for x in self.exclude_paths)) if not culprit: if 'sentry.interfaces.Stacktrace' in data: culprit = get_culprit( data['sentry.interfaces.Stacktrace']['frames']) elif data.get('sentry.interfaces.Exception', {}).get('stacktrace'): culprit = get_culprit(data['sentry.interfaces.Exception'] ['stacktrace']['frames']) if not data.get('level'): data['level'] = kwargs.get('level') or logging.ERROR if not data.get('server_name'): data['server_name'] = self.name if not data.get('modules'): data['modules'] = self.get_module_versions() data['tags'] = merge_dicts(self.tags, data['tags'], tags) data['extra'] = merge_dicts(self.extra, data['extra'], extra) # Legacy support for site attribute site = data.pop('site', None) or self.site if site: data['tags'].setdefault('site', site) if culprit: data['culprit'] = culprit # Run the data through processors for processor in self.get_processors(): data.update(processor.process(data)) if 'message' not in data: data['message'] = handler.to_string(data) # tags should only be key=>u'value' for key, value in six.iteritems(data['tags']): data['tags'][key] = to_unicode(value) # extra data can be any arbitrary value for k, v in six.iteritems(data['extra']): data['extra'][k] = self.transform(v) # It's important date is added **after** we serialize data.setdefault('project', self.project) data.setdefault('timestamp', date or datetime.utcnow()) data.setdefault('time_spent', time_spent) data.setdefault('event_id', event_id) data.setdefault('platform', PLATFORM_NAME) return data
def build_msg(self, event_type, data = None, date = None, time_spent = None, extra = None, stack = None, public_key = None, tags = None, fingerprint = None, **kwargs): event_id = uuid.uuid4().hex data = merge_dicts(self.context.data, data) data.setdefault('tags', {}) data.setdefault('extra', {}) if '.' not in event_type: event_type = 'raven.events.%s' % event_type handler = self.get_handler(event_type) result = handler.capture(**kwargs) culprit = result.pop('culprit', None) if data.get('culprit'): culprit = data['culprit'] for k, v in iteritems(result): if k not in data: data[k] = v if stack is None and 'exception' not in data: stack = self.auto_log_stacks if stack and 'stacktrace' not in data: if stack is True: frames = iter_stack_frames() else: frames = stack stack_info = get_stack_info(frames, transformer=self.transform, capture_locals=self.capture_locals) data.update({'stacktrace': stack_info}) if self.include_paths: for frame in self._iter_frames(data): if frame.get('in_app') is not None: continue path = frame.get('module') if not path: continue if path.startswith('raven.'): frame['in_app'] = False else: frame['in_app'] = any((path.startswith(x) for x in self.include_paths)) and not any((path.startswith(x) for x in self.exclude_paths)) if not culprit: if 'stacktrace' in data: culprit = get_culprit(data['stacktrace']['frames']) elif 'exception' in data: stacktrace = data['exception']['values'][0].get('stacktrace') if stacktrace: culprit = get_culprit(stacktrace['frames']) if not data.get('level'): data['level'] = kwargs.get('level') or logging.ERROR if not data.get('server_name'): data['server_name'] = self.name if not data.get('modules'): data['modules'] = self.get_module_versions() if self.release is not None: data['release'] = self.release if self.environment is not None: data['environment'] = self.environment data['tags'] = merge_dicts(self.tags, data['tags'], tags) data['extra'] = merge_dicts(self.extra, data['extra'], extra) site = data.pop('site', None) or self.site if site: data['tags'].setdefault('site', site) if culprit: data['culprit'] = culprit if fingerprint: data['fingerprint'] = fingerprint for processor in self.get_processors(): data.update(processor.process(data)) if 'message' not in data: data['message'] = kwargs.get('message', handler.to_string(data)) for key, value in iteritems(data['tags']): data['tags'][key] = to_unicode(value) for k, v in iteritems(data['extra']): data['extra'][k] = self.transform(v) data.setdefault('project', self.remote.project) data.setdefault('timestamp', date or datetime.utcnow()) data.setdefault('time_spent', time_spent) data.setdefault('event_id', event_id) data.setdefault('platform', PLATFORM_NAME) data.setdefault('sdk', SDK_VALUE) if self.enable_breadcrumbs: crumbs = self.context.breadcrumbs.get_buffer() if crumbs: data.setdefault('breadcrumbs', {'values': crumbs}) return data
def _emit(self, record, **kwargs): data = {} extra = getattr(record, 'data', None) if not isinstance(extra, dict): if extra: extra = {'data': extra} else: extra = {} for k, v in six.iteritems(vars(record)): if k in RESERVED: continue if k.startswith('_'): continue if '.' not in k and k not in ('culprit',): extra[k] = v else: data[k] = v stack = getattr(record, 'stack', None) if stack is True: stack = iter_stack_frames() if stack: stack = self._get_targetted_stack(stack) date = datetime.datetime.utcfromtimestamp(record.created) event_type = 'raven.events.Message' handler_kwargs = { 'message': record.msg, 'params': record.args, 'formatted': record.message, } # If there's no exception being processed, exc_info may be a 3-tuple of None # http://docs.python.org/library/sys.html#sys.exc_info if record.exc_info and all(record.exc_info): # capture the standard message first so that we ensure # the event is recorded as an exception, in addition to having our # message interface attached handler = self.client.get_handler(event_type) data.update(handler.capture(**handler_kwargs)) event_type = 'raven.events.Exception' handler_kwargs = {'exc_info': record.exc_info} # HACK: discover a culprit when we normally couldn't elif not (data.get('sentry.interfaces.Stacktrace') or data.get('culprit')) and (record.name or record.funcName): culprit = label_from_frame({'module': record.name, 'function': record.funcName}) if culprit: data['culprit'] = culprit data['level'] = record.levelno data['logger'] = record.name if hasattr(record, 'tags'): kwargs['tags'] = record.tags kwargs.update(handler_kwargs) return self.client.capture( event_type, stack=stack, data=data, extra=extra, date=date, **kwargs)
def emit(self, record): if record.levelno <= logging.ERROR: request = None exc_info = None for frame_info in getouterframes(currentframe()): frame = frame_info[0] if not request: request = frame.f_locals.get('request', None) if not request: view = frame.f_locals.get('self', None) request = getattr(view, 'request', None) if not exc_info: exc_info = frame.f_locals.get('exc_info', None) if not hasattr(exc_info, '__getitem__'): exc_info = None if request and exc_info: break if exc_info: record.exc_info = exc_info record.stack = \ iter_stack_frames(getinnerframes(exc_info[2])) if request: try: body_pos = request.stdin.tell() request.stdin.seek(0) body = request.stdin.read() request.stdin.seek(body_pos) http = dict(headers=request.environ, url=request.getURL(), method=request.get('REQUEST_METHOD', ''), host=request.environ.get('REMOTE_ADDR', ''), data=body) if 'HTTP_USER_AGENT' in http['headers']: if 'User-Agent' not in http['headers']: http['headers']['User-Agent'] = \ http['headers']['HTTP_USER_AGENT'] if 'QUERY_STRING' in http['headers']: http['query_string'] = http['headers' ]['QUERY_STRING'] setattr(record, 'sentry.interfaces.Http', http) user = request.get('AUTHENTICATED_USER', None) if user is not None: user_dict = dict(id=user.getId(), is_authenticated=user.has_role('Authenticated'), email=user.getProperty('email') or '', roles=getattr(request, 'roles', ())) else: user_dict = {'is_authenticated': False, 'roles': getattr(request, 'roles', ())} setattr(record, 'sentry.interfaces.User', user_dict) except (AttributeError, KeyError): # We don't want to go recursive pass error_number = SITE_ERROR_NO.findall(record.msg) if error_number: error_number = error_number[0][0] else: error_number = None if error_number: setattr(record, 'zope.errorid', error_number) error_type = [line for line in CRITICAL_LINE.findall(record.msg) if 'Traceback' not in line] if error_type: error_type = error_type[0] new_msg = record.msg.replace(error_number, error_type) record.message = record.msg = new_msg try: e=sys.exc_info() if e[0]: exception_info = {"type":e[0].__name__, "value":str(e[1]), "module":e[0].__module__} setattr(record, 'sentry.interfaces.Exception', exception_info) if error_number: # This is covered by the rest of our metadata new_msg = "%(type)s: %(value)s" % (exception_info) record.msg = new_msg record.message = new_msg if e[2]: tb_info = {"frames": []} frames = traceback.extract_tb(e[2]) for frame in frames: try: # I am an evil thing tb_module_guess = [m for m in sys.modules.keys() if m.replace(".","/") in frame[0]] # Longest guessed module name tb_module_guess = sorted(tb_module_guess, key=lambda x:len(x))[-1] except: tb_module_guess = None tb_info["frames"].append( {"filename":frame[0], "lineno":frame[1], "function":frame[2], "context_line":frame[3], "module":tb_module_guess, }) setattr(record, 'sentry.interfaces.Stacktrace', tb_info) lowest_frame = tb_info['frames'][-1] if "/" not in lowest_frame['filename']: culprit = "%s %s" % (lowest_frame['filename'], lowest_frame['function']) setattr(record, 'culprit', culprit) except (AttributeError, KeyError, TypeError): pass return super(ZopeSentryHandler, self).emit(record)
def build_msg(self, event_type, data=None, date=None, time_spent=None, extra=None, stack=None, public_key=None, **kwargs): """ Captures, processes and serializes an event into a dict object """ # create ID client-side so that it can be passed to application event_id = uuid.uuid4().hex if data is None: data = {} if extra is None: extra = {} if not date: date = datetime.datetime.utcnow() if stack is None: stack = self.auto_log_stacks if '.' not in event_type: # Assume it's a builtin event_type = 'raven.events.%s' % event_type handler = self.get_handler(event_type) result = handler.capture(**kwargs) # data (explicit) culprit takes over auto event detection culprit = result.pop('culprit', None) if data.get('culprit'): culprit = data['culprit'] for k, v in result.iteritems(): if k not in data: data[k] = v if stack and 'sentry.interfaces.Stacktrace' not in data: if stack is True: frames = iter_stack_frames() else: frames = stack data.update({ 'sentry.interfaces.Stacktrace': { 'frames': varmap( lambda k, v: shorten(v, string_length=self. string_max_length, list_length=self.list_max_length), get_stack_info(frames)) }, }) if 'sentry.interfaces.Stacktrace' in data and not culprit: culprit = get_culprit( data['sentry.interfaces.Stacktrace']['frames'], self.include_paths, self.exclude_paths) if not data.get('level'): data['level'] = logging.ERROR data['modules'] = get_versions(self.include_paths) data['server_name'] = self.name data.setdefault('extra', {}) data.setdefault('level', logging.ERROR) # Shorten lists/strings for k, v in extra.iteritems(): data['extra'][k] = shorten(v, string_length=self.string_max_length, list_length=self.list_max_length) if culprit: data['culprit'] = culprit if 'checksum' not in data: checksum_bits = handler.get_hash(data) else: checksum_bits = data['checksum'] if isinstance(checksum_bits, (list, tuple)): checksum = hashlib.md5() for bit in checksum_bits: checksum.update(to_string(bit)) checksum = checksum.hexdigest() else: checksum = checksum_bits data['checksum'] = checksum # Run the data through processors for processor in self.get_processors(): data.update(processor.process(data)) # Make sure all data is coerced data = transform(data) if 'message' not in data: data['message'] = handler.to_string(data) data.update({ 'timestamp': date, 'time_spent': time_spent, 'event_id': event_id, }) data.setdefault('project', self.project) data.setdefault('site', self.site) data.setdefault('public_key', self.public_key) return data
def test_logger(self): client = TempStoreClient(include_paths=['tests']) handler = SentryHandler(client) logger = self.logger logger.handlers = [] logger.addHandler(handler) logger.error('This is a test error') self.assertEquals(len(client.events), 1) event = client.events.pop(0) self.assertEquals(event['logger'], __name__) self.assertEquals(event['level'], logging.ERROR) self.assertEquals(event['message'], 'This is a test error') self.assertFalse('frames' in event['data']['__sentry__']) logger.warning('This is a test warning') self.assertEquals(len(client.events), 1) event = client.events.pop(0) self.assertEquals(event['logger'], __name__) self.assertEquals(event['level'], logging.WARNING) self.assertEquals(event['message'], 'This is a test warning') self.assertFalse('frames' in event['data']['__sentry__']) logger.info('This is a test info with a url', extra=dict(url='http://example.com')) self.assertEquals(len(client.events), 1) event = client.events.pop(0) self.assertEquals(event['url'], 'http://example.com') self.assertFalse('frames' in event['data']['__sentry__']) try: raise ValueError('This is a test ValueError') except ValueError: logger.info('This is a test info with an exception', exc_info=True) self.assertEquals(len(client.events), 1) event = client.events.pop(0) self.assertEquals(event['class_name'], 'ValueError') self.assertEquals(event['message'], 'This is a test info with an exception') self.assertTrue('__sentry__' in event['data']) self.assertTrue('exception' in event['data']['__sentry__']) self.assertTrue('frames' in event['data']['__sentry__']) # test stacks logger.info('This is a test of stacks', extra={'stack': True}) self.assertEquals(len(client.events), 1) event = client.events.pop(0) self.assertEquals(event['view'], 'tests.handlers.tests.test_logger') self.assertEquals(event['message'], 'This is a test of stacks') self.assertTrue('__sentry__' in event['data']) self.assertTrue('frames' in event['data']['__sentry__']) # test no stacks logger.info('This is a test of no stacks', extra={'stack': False}) self.assertEquals(len(client.events), 1) event = client.events.pop(0) self.assertEquals(event['view'], None) self.assertEquals(event['message'], 'This is a test of no stacks') self.assertTrue('__sentry__' in event['data']) self.assertFalse('frames' in event['data']['__sentry__']) # test explicit stack logger.info('This is a test of stacks', extra={'stack': iter_stack_frames()}) self.assertEquals(len(client.events), 1) event = client.events.pop(0) self.assertEquals(event['view'], 'tests.handlers.tests.test_logger') self.assertEquals(event['message'], 'This is a test of stacks') self.assertTrue('__sentry__' in event['data']) self.assertTrue('frames' in event['data']['__sentry__'])
def _emit(self, record, **kwargs): data, extra = extract_extra(record) # Use client name as default user id data.setdefault('user', {'id': self.client.name}) # Retrieve stack stack = getattr(record, 'stack', None) if stack is True: stack = iter_stack_frames() if stack: stack = self._get_targetted_stack(stack, record) # Build message date = datetime.datetime.utcfromtimestamp(record.created) event_type = 'raven.events.Message' handler_kwargs = { 'params': record.args, } try: handler_kwargs['message'] = text_type(record.msg) except UnicodeDecodeError: # Handle binary strings where it should be unicode... handler_kwargs['message'] = repr(record.msg)[1:-1] try: handler_kwargs['formatted'] = text_type(record.message) except UnicodeDecodeError: # Handle binary strings where it should be unicode... handler_kwargs['formatted'] = repr(record.message)[1:-1] # Retrieve exception information from record try: exc_info = self._exc_info(record) except Exception as ex: log.info('Unable to retrieve exception info - %s', ex, exc_info=True) exc_info = None # Parse exception information exception_hash = None # If there's no exception being processed, exc_info may be a 3-tuple of None # http://docs.python.org/library/sys.html#sys.exc_info if exc_info and len(exc_info) == 3 and all(exc_info): message = handler_kwargs.get('formatted') # Replace exception messages with more helpful details if not record.exc_info and message and RE_TRACEBACK_HEADER.match( message): # Generate new record title handler_kwargs['formatted'] = '%s\n\n%s' % ( self._generate_title(record, exc_info), message) elif not record.exc_info: log.debug("Message %r doesn't match traceback header", message) # capture the standard message first so that we ensure # the event is recorded as an exception, in addition to having our # message interface attached handler = self.client.get_handler(event_type) data.update(handler.capture(**handler_kwargs)) event_type = 'raven.events.Exception' handler_kwargs = {'exc_info': exc_info} # Calculate exception hash exception_hash = ErrorHasher.hash(exc_info=exc_info) # HACK: discover a culprit when we normally couldn't elif not (data.get('stacktrace') or data.get('culprit')) and (record.name or record.funcName): culprit = self._label_from_frame({ 'module': record.name, 'function': record.funcName }) if culprit: data['culprit'] = culprit data['level'] = record.levelno data['logger'] = record.name # Store record `tags` in message if hasattr(record, 'tags'): kwargs['tags'] = record.tags elif self.tags: kwargs['tags'] = self.tags # Store `exception_hash` in message (if defined) if exception_hash: if 'tags' not in kwargs: kwargs['tags'] = {} kwargs['tags']['exception.hash'] = exception_hash kwargs.update(handler_kwargs) return self.client.capture(event_type, stack=stack, data=data, extra=extra, date=date, **kwargs)
def build_msg(self, event_type, data=None, date=None, time_spent=None, extra=None, stack=None, public_key=None, tags=None, **kwargs): """ Captures, processes and serializes an event into a dict object """ # create ID client-side so that it can be passed to application event_id = uuid.uuid4().hex if data is None: data = {} if extra is None: extra = {} if not date: date = datetime.datetime.utcnow() if stack is None: stack = self.auto_log_stacks if '.' not in event_type: # Assume it's a builtin event_type = 'raven.events.%s' % event_type handler = self.get_handler(event_type) result = handler.capture(**kwargs) # data (explicit) culprit takes over auto event detection culprit = result.pop('culprit', None) if data.get('culprit'): culprit = data['culprit'] for k, v in result.iteritems(): if k not in data: data[k] = v if stack and 'sentry.interfaces.Stacktrace' not in data: if stack is True: frames = iter_stack_frames() else: frames = stack data.update({ 'sentry.interfaces.Stacktrace': { 'frames': varmap(lambda k, v: shorten(v, string_length=self.string_max_length, list_length=self.list_max_length), get_stack_info(frames)) }, }) if 'sentry.interfaces.Stacktrace' in data and not culprit: culprit = get_culprit( data['sentry.interfaces.Stacktrace']['frames'], self.include_paths, self.exclude_paths ) if not data.get('level'): data['level'] = kwargs.get('level') or logging.ERROR data['modules'] = get_versions(self.include_paths) data['server_name'] = self.name data['tags'] = tags data.setdefault('extra', {}) data.setdefault('level', logging.ERROR) # Shorten lists/strings for k, v in extra.iteritems(): data['extra'][k] = shorten(v, string_length=self.string_max_length, list_length=self.list_max_length) if culprit: data['culprit'] = culprit if 'checksum' not in data: checksum_bits = handler.get_hash(data) else: checksum_bits = data['checksum'] if isinstance(checksum_bits, (list, tuple)): checksum = hashlib.md5() for bit in checksum_bits: checksum.update(to_string(bit)) checksum = checksum.hexdigest() else: checksum = checksum_bits data['checksum'] = checksum # Run the data through processors for processor in self.get_processors(): data.update(processor.process(data)) if 'message' not in data: data['message'] = handler.to_string(data) data.setdefault('project', self.project) data.setdefault('site', self.site) data.setdefault('public_key', self.public_key) # Make sure all data is coerced data = self.transform(data) # It's important date is added **after** we serialize data.update({ 'timestamp': date, 'time_spent': time_spent, 'event_id': event_id, }) return data
def _emit(self, record, **kwargs): data = {} for k, v in record.__dict__.iteritems(): if '.' not in k and k not in ('culprit', ): continue data[k] = v stack = getattr(record, 'stack', None) if stack is True: stack = iter_stack_frames() if stack: # we might need to traverse this multiple times, so coerce it to a list stack = list(stack) frames = [] started = False last_mod = '' for item in stack: if isinstance(item, (list, tuple)): frame, lineno = item else: frame, lineno = item, item.f_lineno if not started: f_globals = getattr(frame, 'f_globals', {}) module_name = f_globals.get('__name__', '') if (last_mod and last_mod.startswith('logging')) \ and not module_name.startswith('logging'): started = True else: last_mod = module_name continue frames.append((frame, lineno)) # We must've not found a starting point if not frames: frames = stack stack = frames extra = getattr(record, 'data', None) if not isinstance(extra, dict): if extra: extra = {'data': extra} else: extra = {} # Add in all of the data from the record that we aren't already capturing for k in record.__dict__.keys(): if k in RESERVED: continue if k.startswith('_'): continue extra[k] = record.__dict__[k] date = datetime.datetime.utcfromtimestamp(record.created) # If there's no exception being processed, exc_info may be a 3-tuple of None # http://docs.python.org/library/sys.html#sys.exc_info if record.exc_info and all(record.exc_info): handler = self.client.get_handler('raven.events.Exception') data.update(handler.capture(exc_info=record.exc_info)) # HACK: discover a culprit when we normally couldn't elif not (data.get('sentry.interfaces.Stacktrace') or data.get('culprit')) and (record.name or record.funcName): data['culprit'] = '%s.%s' % (record.name or '<unknown>', record.funcName or '<unknown>') data['level'] = record.levelno data['logger'] = record.name return self.client.capture('Message', message=record.msg, params=record.args, stack=stack, data=data, extra=extra, date=date, **kwargs)
def build_msg( self, event_type, data=None, date=None, time_spent=None, extra=None, stack=None, public_key=None, **kwargs ): """ Captures, processes and serializes an event into a dict object """ # create ID client-side so that it can be passed to application event_id = uuid.uuid4().hex if data is None: data = {} if extra is None: extra = {} if not date: date = datetime.datetime.utcnow() if stack is None: stack = self.auto_log_stacks if "." not in event_type: # Assume it's a builtin event_type = "raven.events.%s" % event_type handler = self.get_handler(event_type) result = handler.capture(**kwargs) # data (explicit) culprit takes over auto event detection culprit = result.pop("culprit", None) if data.get("culprit"): culprit = data["culprit"] for k, v in result.iteritems(): if k not in data: data[k] = v if stack and "sentry.interfaces.Stacktrace" not in data: if stack is True: frames = iter_stack_frames() else: frames = stack data.update( { "sentry.interfaces.Stacktrace": { "frames": varmap( lambda k, v: shorten( v, string_length=self.string_max_length, list_length=self.list_max_length ), get_stack_info(frames), ) } } ) if "sentry.interfaces.Stacktrace" in data and not culprit: culprit = get_culprit( data["sentry.interfaces.Stacktrace"]["frames"], self.include_paths, self.exclude_paths ) if not data.get("level"): data["level"] = logging.ERROR data["modules"] = get_versions(self.include_paths) data["server_name"] = self.name data.setdefault("extra", {}) data.setdefault("level", logging.ERROR) # Shorten lists/strings for k, v in extra.iteritems(): data["extra"][k] = shorten(v, string_length=self.string_max_length, list_length=self.list_max_length) if culprit: data["culprit"] = culprit if "checksum" not in data: checksum_bits = handler.get_hash(data) else: checksum_bits = data["checksum"] if isinstance(checksum_bits, (list, tuple)): checksum = hashlib.md5() for bit in checksum_bits: checksum.update(to_string(bit)) checksum = checksum.hexdigest() else: checksum = checksum_bits data["checksum"] = checksum # Run the data through processors for processor in self.get_processors(): data.update(processor.process(data)) # Make sure all data is coerced data = transform(data) if "message" not in data: data["message"] = handler.to_string(data) data.update({"timestamp": date, "time_spent": time_spent, "event_id": event_id}) data.setdefault("project", self.project) data.setdefault("site", self.site) data.setdefault("public_key", self.public_key) return data
def capture(self, event_type, data=None, date=None, time_spent=None, event_id=None, extra=None, stack=None, **kwargs): """ Captures and processes an event and pipes it off to SentryClient.send. To use structured data (interfaces) with capture: >>> capture('Message', message='foo', data={ >>> 'sentry.interfaces.Http': { >>> 'url': '...', >>> 'data': {}, >>> 'query_string': '...', >>> 'method': 'POST', >>> }, >>> 'logger': 'logger.name', >>> 'site': 'site.name', >>> }, extra={ >>> 'key': 'value', >>> }) The finalized ``data`` structure contains the following (some optional) builtin values: >>> { >>> # the culprit and version information >>> 'culprit': 'full.module.name', # or /arbitrary/path >>> >>> # all detectable installed modules >>> 'modules': { >>> 'full.module.name': 'version string', >>> }, >>> >>> # arbitrary data provided by user >>> 'extra': { >>> 'key': 'value', >>> } >>> } :param event_type: the module path to the Event class. Builtins can use shorthand class notation and exclude the full module path. :param data: the data base, useful for specifying structured data interfaces. Any key which contains a '.' will be assumed to be a data interface. :param date: the datetime of this event :param time_spent: a float value representing the duration of the event :param event_id: a 32-length unique string identifying this event :param extra: a dictionary of additional standard metadata :param culprit: a string representing the cause of this event (generally a path to a function) :return: a 32-length string identifying this event """ if data is None: data = {} if extra is None: extra = {} if not date: date = datetime.datetime.utcnow() if stack is None: stack = self.auto_log_stacks if '.' not in event_type: # Assume it's a builtin event_type = 'raven.events.%s' % event_type handler = self.get_handler(event_type) result = handler.capture(**kwargs) # data (explicit) culprit takes over auto event detection culprit = result.pop('culprit', None) if data.get('culprit'): culprit = data['culprit'] for k, v in result.iteritems(): if k not in data: data[k] = v if stack and 'sentry.interfaces.Stacktrace' not in data: if stack is True: frames = iter_stack_frames() else: frames = stack data.update({ 'sentry.interfaces.Stacktrace': { 'frames': varmap(lambda k, v: shorten(v, string_length=self.string_max_length, list_length=self.list_max_length), get_stack_info(frames)) }, }) if 'sentry.interfaces.Stacktrace' in data and not culprit: culprit = get_culprit(data['sentry.interfaces.Stacktrace']['frames'], self.include_paths, self.exclude_paths) if not data.get('level'): data['level'] = logging.ERROR data['modules'] = get_versions(self.include_paths) data['server_name'] = self.name data.setdefault('extra', {}) data.setdefault('level', logging.ERROR) # Shorten lists/strings for k, v in extra.iteritems(): data['extra'][k] = shorten(v, string_length=self.string_max_length, list_length=self.list_max_length) if culprit: data['culprit'] = culprit if 'checksum' not in data: checksum_bits = handler.get_hash(data) else: checksum_bits = data['checksum'] if isinstance(checksum_bits, (list, tuple)): checksum = hashlib.md5() for bit in checksum_bits: checksum.update(to_string(bit)) checksum = checksum.hexdigest() else: checksum = checksum_bits data['checksum'] = checksum # create ID client-side so that it can be passed to application event_id = uuid.uuid4().hex # Run the data through processors for processor in self.get_processors(): data.update(processor.process(data)) # Make sure all data is coerced data = transform(data) if 'message' not in data: data['message'] = handler.to_string(data) data.update({ 'timestamp': date, 'time_spent': time_spent, 'event_id': event_id, }) data.setdefault('project', self.project) data.setdefault('site', self.site) self.send(**data) return (event_id, checksum)
def build_msg(self, event_type, data=None, date=None, time_spent=None, extra=None, stack=None, public_key=None, tags=None, **kwargs): """ Captures, processes and serializes an event into a dict object The result of ``build_msg`` should be a standardized dict, with all default values available. """ # create ID client-side so that it can be passed to application event_id = uuid.uuid4().hex if data is None: data = {} if extra is None: extra = {} if not date: date = datetime.datetime.utcnow() if stack is None: stack = self.auto_log_stacks if '.' not in event_type: # Assume it's a builtin event_type = 'raven.events.%s' % event_type handler = self.get_handler(event_type) result = handler.capture(**kwargs) # data (explicit) culprit takes over auto event detection culprit = result.pop('culprit', None) if data.get('culprit'): culprit = data['culprit'] for k, v in result.iteritems(): if k not in data: data[k] = v if stack and 'sentry.interfaces.Stacktrace' not in data: if stack is True: frames = iter_stack_frames() else: frames = stack data.update({ 'sentry.interfaces.Stacktrace': { 'frames': get_stack_info(frames, list_max_length=self.list_max_length, string_max_length=self.string_max_length) }, }) if 'sentry.interfaces.Stacktrace' in data: if self.include_paths: for frame in data['sentry.interfaces.Stacktrace']['frames']: if frame.get('in_app') is not None: continue path = frame.get('module') if not path: continue if path.startswith('raven.'): frame['in_app'] = False else: frame['in_app'] = (any(path.startswith(x) for x in self.include_paths) and not any(path.startswith(x) for x in self.exclude_paths)) if not culprit: culprit = get_culprit(data['sentry.interfaces.Stacktrace']['frames']) if not data.get('level'): data['level'] = kwargs.get('level') or logging.ERROR if not data.get('server_name'): data['server_name'] = self.name if not data.get('modules'): data['modules'] = self.get_module_versions() data['tags'] = tags or {} data.setdefault('extra', {}) data.setdefault('level', logging.ERROR) # Add extra context if self.extra: for k, v in self.extra.iteritems(): data['extra'].setdefault(k, v) for k, v in extra.iteritems(): data['extra'][k] = v if culprit: data['culprit'] = culprit if not data.get('checksum'): checksum_bits = handler.get_hash(data) else: checksum_bits = data['checksum'] if isinstance(checksum_bits, (list, tuple)): checksum = hashlib.md5() for bit in checksum_bits: checksum.update(to_string(bit)) checksum = checksum.hexdigest() else: checksum = checksum_bits data['checksum'] = checksum # Run the data through processors for processor in self.get_processors(): data.update(processor.process(data)) if 'message' not in data: data['message'] = handler.to_string(data) data.setdefault('project', self.project) # Legacy support for site attribute site = data.pop('site', None) or self.site if site: data['tags'].setdefault('site', site) # Make sure all data is coerced data = self.transform(data) # It's important date is added **after** we serialize data.update({ 'timestamp': date, 'time_spent': time_spent, 'event_id': event_id, 'platform': PLATFORM_NAME, }) return data
def _emit(self, record, **kwargs): data = {} extra = getattr(record, 'data', None) if not isinstance(extra, dict): if extra: extra = {'data': extra} else: extra = {} for k, v in iteritems(vars(record)): if k in RESERVED: continue if k.startswith('_'): continue if '.' not in k and k not in ('culprit', 'server_name', 'fingerprint'): extra[k] = v else: data[k] = v stack = getattr(record, 'stack', None) if stack is True: stack = iter_stack_frames() if stack: stack = self._get_targetted_stack(stack, record) date = datetime.datetime.utcfromtimestamp(record.created) event_type = 'raven.events.Message' handler_kwargs = { 'params': record.args, } try: handler_kwargs['message'] = text_type(record.msg) except UnicodeDecodeError: # Handle binary strings where it should be unicode... handler_kwargs['message'] = repr(record.msg)[1:-1] try: handler_kwargs['formatted'] = text_type(record.message) except UnicodeDecodeError: # Handle binary strings where it should be unicode... handler_kwargs['formatted'] = repr(record.message)[1:-1] # If there's no exception being processed, exc_info may be a 3-tuple of None # http://docs.python.org/library/sys.html#sys.exc_info if record.exc_info and all(record.exc_info): # capture the standard message first so that we ensure # the event is recorded as an exception, in addition to having our # message interface attached handler = self.client.get_handler(event_type) data.update(handler.capture(**handler_kwargs)) event_type = 'raven.events.Exception' handler_kwargs = {'exc_info': record.exc_info} data['level'] = record.levelno data['logger'] = record.name if hasattr(record, 'tags'): kwargs['tags'] = record.tags elif self.tags: kwargs['tags'] = self.tags kwargs.update(handler_kwargs) return self.client.capture( event_type, stack=stack, data=data, extra=extra, date=date, **kwargs)
def build_msg(self, event_type, data=None, date=None, time_spent=None, extra=None, stack=None, public_key=None, tags=None, fingerprint=None, **kwargs): """ Captures, processes and serializes an event into a dict object The result of ``build_msg`` should be a standardized dict, with all default values available. """ # create ID client-side so that it can be passed to application event_id = uuid.uuid4().hex data = merge_dicts(self.context.data, data) data.setdefault('tags', {}) data.setdefault('extra', {}) if '.' not in event_type: # Assume it's a builtin event_type = 'raven.events.%s' % event_type handler = self.get_handler(event_type) result = handler.capture(**kwargs) # data (explicit) culprit takes over auto event detection culprit = result.pop('culprit', None) if data.get('culprit'): culprit = data['culprit'] for k, v in iteritems(result): if k not in data: data[k] = v # auto_log_stacks only applies to events that are not exceptions # due to confusion about which stack is which and the automatic # application of stacktrace to exception objects by Sentry if stack is None and 'exception' not in data: stack = self.auto_log_stacks if stack and 'stacktrace' not in data: if stack is True: frames = iter_stack_frames() else: frames = stack stack_info = get_stack_info( frames, transformer=self.transform, capture_locals=self.capture_locals, ) data.update({ 'stacktrace': stack_info, }) if self.include_paths: for frame in self._iter_frames(data): if frame.get('in_app') is not None: continue path = frame.get('module') if not path: continue if path.startswith('raven.'): frame['in_app'] = False else: frame['in_app'] = (any( path.startswith(x) for x in self.include_paths) and not any( path.startswith(x) for x in self.exclude_paths)) if not culprit: if 'stacktrace' in data: culprit = get_culprit(data['stacktrace']['frames']) elif 'exception' in data: stacktrace = data['exception']['values'][0].get('stacktrace') if stacktrace: culprit = get_culprit(stacktrace['frames']) if not data.get('level'): data['level'] = kwargs.get('level') or logging.ERROR if not data.get('server_name'): data['server_name'] = self.name if not data.get('modules'): data['modules'] = self.get_module_versions() if self.release is not None: data['release'] = self.release if self.environment is not None: data['environment'] = self.environment data['tags'] = merge_dicts(self.tags, data['tags'], tags) data['extra'] = merge_dicts(self.extra, data['extra'], extra) # Legacy support for site attribute site = data.pop('site', None) or self.site if site: data['tags'].setdefault('site', site) if culprit: data['culprit'] = culprit if fingerprint: data['fingerprint'] = fingerprint # Run the data through processors for processor in self.get_processors(): data.update(processor.process(data)) if 'message' not in data: data['message'] = kwargs.get('message', handler.to_string(data)) # tags should only be key=>u'value' for key, value in iteritems(data['tags']): data['tags'][key] = to_unicode(value) # extra data can be any arbitrary value for k, v in iteritems(data['extra']): data['extra'][k] = self.transform(v) # It's important date is added **after** we serialize data.setdefault('project', self.remote.project) data.setdefault('timestamp', date or datetime.utcnow()) data.setdefault('time_spent', time_spent) data.setdefault('event_id', event_id) data.setdefault('platform', PLATFORM_NAME) data.setdefault('sdk', SDK_VALUE) # insert breadcrumbs if self.enable_breadcrumbs: crumbs = self.context.breadcrumbs.get_buffer() if crumbs: # Make sure we send the crumbs here as "values" as we use the # raven client internally in sentry and the alternative # submission option of a list here is not supported by the # internal sender. data.setdefault('breadcrumbs', {'values': crumbs}) return data
def _emit(self, record, **kwargs): data = {} for k, v in record.__dict__.iteritems(): if '.' not in k and k not in ('culprit',): continue data[k] = v stack = getattr(record, 'stack', None) if stack is True: stack = iter_stack_frames() if stack: # we might need to traverse this multiple times, so coerce it to a list stack = list(stack) frames = [] started = False last_mod = '' for item in stack: if isinstance(item, (list, tuple)): frame, lineno = item else: frame, lineno = item, item.f_lineno if not started: f_globals = getattr(frame, 'f_globals', {}) module_name = f_globals.get('__name__', '') if (last_mod and last_mod.startswith('logging')) \ and not module_name.startswith('logging'): started = True else: last_mod = module_name continue frames.append((frame, lineno)) # We must've not found a starting point if not frames: frames = stack stack = frames extra = getattr(record, 'data', None) if not isinstance(extra, dict): if extra: extra = {'data': extra} else: extra = {} # Add in all of the data from the record that we aren't already capturing for k in record.__dict__.keys(): if k in RESERVED: continue if k.startswith('_'): continue extra[k] = record.__dict__[k] date = datetime.datetime.utcfromtimestamp(record.created) event_type = 'raven.events.Message' handler_kwargs = {'message': record.msg, 'params': record.args} # If there's no exception being processed, exc_info may be a 3-tuple of None # http://docs.python.org/library/sys.html#sys.exc_info if record.exc_info and all(record.exc_info): # capture the standard message first so that we ensure # the event is recorded as an exception, in addition to having our # message interface attached handler = self.client.get_handler(event_type) data.update(handler.capture(**handler_kwargs)) # ensure message is propagated, otherwise the exception will overwrite it data['message'] = record.message event_type = 'raven.events.Exception' handler_kwargs = {'exc_info': record.exc_info} # HACK: discover a culprit when we normally couldn't elif not (data.get('sentry.interfaces.Stacktrace') or data.get('culprit')) and (record.name or record.funcName): culprit = label_from_frame({'module': record.name, 'function': record.funcName}) if culprit: data['culprit'] = culprit data['level'] = record.levelno data['logger'] = record.name if hasattr(record, 'tags'): kwargs['tags'] = record.tags kwargs.update(handler_kwargs) return self.client.capture(event_type, stack=stack, data=data, extra=extra, date=date, **kwargs)