2009-10-09 11 views
28

Próbuję zalogować łańcuch kodowany w UTF-8 do pliku przy użyciu pakietu logowania Pythona. Jako zabawny przykład:UTF-8 W logowaniu Python, jak?

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

To eksploduje za pomocą UnicodeDecodeError w wywołaniu logging.info().

Na niższym poziomie pakiet rejestrowania w języku Python używa pakietu kodeków do otwarcia pliku dziennika, przekazując jako argument kodowanie "UTF-8". Wszystko dobrze i dobrze, ale próbuje napisać ciągi bajtów do pliku zamiast do obiektów unicode, które eksplodują. Zasadniczo, Python robi to:

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

Kiedy należy to zrobić:

file_handler.write(unicode_string) 

Jest to błąd w Pythonie, albo ja biorąc szalone pigułki? FWIW, to jest instalacja Pythona 2.6.

+0

Twój kod działa perfekcyjnie tutaj . Bardzo się starałem, aby to się nie udało, ale mi się nie udało. –

+0

I masz rację, Python koduje go za pomocą UTF-8, ponieważ prosi o plik wyjściowy, jakiego kodowania użyć, i podałeś UTF-8, więc wszystko jest w porządku. –

+1

Musiałem uderzyć w maszynę dojazdową, aby znaleźć [przykład] (http://web.archive.org/web/20100107060919/http://tony.czechit.net/2009/02/unicode-support-for-pythons -logowanie-biblioteka /), o którym wspomniałeś. Ciekawy. – Epu

Odpowiedz

13

Sprawdź, czy masz najnowszy Python 2.6 - niektóre błędy Unicode zostały znalezione i naprawione od czasu pojawienia się 2.6. Na przykład w systemie Ubuntu Jaunty uruchomiłem skrypt skopiowany i wklejony, usuwając tylko prefiks "/ home/ted /" z nazwy pliku dziennika. Wynik (skopiowany i wklejony z oknie terminala):

 
[email protected]:~/projects/scratch$ python --version 
Python 2.6.2 
[email protected]:~/projects/scratch$ python utest.py 
printed unicode object: ô 
[email protected]:~/projects/scratch$ cat logfile.txt 
ô 
[email protected]:~/projects/scratch$ 

na pole Windows:

 
C:\temp>python --version 
Python 2.6.2 

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

a zawartość pliku:

alt text

Może to także wyjaśniać dlaczego Lennart Regebro też nie mógł tego powtórzyć.

+0

Tak, to było to. Wystąpił błąd w pakiecie logowania Pythona, który został naprawiony w późniejszej wersji. –

+0

Używam Python 2.6.1 (r261: 67.515, 11 lutego 2010, 00:51:29) [GCC 4.2.1 (Apple Inc. zbudować 5646)] w Darwin na moim iMac, a ja nadal pojawia się ten sam błąd. Naprawiono błąd? – Tsf

+1

Tak, to było - zdarzyło się między 2.6.1 a 2.6.2, w wersji 69448: http://svn.python.org/view?view=rev&revision=69448 - więc musisz uaktualnić do nowszej wersji. –

1

Spróbuj tego:

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

Na co warto Spodziewałem się użyć codecs.open otworzyć plik z kodowaniem UTF-8, ale albo to domyślny lub coś innego się dzieje tutaj, ponieważ działa tak, jak jest.

+0

NameError: nazwa globalna 'unicode' nie jest zdefiniowana – Gank

+0

@Gank używasz python 3 Zgaduję – warvariuc

1

Jeśli zrozumiałem problem właściwie ten sam problem powinien pojawić się w systemie po prostu zrobić:

str(u'ô') 

Chyba automatycznego kodowania do kodowania locale na Uniksie nie będzie działać dopóki nie zostaną włączone locale- świadomy if oddział w funkcji setencoding w swoim module site poprzez locale. Ten plik zwykle znajduje się w /usr/lib/python2.x, warto go jednak sprawdzić. AFAIK, locale-aware setencoding jest domyślnie wyłączony (jest to prawda dla mojej instalacji Pythona 2.6).

Do wyboru są:

  • Niech figura System się na właściwej drodze do kodowania ciągów Unicode do bajtów lub zrobić to w kodzie (jakiś konfiguracji w miejscu specyficznym site.py jest potrzebne)
  • Kodowanie Unicode ciągi w kodzie i wyprowadzają tylko bajty

Zobacz także The Illusive setdefaultencoding autorstwa Iana Bickinga i powiązanych linków.

21

Mając kod jak:

raise Exception(u'щ') 

Spowodowany:

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) 

Dzieje się tak dlatego, że ciąg formatu jest ciąg bajtów, podczas gdy niektóre z argumentów format string jest Unicode ciągi ze znaków spoza ASCII :

>>> "%(message)s" % {'message': Exception(u'\u0449')} 
*** UnicodeEncodeError: 'ascii' codec can't encode character u'\u0449' in position 0: ordinal not in range(128) 

Tworzenie ciągu znaków w formacie Unicode rozwiązuje problem:

>>> u"%(message)s" % {'message': Exception(u'\u0449')} 
u'\u0449' 

Tak, w konfiguracji rejestrowania zrobić wszystko Unicode format string:

'formatters': { 
    'simple': { 
     'format': u'%(asctime)-s %(levelname)s [%(name)s]: %(message)s', 
     'datefmt': '%Y-%m-%d %H:%M:%S', 
    }, 
... 

I załatać Wartość domyślna logging formatowania używać formatu Unicode ciąg:

logging._defaultFormatter = logging.Formatter(u"%(message)s") 
+1

Co z Pythonem 3.5? Czy nie wszystkie ciągi powinny być domyślnie Unicode? –

+0

@JanuszSkonieczny czy masz ten sam problem z Pythonem 3 – warvariuc

+0

Tak, zrobiłem to w pojemniku dokera. Rozwiązałem go, ustawiając kilka zmiennych env związanych z kodowaniem os. Dla każdego potykającego się z tym samym problemem zobacz http://stackoverflow.com/a/27931669/260480. –