Logging-Modul hat Probleme mit Unicode

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

Moin,

mach ich da was falsch?

Code: Alles auswählen

import logging
from logging.handlers import SysLogHandler, SYSLOG_UDP_PORT

LOG = logging.getLogger("Test")

def setup_logging():
    '''Setup for the LOG object.'''
    facility = SysLogHandler.LOG_MAIL
    address = ('localhost', SYSLOG_UDP_PORT)
    logHandler = SysLogHandler(address=address, facility=facility)
    msgFormat = "%(name)s:%(levelname)s %(module)s:%(lineno)d: %(message)s"
    fmt = logging.Formatter(msgFormat)
    logHandler.setFormatter(fmt)
    logging.root.addHandler(logHandler)
    priority = SysLogHandler.LOG_INFO
    logging.root.setLevel(priority)

setup_logging()
LOG.info(u"Hallö")
Hier bekomm ich folgende Ausgabe in der Konsole:

Code: Alles auswählen

Traceback (most recent call last):
  File "logging/handlers.py", line 641, in emit
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 33: ordinal not in range(128)
Traceback (most recent call last):
  File "logging/handlers.py", line 641, in emit
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 33: ordinal not in range(128)
Traceback (most recent call last):
  File "logging/handlers.py", line 641, in emit
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 33: ordinal not in range(128)
Traceback (most recent call last):
  File "logging/handlers.py", line 646, in emit
TypeError: sendto() takes exactly 3 arguments (2 given)
Scheint so, als hätte das logging-Modul Probleme, wenn ich Unicode verwende. In der Doku habe ich nichts gefunden, was Unicode verbieten würde.

Gruß,
Manuel
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

Konnte ich jetzt so nicht nachvollziehen. Hab deinen Code aber etwas abgewandelt (bzw. schnell aus einem meiner Programme kopiert), weil der so ohne weiteres nicht bei mir lief. Bei der Konfiguration des Logging-Moduls ist jetzt aber nichts dabei, was mit Unicode zu tun hat. Wichtig dürfte hingegen die zweite Zeile sein. Die müßtest du dann mit dem für dein System richtigen / von deinem Editor verwendeten Wert versehen.

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf-8 

import logging
import time

def setup_logging():
    '''Setup for the LOG object.'''
    logging.basicConfig(level=logging.DEBUG,
            format='%(levelname)-8s %(message)s',
            filename='log',
            filemode='a')
    logging.info("====== Programm gestartet am %s ======" % (time.ctime()))

    console = logging.StreamHandler()
    console.setLevel(logging.WARNING)
    formatter = logging.Formatter('%(message)s')
    console.setFormatter(formatter)
    logging.getLogger("").addHandler(console)

setup_logging()
logging.info(u"Hallö")
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

Das coding-Tag ist richtig gesetzt. Hat im Original mit dem auch nichts zu tun. Da hab ich nur mit Unicode-Objekten zu tun - da gibt's keine Umlaute im Quellcode.

Dein Beispiel funktioniert bei mir auch. Der Unterschied wird wohl im SysLogHandler liegen. Der oben genannte Fehler tritt auf, wenn auf via UDP auf localhost:514 zugreife (wie im Beispiel). Wenn ich als address aber "/dev/log" angebe, bekomme ich nur einen UnicodeEncodeError, aber keinen TypeError.

Der SysLogHandler versucht das Unicode-Objekt in Ascii zu kodieren. Dabei kommt es zum EncodeError, wenn ich z.B. Umlaute drin hab. Die Frage ist, warum Ascii? Das System, in dem das ganze rennt, ist ISO-8859-1. :?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Weil ASCII das Standard-Encoding in Python 2.x ist, wenn der Interpreter nicht weiss was er fuer ein Encoding nehmen koennte.
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

Das ist mir auch eingefallen. Dumm nur, dass ich für den SysLogHandler nirgens ein Encoding angeben kann. Bei ein paar anderen Handlern kann ich das. Da werd ich das ganze wohl wrappen müssen.
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

So, noch einmal mit exakt deinem Code probiert: Ich bekomme nur das hier:

Code: Alles auswählen

Traceback (most recent call last):
  File "/usr/lib/python2.5/logging/handlers.py", line 672, in emit
    self.socket.sendto(msg, self.address)
TypeError: sendto() takes exactly 3 arguments (2 given)
Den Schnippsel sieht man ja auch bei dir. Meine Idee ist Folgende: Es tritt irgendwo ein Fehler auf (Unicode). Dann versucht der Handler das zu loggen und stößt auf den obigen Fehler.

Fehlt vielleicht irgendwo noch eine Einstellung? Oder ein 'self'? Eventuell auch ein Bug in Logging? Für mich sieht das nicht nach einem Unicode-Problem aus.

Edit: Ok, sehe gerade daß die anderen Fehler auch in handler.py auftreten. Komisch ist halt, daß nach dem Unicode-Fehler noch ein anderer Fehler auftritt.
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

Den Fehler kann man reproduzieren, indem man folgendes macht:

Code: Alles auswählen

import socket
my_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
my_socket.sendto(1, ("localhost", 514))
Wenn der sendto-Methode als erstes Argument kein String gegeben wird, dann meckert er auch rum, von wegen nicht genug Argumente und so.

Schaut man in den C-Code des socket-Moduls, dann wird versucht, zuerst zwei Argumente zu parsen und wenn das nicht geht, drei. Und wenn das schief geht, dann sagt er einfach, er würde drei brauchen. IMO ist die Fehlermeldung hier nicht korrekt.

Code: Alles auswählen

static PyObject *
sock_sendto(PySocketSockObject *s, PyObject *args)
{
        PyObject *addro;
        char *buf;
        sock_addr_t addrbuf;
        int addrlen, len, n = -1, flags, timeout;

        flags = 0;
        if (!PyArg_ParseTuple(args, "s#O:sendto", &buf, &len, &addro)) {
                PyErr_Clear();
                if (!PyArg_ParseTuple(args, "s#iO:sendto",
                                      &buf, &len, &flags, &addro))
                        return NULL;
        }
...
Übergibt man in Python der sendto-Methode einen Integer (wie oben), dann schlägt das Parsen der (zwei) Argumente in C fehl, es wird versucht, drei Argumente zu parsen, auch das schlägt fehlt, dann gibt's die Fehlermeldung.

Übergibt man ein Unicode-Objekt funktioniert alles wunderbar - außer es enthält Nicht-ASCII-Zeichen. Weil das Unicode-Objekt nicht in einen ASCII-String umgewandelt werden kann, wird der C-Funktion "irgendwas" übergeben, das er nicht als String parsen kann: Bumm.

Ich denke, ich werde mal einen Bug-Report schreiben.
Antworten