def get_stack_info(frames): results = [] for frame in frames: # Support hidden frames if frame.f_locals.get("__traceback_hide__"): continue filename = frame.f_code.co_filename function = frame.f_code.co_name lineno = frame.f_lineno - 1 loader = frame.f_globals.get("__loader__") module_name = frame.f_globals.get("__name__") pre_context_lineno, pre_context, context_line, post_context = get_lines_from_file( filename, lineno, 7, loader, module_name ) if pre_context_lineno is not None: results.append( { "id": id(frame), "filename": filename, "module": module_name, "function": function, "lineno": lineno + 1, # TODO: vars need to be references "vars": transform(frame.f_locals.items()), "pre_context": pre_context, "context_line": context_line, "post_context": post_context, "pre_context_lineno": pre_context_lineno + 1, } ) return results
def get_stack_info(frames): results = [] for frame in frames: # Support hidden frames if frame.f_locals.get('__traceback_hide__'): continue filename = frame.f_code.co_filename function = frame.f_code.co_name lineno = frame.f_lineno - 1 loader = frame.f_globals.get('__loader__') module_name = frame.f_globals.get('__name__') pre_context_lineno, pre_context, context_line, post_context = get_lines_from_file(filename, lineno, 7, loader, module_name) if pre_context_lineno is not None: results.append({ 'filename': filename, 'module': module_name, 'function': function, 'lineno': lineno + 1, # TODO: vars need to be references 'vars': transform(frame.f_locals.items()), 'pre_context': pre_context, 'context_line': context_line, 'post_context': post_context, 'pre_context_lineno': pre_context_lineno + 1, }) return results
def test_int_subclass(self): class X(int): pass result = transform(X()) self.assertEquals(type(result), int) self.assertEquals(result, 0)
def test_uuid(self): import uuid uuid = uuid.uuid4() result = transform(uuid) self.assertEquals(result, repr(uuid)) self.assertTrue(type(result), str)
def get_stack_info(frames): results = [] for frame in frames: # Support hidden frames if frame.f_locals.get('__traceback_hide__'): continue filename = frame.f_code.co_filename function = frame.f_code.co_name lineno = frame.f_lineno - 1 loader = frame.f_globals.get('__loader__') module_name = frame.f_globals.get('__name__') pre_context_lineno, pre_context, context_line, post_context = get_lines_from_file( filename, lineno, 7, loader, module_name) if pre_context_lineno is not None: results.append({ 'filename': filename, 'module': module_name, 'function': function, 'lineno': lineno + 1, # TODO: vars need to be references 'vars': transform(frame.f_locals.items()), 'pre_context': pre_context, 'context_line': context_line, 'post_context': post_context, 'pre_context_lineno': pre_context_lineno + 1, }) return results
def test_dict_keys(self): x = {u'foo': 'bar'} result = transform(x) keys = result.keys() self.assertEquals(len(keys), 1) self.assertEquals(keys[0], 'foo') self.assertTrue(isinstance(keys[0], str))
def test_dict_keys_utf8_as_unicode(self): x = {u"רונית מגן": "bar"} result = transform(x) keys = result.keys() self.assertEquals(len(keys), 1) self.assertTrue(isinstance(keys[0], str)) self.assertEquals(keys[0], "רונית מגן")
def test_dict_keys(self): x = {u"foo": "bar"} result = transform(x) keys = result.keys() self.assertEquals(len(keys), 1) self.assertTrue(isinstance(keys[0], str)) self.assertEquals(keys[0], "foo")
def test_dict_keys_utf8_as_unicode(self): x = {u'רונית מגן': 'bar'} result = transform(x) keys = result.keys() self.assertEquals(len(keys), 1) self.assertTrue(type(keys[0]), str) self.assertEquals(keys[0], 'רונית מגן')
def test_dict_keys_utf8_as_str(self): x = {'רונית מגן': 'bar'} result = transform(x) keys = result.keys() self.assertEquals(len(keys), 1) self.assertTrue(isinstance(keys[0], str)) self.assertEquals(keys[0], 'רונית מגן')
def test_custom_repr(self): class Foo(object): def __sentry__(self): return 'example' x = Foo() result = transform(x) self.assertEquals(result, 'example')
def test_dict_keys(self): x = {u'foo': 'bar'} result = transform(x) self.assertEquals(type(result), dict) keys = result.keys() self.assertEquals(len(keys), 1) self.assertTrue(type(keys[0]), str) self.assertEquals(keys[0], 'foo')
def test_broken_repr(self): class Foo(object): def __repr__(self): raise ValueError x = Foo() result = transform(x) self.assertEquals(result, u"<BadRepr: <class 'tests.utils.encoding.tests.Foo'>>")
def test_broken_repr(self): class Foo(object): def __repr__(self): raise ValueError x = Foo() result = transform(x) self.assertEquals( result, u"<BadRepr: <class 'tests.utils.encoding.tests.Foo'>>")
def create_from_exception(self, exc_info=None, **kwargs): """ Creates an event from an exception. >>> try: >>> exc_info = sys.exc_info() >>> client.create_from_exception(exc_info) >>> finally: >>> del exc_info If exc_info is not provided, or is set to True, then this method will perform the ``exc_info = sys.exc_info()`` and the requisite clean-up for you. """ new_exc = False if not exc_info or exc_info is True: new_exc = True exc_info = sys.exc_info() data = kwargs.pop('data', {}) or {} try: exc_type, exc_value, exc_traceback = exc_info frames = varmap( shorten, get_stack_info(iter_traceback_frames(exc_traceback))) if hasattr(exc_type, '__class__'): exc_module = exc_type.__class__.__module__ else: exc_module = None data['__sentry__'] = {} data['__sentry__']['frames'] = frames data['__sentry__']['exception'] = [exc_module, exc_value.args] tb_message = '\n'.join( traceback.format_exception(exc_type, exc_value, exc_traceback)) kwargs.setdefault('message', transform(force_unicode(exc_value))) return self.process(class_name=exc_type.__name__, traceback=tb_message, data=data, **kwargs) finally: # It's important that we cleanup the frames object (specifically exc_info[2]) # to ensure that GC can happen properly. if new_exc: try: del exc_info del exc_traceback except Exception, e: logger.exception(e)
def create_from_exception(self, exc_info=None, **kwargs): """ Creates an event from an exception. >>> try: >>> exc_info = sys.exc_info() >>> client.create_from_exception(exc_info) >>> finally: >>> del exc_info If exc_info is not provided, or is set to True, then this method will perform the ``exc_info = sys.exc_info()`` and the requisite clean-up for you. """ new_exc = False if not exc_info or exc_info is True: new_exc = True exc_info = sys.exc_info() data = kwargs.pop('data', {}) or {} try: exc_type, exc_value, exc_traceback = exc_info frames = varmap(shorten, get_stack_info(iter_traceback_frames(exc_traceback))) if hasattr(exc_type, '__class__'): exc_module = exc_type.__class__.__module__ else: exc_module = None data['__sentry__'] = {} data['__sentry__']['frames'] = frames data['__sentry__']['exception'] = [exc_module, exc_value.args] tb_message = '\n'.join(traceback.format_exception(exc_type, exc_value, exc_traceback)) kwargs.setdefault('message', transform(force_unicode(exc_value))) return self.process( class_name=exc_type.__name__, traceback=tb_message, data=data, **kwargs ) finally: # It's important that we cleanup the frames object (specifically exc_info[2]) # to ensure that GC can happen properly. if new_exc: try: del exc_info del exc_traceback except Exception, e: logger.exception(e)
def get_stack_info(frames): """ Given a list of frames, returns a list of stack information dictionary objects that are JSON-ready. """ results = [] for frame in frames: # Support hidden frames f_locals = frame.f_locals if _getitem_from_frame(f_locals, '__traceback_hide__'): continue abs_path = frame.f_code.co_filename function = frame.f_code.co_name lineno = frame.f_lineno - 1 loader = frame.f_globals.get('__loader__') module_name = frame.f_globals.get('__name__') pre_context, context_line, post_context = get_lines_from_file(abs_path, lineno, 3, loader, module_name) # Try to pull a relative file path # This changes /foo/site-packages/baz/bar.py into baz/bar.py try: base_filename = sys.modules[module_name.split('.', 1)[0]].__file__ filename = abs_path.split(base_filename.rsplit('/', 2)[0], 1)[-1][1:] except: filename = abs_path if context_line: f_locals = frame.f_locals if not isinstance(f_locals, dict): # XXX: Genshi (and maybe others) have broken implementations of # f_locals that are not actually dictionaries try: f_locals = to_dict(f_locals) except Exception, e: print e f_locals = '<invalid local scope>' results.append({ 'abs_path': abs_path, 'filename': filename or abs_path, 'module': module_name, 'function': function, 'lineno': lineno + 1, # TODO: vars need to be references 'vars': transform(f_locals), 'pre_context': pre_context, 'context_line': context_line, 'post_context': post_context, })
def get_stack_info(frames): """ Given a list of frames, returns a list of stack information dictionary objects that are JSON-ready. """ results = [] for frame in frames: # Support hidden frames f_locals = getattr(frame, 'f_locals', {}) if _getitem_from_frame(f_locals, '__traceback_hide__'): continue f_globals = getattr(frame, 'f_globals', {}) abs_path = frame.f_code.co_filename function = frame.f_code.co_name lineno = frame.f_lineno - 1 loader = f_globals.get('__loader__') module_name = f_globals.get('__name__') pre_context, context_line, post_context = get_lines_from_file(abs_path, lineno, 3, loader, module_name) # Try to pull a relative file path # This changes /foo/site-packages/baz/bar.py into baz/bar.py try: base_filename = sys.modules[module_name.split('.', 1)[0]].__file__ filename = abs_path.split(base_filename.rsplit('/', 2)[0], 1)[-1][1:] except: filename = abs_path if context_line: if f_locals is not None and not isinstance(f_locals, dict): # XXX: Genshi (and maybe others) have broken implementations of # f_locals that are not actually dictionaries try: f_locals = to_dict(f_locals) except Exception: f_locals = '<invalid local scope>' results.append({ 'abs_path': abs_path, 'filename': filename or abs_path, 'module': module_name, 'function': function, 'lineno': lineno + 1, # TODO: vars need to be references 'vars': transform(f_locals), 'pre_context': pre_context, 'context_line': context_line, 'post_context': post_context, }) return results
def create_from_exception(self, exc_info=None, **kwargs): """ Creates an event from an exception. >>> try: >>> exc_info = sys.exc_info() >>> client.create_from_exception(exc_info) >>> finally: >>> del exc_info """ new_exc = bool(exc_info) if not exc_info or exc_info is True: exc_info = sys.exc_info() data = kwargs.pop('data', {}) or {} try: exc_type, exc_value, exc_traceback = exc_info frames = varmap(shorten, get_stack_info(iter_traceback_frames(exc_traceback))) if hasattr(exc_type, '__class__'): exc_module = exc_type.__class__.__module__ else: exc_module = None data['__sentry__'] = {} data['__sentry__']['frames'] = frames data['__sentry__']['exception'] = [exc_module, exc_value.args] tb_message = '\n'.join(traceback.format_exception(exc_type, exc_value, exc_traceback)) kwargs.setdefault('message', transform(force_unicode(exc_value))) return self.process( class_name=exc_type.__name__, traceback=tb_message, data=data, **kwargs ) finally: if new_exc: try: del exc_info except Exception, e: logger.exception(e)
def get_stack_info(frames): results = [] for frame in frames: # Support hidden frames if frame.f_locals.get('__traceback_hide__'): continue abs_path = frame.f_code.co_filename function = frame.f_code.co_name lineno = frame.f_lineno - 1 loader = frame.f_globals.get('__loader__') module_name = frame.f_globals.get('__name__') pre_context, context_line, post_context = get_lines_from_file( abs_path, lineno, 3, loader, module_name) # Try to pull a relative file path # This changes /foo/site-packages/baz/bar.py into baz/bar.py try: base_filename = sys.modules[module_name.split('.', 1)[0]].__file__ filename = abs_path.split(base_filename.rsplit('/', 2)[0], 1)[-1][1:] except: filename = abs_path if context_line: results.append({ 'abs_path': abs_path, 'filename': filename or abs_path, 'module': module_name, 'function': function, 'lineno': lineno + 1, # TODO: vars need to be references 'vars': transform(frame.f_locals), 'pre_context': pre_context, 'context_line': context_line, 'post_context': post_context, }) return results
def get_stack_info(frames): results = [] for frame in frames: # Support hidden frames if frame.f_locals.get('__traceback_hide__'): continue abs_path = frame.f_code.co_filename function = frame.f_code.co_name lineno = frame.f_lineno - 1 loader = frame.f_globals.get('__loader__') module_name = frame.f_globals.get('__name__') pre_context, context_line, post_context = get_lines_from_file(abs_path, lineno, 3, loader, module_name) # Try to pull a relative file path # This changes /foo/site-packages/baz/bar.py into baz/bar.py try: base_filename = sys.modules[module_name.split('.', 1)[0]].__file__ filename = abs_path.split(base_filename.rsplit('/', 2)[0], 1)[-1][1:] except: filename = abs_path if context_line: results.append({ 'abs_path': abs_path, 'filename': filename or abs_path, 'module': module_name, 'function': function, 'lineno': lineno + 1, # TODO: vars need to be references 'vars': transform(frame.f_locals), 'pre_context': pre_context, 'context_line': context_line, 'post_context': post_context, }) return results
def test_bool(self): result = transform(True) self.assertEquals(type(result), bool) self.assertEquals(result, True)
def test_recursive(self): x = [] x.append(x) result = transform(x) self.assertEquals(result, ['<...>'])
def test_uuid(self): x = uuid.uuid4() result = transform(x) self.assertEquals(result, repr(x)) self.assertTrue(type(result), str)
def test_correct_unicode(self): x = 'רונית מגן'.decode('utf-8') result = transform(x) self.assertEquals(type(result), unicode) self.assertEquals(result, x)
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 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_uuid(self): import uuid uuid = uuid.uuid4() self.assertEquals(transform(uuid), repr(uuid))
def test_correct_unicode(self): x = "רונית מגן".decode("utf-8") result = transform(x) self.assertEquals(result, x)
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 get_stack_info(frames): """ Given a list of frames, returns a list of stack information dictionary objects that are JSON-ready. We have to be careful here as certain implementations of the _Frame class do not contain the nescesary data to lookup all of the information we want. """ results = [] for frame in frames: # Support hidden frames f_locals = getattr(frame, 'f_locals', {}) if _getitem_from_frame(f_locals, '__traceback_hide__'): continue f_globals = getattr(frame, 'f_globals', {}) loader = f_globals.get('__loader__') module_name = f_globals.get('__name__') f_code = getattr(frame, 'f_code', None) if f_code: abs_path = frame.f_code.co_filename function = frame.f_code.co_name else: abs_path = None function = None lineno = getattr(frame, 'f_lineno', None) if lineno: lineno -= 1 if lineno is not None and abs_path: pre_context, context_line, post_context = get_lines_from_file(abs_path, lineno, 3, loader, module_name) else: pre_context, context_line, post_context = [], None, [] # Try to pull a relative file path # This changes /foo/site-packages/baz/bar.py into baz/bar.py try: base_filename = sys.modules[module_name.split('.', 1)[0]].__file__ filename = abs_path.split(base_filename.rsplit('/', 2)[0], 1)[-1][1:] except: filename = abs_path if not filename: filename = abs_path if f_locals is not None and not isinstance(f_locals, dict): # XXX: Genshi (and maybe others) have broken implementations of # f_locals that are not actually dictionaries try: f_locals = to_dict(f_locals) except Exception: f_locals = '<invalid local scope>' frame_result = { 'abs_path': abs_path, 'filename': filename, 'module': module_name, 'function': function, 'lineno': lineno + 1, 'vars': transform(f_locals), } if context_line: frame_result.update({ 'pre_context': pre_context, 'context_line': context_line, 'post_context': post_context, }) results.append(frame_result) return results
def get_stack_info(frames): """ Given a list of frames, returns a list of stack information dictionary objects that are JSON-ready. We have to be careful here as certain implementations of the _Frame class do not contain the nescesary data to lookup all of the information we want. """ results = [] for frame, lineno in frames: # Support hidden frames f_locals = getattr(frame, 'f_locals', {}) if _getitem_from_frame(f_locals, '__traceback_hide__'): continue f_globals = getattr(frame, 'f_globals', {}) loader = f_globals.get('__loader__') module_name = f_globals.get('__name__') f_code = getattr(frame, 'f_code', None) if f_code: abs_path = frame.f_code.co_filename function = frame.f_code.co_name else: abs_path = None function = None if lineno: lineno -= 1 if lineno is not None and abs_path: pre_context, context_line, post_context = get_lines_from_file( abs_path, lineno, 3, loader, module_name) else: pre_context, context_line, post_context = [], None, [] # Try to pull a relative file path # This changes /foo/site-packages/baz/bar.py into baz/bar.py try: base_filename = sys.modules[module_name.split('.', 1)[0]].__file__ filename = abs_path.split(base_filename.rsplit('/', 2)[0], 1)[-1][1:] except: filename = abs_path if not filename: filename = abs_path if f_locals is not None and not isinstance(f_locals, dict): # XXX: Genshi (and maybe others) have broken implementations of # f_locals that are not actually dictionaries try: f_locals = to_dict(f_locals) except Exception: f_locals = '<invalid local scope>' frame_result = { 'abs_path': abs_path, 'filename': filename, 'module': module_name, 'function': function, 'lineno': lineno + 1, 'vars': transform(f_locals), } if context_line: frame_result.update({ 'pre_context': pre_context, 'context_line': context_line, 'post_context': post_context, }) results.append(frame_result) return results
def test_bad_string(self): x = "The following character causes problems: \xd4" result = transform(x) self.assertEquals(result, "<type 'str'>")
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 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, **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_incorrect_unicode(self): x = 'רונית מגן' result = transform(x) self.assertEquals(type(result), str) self.assertEquals(result, 'רונית מגן')
def test_bad_string(self): x = 'The following character causes problems: \xd4' result = transform(x) self.assertEquals(type(result), str) self.assertEquals(result, '<type \'str\'>')
def test_float(self): result = transform(13.0) self.assertEquals(type(result), float) self.assertEquals(result, 13.0)
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)