Seite 1 von 1
logging objecte und try..except
Verfasst: Samstag 31. Mai 2008, 21:38
von str1442
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
Verfasst: Sonntag 1. Juni 2008, 14:31
von str1442
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.
Verfasst: Montag 2. Juni 2008, 21:11
von str1442
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.
Verfasst: Montag 2. Juni 2008, 22:12
von EyDu
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.
Verfasst: Dienstag 3. Juni 2008, 07:49
von CM
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
Verfasst: Dienstag 3. Juni 2008, 16:19
von str1442
@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
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..
Verfasst: Dienstag 3. Juni 2008, 16:35
von EyDu
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:
Konstanten in Python schreibt man nach PEP8 übrigens vollständig in Großbuchstaben.
Verfasst: Dienstag 3. Juni 2008, 17:21
von str1442
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]
Verfasst: Dienstag 3. Juni 2008, 19:41
von EyDu
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.
Verfasst: Dienstag 3. Juni 2008, 19:58
von str1442
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ö

... Das 1/0 True/False entspricht war ja klar, aber das das bei intenger-erwartenden objekten andersrum auch geht...
Danke für die Hilfe
