logging objecte und try..except

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
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Hallö,

Code: Alles auswählen

try:
       fil = file(loadfile, "rb")
except IOError:
       logger.error("Regular FILE %s not found." % str(loadfile))
       logger.shutdown()
       raise RegularFileNotFoundException("Regular FILE %s not found." % str(loadfile))
logger ist ein lokales modul, das nichts weiter macht als das logging modul sternchen-zu-importieren und dann nur die baseConfig zu setzen, damit ich das in reinen Klassenmodulen nicht machen muss, also nur eine Übergangslösung bis die Klassenlogik einigermaßen steht.

Will ich nun dazu passende unittests schreiben, die auf self.assertsRaises RegularFileNotFoundException überprüfen und ggf. meinen logger dort miteinbeziehen, bekomme ich zb sowas:
UniSInit.getName should give an RegularFileNotFound Exception ... ok
UniSInit.getName should return an random choosen Name ... Traceback (most recent call last):
File "/usr/lib/python2.5/logging/__init__.py", line 750, in emit
self.stream.write(fs % msg)
ValueError: I/O operation on closed file
ok

----------------------------------------------------------------------
Ran 2 tests in 0.003s

OK
Sieht unschön aus, und ist im Grunde auch relativ harmlos sofern ich nicht mit dem logfile arbeiten will, würd ich aber dennoch gerne loswerden... Nur liegt das am explizit aufgerufenen logger.shutdown(), was ja das logging aquivalent zu file.close() sein dürfte...

thx schonmal & cu
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

sry für den doppelpost:

inzwischen bin ich auf die idee gekommen, je nachdem ob das skript produktiv oder im unittest durchlaufen wird, eine fakeshutdown oder eine richtige shutdown auszuführen. di fakeshutdown hab ich schon und macht nichts weiter als ein logging.<filehandler instance>.flush(), allerdings müßt ich da nur noch ne bedingung drankleben.

Es gibt nicht zufällig eine schöne Variable im __name__ style, die mir alle importierten module eines skripts anzeigt, und ich das eben aus einem importiertem module heraus überprüfen kann..? Hätte ausserdem den schönen Nebeneffekt, das ich das Teil je nach Gebrauch öfter nutzen könnt.
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

http://paste.pocoo.org/show/60211/

hab jetzt das modul etwas angepasst, inzwischen bekomm ich den Error (ausser bei einem sehr eigenartigem Fall) nicht mehr.. ist zwar etwas unschön und das schreiben funktioniert auch noch nicht, wird aber wohl erstmal gehen.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Code: Alles auswählen

def critical(self, msg, *args, **kwargs):
        """Own critical implementation. Gets called if an error occurs, extra checking if an logger's handler is closed."""

        if self.handlers[0].stream.closed:
            logging.Handler.__init__(self.handlers[0], logging.DEBUG)
            self.handlers[0].stream = open(self.handlers[0].stream.name, self.handlers[0].stream.mode)

            logging.Logger.critical(self, msg, *args, **kwargs)
        else:
            logging.Logger.critical(self, msg, *args, **kwargs)
kannst du aber kürzer schreiben:

Code: Alles auswählen

def critical(self, msg, *args, **kwargs):
        """Own critical implementation. Gets called if an error occurs, extra checking if an logger's handler is closed."""
        handler = self.handlers[0]
        stream = handler.stream
        if stream.closed:
            logging.Handler.__init__(handler, logging.DEBUG)
            handler.stream = open(stream.name, stream.mode)
        logging.Logger.critical(self, msg, *args, **kwargs)
Das gleiche gilt für die error-Methode.

Und wenn du schon von einer Klasse erbst, dann brauchst du die Methoden, die die Basisklasse mit den selben Argumenten noch mal aufrufen nicht hinschreiben.
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Meine 2 Cent: Ich unterscheide zwischen Testläufen zum Debuggen und den unittest-Läufen. Also lasse ich unittest das verbosity level auf logging.ERROR setzten und der unittest läuft leise durch.

Gruß,
Christian
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

@EyDu:

Stimmt, die methoden waren aber drinne weil ich ursprünglich das anders umsetzen wollte und sie dann nach dem umentschied einfach nicht entfernt habe ^_^

Ich habe die Version jetzt nochmal komplett verändert:

http://paste.pocoo.org/show/60802/

Diese Version hat den Vorteil, das sie solang alles in ordnung läuft ganz normal logt und bei einem richtigem, normalen shutdown anhand des all parameters/(arguments?) entscheidet, ob alles abzuschalten ist. Taucht ein Fehler auf, wird beim ersten mal nur der normale logger bemüht und direkt danach geschlossen, dadurch sind die daten sicher und das logger objekt wird korrekt geschlossen. Tauchen mehrere errors danach noch auf, wird der Error Handler benutzt und ich verliere so keine Nachricht, und kann mir sicher sein, das dieser am ende sowieso per shutdown(True) geschlossen wird.

Nur beim normalen exit wird der Errorlogger nicht geschlossen, was jedoch kein problem darstellen sollte, da er sowieso nicht gebraucht wurde und das date objekt nun nicht so dringend explizit zu schliessen ist, korrigiert mich, sollte ich mich da irren.

Ansonsten sollte das so passen :D

PS: das l oder ll for filename usw steht für jeweils für local oder super duber ober doppel local, etwas unglücklich, aber da eh nur parameter übergeben werden die recht offensichtlich sind..
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Da geht aber noch was ;-)

Code: Alles auswählen

def critical(self, msg, errorroot=rooterror, *args, **kwargs):
    logging.Logger.critical([errorroot,self][self.blocked], msg, *args, **kwargs)
Geht auch wieder mit der error-Methode.

Und die restliche Codeverdopplungen bekommst du auch noch raus:

Code: Alles auswählen

def notblocked(func):
    def result(self, *args, **kwargs):
        if not self.blocked:
            func(self, *args, **kwargs)
    return result

class Logger(...):
    ...
    warning = notblocked(logging.Logger.warning)
    info = notblocked(logging.Logger.info)
    debug = notblocked(logging.Logger.debug)
Die ganzen Wrapper die du da unten hast, kannst du auch noch kürzer schreiben:

Code: Alles auswählen

critical = root.critical
error = root.error
...
Konstanten in Python schreibt man nach PEP8 übrigens vollständig in Großbuchstaben.
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Code: Alles auswählen

logging.Logger.critical([errorroot,self][self.blocked], msg, *args, **kwargs)
hm, diese Art der notation (sofern das keine listen sein sollen, wobei das unlogisch wäre?) ist mir nicht bekannt, hab in der python language ref auch beim kurzem überfliegen auch nichts zu gefunden

zu der funktion: sollte das nicht eher

Code: Alles auswählen

class Logger(etc):

    def notblocked(self, func, *args, **kwargs):
        def result(self, *args, **kwargs):
            func(self, *args, **kwargs)
        return result(self, *args, **kwargs)

    warning = notblocked(self, logging.Logger.warning, *args, **kwargs)
    etc
heissen? Ansonsten hat die funktion relativ wenig mit self zu tun und bekommt auch keine *args **kwargs argumente... oder?^^

Ach halt - Denkfehler, die function wird ja zurückgegeben per return result und nicht deren ausführung.. joa jetzt versteh ichs, ziemlich clevere Sache das :!:

stimmt, so könnt ich die wrapper natürlich auch umsetzen ^_^

joa, fühlte mich grad spontan an #define KONSTANTE wert aus c erinnert, Konstanten großschreiben sollt ich mir mal angewöhnen...[/code]
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

str1442 hat geschrieben:

Code: Alles auswählen

logging.Logger.critical([errorroot,self][self.blocked], msg, *args, **kwargs)
hm, diese Art der notation (sofern das keine listen sein sollen, wobei das unlogisch wäre?) ist mir nicht bekannt, hab in der python language ref auch beim kurzem überfliegen auch nichts zu gefunden
Die Notation kennst du mit Sicherheit. Du greifst auf das "self.blocked"-te Element in der Liste [errorroot, self] zu, wobei "False" einer 0 entspricht und "True" einer 1.
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Die Notation kennst du mit Sicherheit. Du greifst auf das "self.blocked"-te Element in der Liste [errorroot, self] zu, wobei "False" einer 0 entspricht und "True" einer 1.
achsö :oops: ... Das 1/0 True/False entspricht war ja klar, aber das das bei intenger-erwartenden objekten andersrum auch geht... :shock:

Danke für die Hilfe :)
Antworten