Python のログ パッケージを使用して、UTF-8 でエンコードされた文字列をファイルに記録しようとしています。簡単な例として:
import logging
def logging_test():
handler = logging.FileHandler("/home/ted/logfile.txt", "w",
encoding = "UTF-8")
formatter = logging.Formatter("%(message)s")
handler.setFormatter(formatter)
root_logger = logging.getLogger()
root_logger.addHandler(handler)
root_logger.setLevel(logging.INFO)
# This is an o with a hat on it.
byte_string = '\xc3\xb4'
unicode_string = unicode("\xc3\xb4", "utf-8")
print "printed unicode object: %s" % unicode_string
# Explode
root_logger.info(unicode_string)
if __name__ == "__main__":
logging_test()
これは、logging.info() 呼び出し時に UnicodeDecodeError で爆発します。
より低いレベルでは、Python のロギング パッケージは codecs パッケージを使用してログ ファイルを開き、エンコードとして「UTF-8」引数を渡します。これはすべて問題ありませんが、Unicode オブジェクトではなくバイト文字列をファイルに書き込もうとするため、問題が発生します。基本的に、Python は次の処理を行っています。
file_handler.write(unicode_string.encode("UTF-8"))
これを実行する必要がある場合:
file_handler.write(unicode_string)
これは Python のバグでしょうか、それとも私がおかしなことをしているのでしょうか? ちなみに、これは標準の Python 2.6 インストールです。
ベストアンサー1
次のようなコードがあるとします:
raise Exception(u'щ')
原因:
File "/usr/lib/python2.7/logging/__init__.py", line 467, in format
s = self._fmt % record.__dict__
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)
これは、フォーマット文字列がバイト文字列であるのに対し、フォーマット文字列引数の一部が非 ASCII 文字を含む Unicode 文字列であるために発生します。
>>> "%(message)s" % {'message': Exception(u'\u0449')}
*** UnicodeEncodeError: 'ascii' codec can't encode character u'\u0449' in position 0: ordinal not in range(128)
フォーマット文字列を Unicode にすると、問題は解決します。
>>> u"%(message)s" % {'message': Exception(u'\u0449')}
u'\u0449'
したがって、ログ設定では、すべてのフォーマット文字列を Unicode にします。
'formatters': {
'simple': {
'format': u'%(asctime)-s %(levelname)s [%(name)s]: %(message)s',
'datefmt': '%Y-%m-%d %H:%M:%S',
},
...
logging
そして、 Unicode フォーマット文字列を使用するようにデフォルトのフォーマッタにパッチを適用します。
logging._defaultFormatter = logging.Formatter(u"%(message)s")