Actually, I think I finally found the error and the correct way: I seem to be using logging.exception('msg') all the time. You should not pass an exception, but the message:
# encoding: utf-8 import logging try: raise Exception('jörn') except Exception as e: logging.exception('exception occurred') try: raise Exception(u'jörn') except Exception as e: logging.exception('exception occurred')
the execution of the above correctly logs the exception:
$ python test.py ERROR:root:exception occurred Traceback (most recent call last): File "test.py", line 4, in <module> raise Exception('jörn') Exception: jörn ERROR:root:exception occurred Traceback (most recent call last): File "test.py", line 10, in <module> raise Exception(u'jörn') Exception: j\xf6rn
The reason for the failure of logging.exception(e) is that it passes the e exception up to logging.Formatter.format() , where it appears as record.message , which is still an Exception object.
Then, on line 474, the following happens:
s = self._fmt % record.__dict__
which is equivalent to the following:
s = '%(levelname)s:%(name)s:%(message)s' % { 'levelname': 'ERROR', 'name': 'ROOT', 'message': Exception(u'jörn') }
It turns out, therefore, if message is one of ['jörn', u'jörn', Exception('jörn')] , it works, and not if it is Exception(u'jörn') :
>>> 'foo %s' % 'jörn' 'foo j\xc3\xb6rn' >>> 'foo %s' % u'jörn' u'foo j\xf6rn' >>> 'foo %s' % Exception('jörn') 'foo j\xc3\xb6rn' >>> 'foo %s' % Exception(u'jörn') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 1: ordinal not in range(128)
As you can see, there is an automatic boost that happens for strings in Unicode, and therefore the following works:
>>> logging.error('jörn') ERROR:root:jörn >>> logging.error(u'jörn') ERROR:root:jörn
This conversion to unicode fails when you try it with an Exception object that does not properly process the encoding of its message (which, unfortunately, looks like a lot of libraries).
It appears that calling logging.exception(msg) uses repr() to format the exception for logging and prefix it with msg . Therefore, if you did not make a mistake and did not send an exception to logging.exception , it will correctly register it.
Shortly speaking:
Do not use logging.exception(e) , but logging.exception('exception occurred') . It will automatically and correctly add a formatted exception to your log. If you really want to use the exception message without assuming some encoding, you can make logging.exception(repr(e)) most secure.