def test_exception_without_traceback(self): """ If an Exception is missing a traceback, render it anyway. """ rv = format_exc_info(None, None, {"exc_info": Exception("no traceback!")}) assert {"exception": "Exception: no traceback!"} == rv
def format(self, record): """ Converts the log records message to a dictionary and pass it on to the ``structlog.stdlib.ProcessorFormatter`` to do its magic. """ # Make sure message always is a dictionary message = record.getMessage() try: message = json.loads(message) except json.JSONDecodeError: message = {'event': message} # Format exceptions to JSON and set `exc_info` to None in order # to avoid the stdlib logger to write it out. if record.exc_info and 'exc_info' not in message: message.update( **format_exc_info(None, record.levelname, { 'exc_info': record.exc_info, 'event': record.getMessage() })) record.exc_info = None record.msg = self.json_serializer(self.add_fields(record, message), default=self.json_default, cls=self.json_encoder, indent=self.json_indent) # We're done formatting the `record.msg` attribute. # Need to delete `record.args` so that `record.getMessage()` # don't raise any errors. record.args = () return super(JsonProcessorFormatter, self).format(record)
def test_exception_without_traceback(self): """ If an Exception is missing a traceback, render it anyway. """ rv = format_exc_info(None, None, { "exc_info": Exception("no traceback!") }) assert {"exception": "Exception: no traceback!"} == rv
def test_formats_tuple(self, monkeypatch): """ If exc_info is a tuple, it is used. """ monkeypatch.setattr(structlog.processors, "_format_exception", lambda exc_info: exc_info) d = format_exc_info(None, None, {"exc_info": (None, None, 42)}) assert {"exception": (None, None, 42)} == d
def test_gets_exc_info_on_bool(self): # monkeypatching sys.exc_info makes currently py.test return 1 on # success. try: raise ValueError('test') except ValueError: d = format_exc_info(None, None, {'exc_info': True}) assert 'exc_info' not in d assert 'raise ValueError(\'test\')\nValueError: test' in d['exception']
def test_removes_exception_after_printing(self, sio): """ After pretty printing `exception` is removed from the event_dict. """ epp = ExceptionPrettyPrinter(sio) try: raise ValueError except ValueError: ed = format_exc_info(None, None, {'exc_info': True}) assert 'exception' in ed new_ed = epp(None, None, ed) assert 'exception' not in new_ed
def test_gets_exc_info_on_bool(self): """ If exc_info is True, it is obtained using sys.exc_info(). """ # monkeypatching sys.exc_info makes currently py.test return 1 on # success. try: raise ValueError('test') except ValueError: d = format_exc_info(None, None, {"exc_info": True}) assert "exc_info" not in d assert "raise ValueError('test')\nValueError: test" in d["exception"]
def test_exception_on_py3(self, monkeypatch): """ Passing excetions as exc_info is valid on Python 3. """ monkeypatch.setattr(structlog.processors, "_format_exception", lambda exc_info: exc_info) try: raise ValueError("test") except ValueError as e: d = format_exc_info(None, None, {"exc_info": e}) assert {"exception": (ValueError, e, e.__traceback__)} == d else: pytest.fail("Exception not raised.")
def test_prints_exception(self, sio): """ If there's an `exception` key in the event_dict, just print it out. This happens if `format_exc_info` was run before us in the chain. """ epp = ExceptionPrettyPrinter(file=sio) try: raise ValueError except ValueError: ed = format_exc_info(None, None, {'exc_info': True}) epp(None, None, ed) out = sio.getvalue() assert 'test_prints_exception' in out assert 'raise ValueError' in out
def test_formats_tuple(self, monkeypatch): monkeypatch.setattr(structlog.processors, '_format_exception', lambda exc_info: exc_info) d = format_exc_info(None, None, {'exc_info': (None, None, 42)}) assert {'exception': (None, None, 42)} == d