UTF-8 En el registro de Python, ¿cómo?
logging unicode (4)
Estoy intentando registrar una cadena codificada en UTF-8 en un archivo usando el paquete de registro de Python. Como un ejemplo de juguete:
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()
Esto explota con UnicodeDecodeError en la llamada logging.info ().
En un nivel inferior, el paquete de registro de Python está utilizando el paquete de códecs para abrir el archivo de registro, pasando el argumento "UTF-8" como la codificación. Eso está muy bien, pero está tratando de escribir cadenas de bytes en el archivo en lugar de objetos Unicode, que explotan. Básicamente, Python está haciendo esto:
file_handler.write(unicode_string.encode("UTF-8"))
Cuando debería estar haciendo esto:
file_handler.write(unicode_string)
¿Es esto un error en Python, o estoy tomando píldoras locas? FWIW, esta es una instalación stock de Python 2.6.
Comprueba que tienes la versión más reciente de Python 2.6: algunos errores Unicode fueron encontrados y reparados desde que salió 2.6. Por ejemplo, en mi sistema Ubuntu Jaunty, ejecuté su secuencia de comandos copiada y pegada, eliminando solo el prefijo ''/ home / ted /'' del nombre del archivo de registro. Resultado (copiado y pegado desde una ventana de terminal):
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$
En un cuadro de Windows:
C:/temp>python --version Python 2.6.2 C:/temp>python utest.py printed unicode object: ô
Y el contenido del archivo:
Esto también podría explicar por qué Lennart Regebro tampoco pudo reproducirlo.
Prueba esto:
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()
Por lo que vale, esperaba tener que usar codecs.open para abrir el archivo con codificación utf-8, pero o bien es el valor predeterminado o bien está sucediendo algo más, ya que funciona así.
Si entendí su problema correctamente, debería surgir el mismo problema en su sistema cuando simplemente lo hace:
str(u''ô'')
Supongo que la codificación automática de la codificación de la configuración regional en Unix no funcionará hasta que haya habilitado el setencoding
configuración regional if
setencoding
en la función de setencoding
en el módulo del site
través de la locale
. Este archivo generalmente reside en /usr/lib/python2.x
, vale la pena inspeccionarlo de todos modos. AFAIK, setencoding
sensible a la configuración regional está deshabilitado de forma predeterminada (es cierto para mi instalación de Python 2.6).
Las opciones son:
- Deje que el sistema encuentre la forma correcta de codificar cadenas Unicode en bytes o hágalo en su código (se necesita alguna configuración en el sitio
site.py
específico) - Codifique cadenas Unicode en su código y genere solo bytes
Ver también The Illusive setdefaultencoding por Ian Bicking y enlaces relacionados.
Tener código como:
raise Exception(u''щ'')
Causado
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)
Esto sucede porque la cadena de formato es una cadena de bytes, mientras que algunos de los argumentos de cadena de formato son cadenas unicode con caracteres que no son ASCII:
>>> "%(message)s" % {''message'': Exception(u''/u0449'')}
*** UnicodeEncodeError: ''ascii'' codec can''t encode character u''/u0449'' in position 0: ordinal not in range(128)
Hacer el formato de cadena unicode soluciona el problema:
>>> u"%(message)s" % {''message'': Exception(u''/u0449'')}
u''/u0449''
Entonces, en su configuración de registro, haga que toda cadena de formato sea unicode:
''formatters'': {
''simple'': {
''format'': u''%(asctime)-s %(levelname)s [%(name)s]: %(message)s'',
''datefmt'': ''%Y-%m-%d %H:%M:%S'',
},
...
Y parchee el formateador de logging
predeterminado para usar una cadena de formato unicode:
logging._defaultFormatter = logging.Formatter(u"%(message)s")