# it's worth it since the encoding errors that would otherwise
# result are so useless (and tornado is fond of using utf8-encoded
# byte strings whereever possible).
- try:
- message = _unicode(record.message)
- except UnicodeDecodeError:
- message = repr(record.message)
+ def safe_unicode(s):
+ try:
+ return _unicode(s)
+ except UnicodeDecodeError:
+ return repr(s)
- formatted = prefix + " " + message
+ formatted = prefix + " " + safe_unicode(record.message)
if record.exc_info:
if not record.exc_text:
record.exc_text = self.formatException(record.exc_info)
if record.exc_text:
- formatted = formatted.rstrip() + "\n" + record.exc_text
+ formatted = (formatted.rstrip() + "\n" +
+ safe_unicode(record.exc_text))
return formatted.replace("\n", "\n ")
class LogFormatterTest(unittest.TestCase):
- LINE_RE = re.compile(b"\x01\\[E [0-9]{6} [0-9]{2}:[0-9]{2}:[0-9]{2} log_test:[0-9]+\\]\x02 (.*)")
+ # Matches the output of a single logging call (which may be multiple lines
+ # if a traceback was included, so we use the DOTALL option)
+ LINE_RE = re.compile(b"(?s)\x01\\[E [0-9]{6} [0-9]{2}:[0-9]{2}:[0-9]{2} log_test:[0-9]+\\]\x02 (.*)")
def setUp(self):
self.formatter = LogFormatter(color=False)
# copy of test_bytes_logging.
self.assertEqual(self.get_output(), utf8(repr(utf8(u("\u00e9")))))
+ def test_bytes_exception_logging(self):
+ try:
+ raise Exception(b'\xe9')
+ except Exception:
+ self.logger.exception('caught exception')
+ # This will be "Exception: \xe9" on python 2 or
+ # "Exception: b'\xe9'" on python 3.
+ self.assertRegexpMatches(self.get_output(), br'Exception.*\\xe9')
+
class UnicodeLogFormatterTest(LogFormatterTest):
def make_handler(self, filename):