UTF-8 В журнале Python, как? - PullRequest
       12

UTF-8 В журнале Python, как?

39 голосов
/ 09 октября 2009

Я пытаюсь записать строку в кодировке UTF-8 в файл, используя пакет журналов Python. В качестве примера игрушки:

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()

Это взрывается с UnicodeDecodeError при вызове logging.info ().

На более низком уровне пакет журналов Python использует пакет кодеков, чтобы открыть файл журнала, передавая аргумент "UTF-8" в качестве кодировки. Это все хорошо, но он пытается записать байтовые строки в файл вместо объектов Unicode, которые взрываются. По сути, Python делает это:

file_handler.write(unicode_string.encode("UTF-8"))

Когда это должно быть сделано:

file_handler.write(unicode_string)

Это ошибка в Python или я принимаю сумасшедшие таблетки? Кстати, это стандартная установка Python 2.6.

Ответы [ 4 ]

27 голосов
/ 11 марта 2014

Имеющий код типа:

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-символами:

>>> "%(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")
14 голосов
/ 09 октября 2009

Убедитесь, что у вас установлена ​​последняя версия Python 2.6 - некоторые ошибки Юникода были найдены и исправлены после выхода версии 2.6. Например, в моей системе Ubuntu Jaunty я запустил скопированный и вставленный скрипт, удалив только префикс / home / ted / из имени файла журнала. Результат (скопировано и вставлено из окна терминала):

vinay@eta-jaunty:~/projects/scratch$ python --version
Python 2.6.2
vinay@eta-jaunty:~/projects/scratch$ python utest.py 
printed unicode object: ô
vinay@eta-jaunty:~/projects/scratch$ cat logfile.txt 
ô
vinay@eta-jaunty:~/projects/scratch$ 

В окне Windows:

C:\temp>python --version
Python 2.6.2

C:\temp>python utest.py
printed unicode object: ô

И содержимое файла:

alt text

Это также может объяснить, почему Леннарт Регебро тоже не смог воспроизвести его.

2 голосов
/ 09 октября 2009

Попробуйте это:

import logging

def logging_test():
    log = open("./logfile.txt", "w")
    handler = logging.StreamHandler(log)
    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.encode("utf8", "replace"))


if __name__ == "__main__":
    logging_test()

Для чего бы я ни ожидал, я должен был использовать codecs.open, чтобы открыть файл с кодировкой utf-8, но это либо значение по умолчанию, либо что-то еще здесь происходит, поскольку он работает так, как это.

1 голос
/ 10 октября 2009

Если я правильно понял вашу проблему, такая же проблема должна возникнуть в вашей системе, когда вы просто:

str(u'ô')

Полагаю, автоматическое кодирование в кодировку локали в Unix не будет работать, пока вы не включите ветку if с поддержкой локали в функции setencoding в своем модуле site через locale. Этот файл обычно находится в /usr/lib/python2.x, его стоит проверить в любом случае. AFAIK, с учетом локали setencoding по умолчанию отключено (это верно для моей установки Python 2.6).

На выбор:

  • Позвольте системе выяснить, как правильно кодировать строки Unicode в байты, или сделайте это в своем коде (необходима некоторая конфигурация для конкретного сайта site.py)
  • Кодировать строки Unicode в вашем коде и выводить только байты

См. Также Призрачное сетевое кодирование , выполненное Яном Бикингом и связанными ссылками.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...