2013-07-16 2 views
33

Lassen Sie uns sagen, dass ich den folgenden Code haben:Was ist der Punkt von setLevel in einem Python-Logging-Handler?

import logging 
import logging.handlers 

a = logging.getLogger('myapp') 
h = logging.handlers.RotatingFileHandler('foo.log') 
h.setLevel(logging.DEBUG) 
a.addHandler(h) 

# The effective log level is still logging.WARN 
print a.getEffectiveLevel() 
a.debug('foo message') 
a.warn('warning message') 

Ich erwarte, dass logging.DEBUG auf der Handler einstellen würde bewirken, dass Debug-Level-Nachrichten in die Protokolldatei geschrieben werden. Dies druckt jedoch 30 für die effektive Ebene (logging.WARNING, die Standardeinstellung) und protokolliert nur die Nachricht in der Protokolldatei, nicht die Debug-Nachricht.

Es scheint, dass der Loglevel des Handlers auf den Boden fällt, z. es wird still ignoriert. Was mich wundern lässt, warum haben setLevel überhaupt auf dem Handler?

+0

Gute Frage, aber aus Gründen der Kohärenz, wenn Sie testen 'a.getEffectiveLevel',' a.setLevel' macht mehr Sinn als 'h.setLevel'. –

+0

In diesem Fall hat der Handler keinen 'getEffectiveLevel'-Befehl. –

Antwort

34

Es ermöglicht eine feinere Kontrolle. Standardmäßig hat der Root-Logger WARNING level gesetzt, dh es werden keine Nachrichten mit niedrigerer Ebene gedruckt (egal wie die Level der Handler eingestellt sind!). Aber, wenn Sie das Root-Logger Niveau DEBUG gesetzt, in der Tat erhalten die Nachricht an die Protokolldatei gesendet:

import logging 
import logging.handlers 

a = logging.getLogger('myapp') 
a.setLevel(logging.DEBUG) # set root's level 
h = logging.handlers.RotatingFileHandler('foo.log') 
h.setLevel(logging.DEBUG) 
a.addHandler(h) 
print a.getEffectiveLevel() 
a.debug('foo message') 
a.warn('warning message') 

Jetzt Bild, das Sie einen neuen Handler hinzufügen möchten, die nicht Debug-Informationen nicht aufzeichnen. Sie können dies tun, indem Sie einfach den Handler Protokollebene einstellen:

import logging 
import logging.handlers 

a = logging.getLogger('myapp') 
a.setLevel(logging.DEBUG) # set root's level 

h = logging.handlers.RotatingFileHandler('foo.log') 
h.setLevel(logging.DEBUG) 
a.addHandler(h) 

h2 = logging.handlers.RotatingFileHandler('foo2.log') 
h2.setLevel(logging.WARNING) 
a.addHandler(h2) 

print a.getEffectiveLevel() 
a.debug('foo message') 
a.warn('warning message') 

Nun wird die Protokolldatei foo.log werden beide Nachrichten enthalten, während die Datei foo2.log nur die Warnmeldung enthalten wird. Sie könnten daran interessiert sein, eine Protokolldatei mit Fehlernachrichten zu haben, fügen Sie einfach eine Handler hinzu und setzen Sie die Ebene auf logging.ERROR, alles unter Verwendung desselben Logger.

Sie können sich die Protokollierungsstufe Logger als globale Einschränkung vorstellen, bei der Nachrichten für einen bestimmten Logger und seine Handler "interessant" sind. Die Meldungen, die vom Logger anschließend berücksichtigt werden, werden an die Handler gesendet, die ihren eigenen Filter- und Protokollierungsprozess durchführen.

+3

So empfiehlt es sich, eine niedrigere Stufe des Root-Loggers festzulegen und die Protokollierung über die Handler-Ebene zu steuern. Hab ich recht? – laike9m

+0

Es ist nicht "Best Practice", nur etwas anderes ist nutzlos. Wenn die Ebene des Handlers DEBUG ist, aber der Logger nur ERROR sendet, empfängt der Handler natürlich nur ERROR. – hmijail

14

Bei der Python-Protokollierung gibt es zwei verschiedene Konzepte: die Ebene, auf der sich der Logger anmeldet, und die Ebene, die der Handler tatsächlich aktiviert.

Wenn ein Anruf gemacht zu protokollieren, was im Grunde geschieht, ist:

if self.level <= loglevel: 
    for handler in self.handlers: 
     handler(loglevel, message) 

Während jeder dieses Handler ruft dann:

if self.level <= loglevel: 
    # do something spiffy with the log! 

Wenn Sie eine reale Welt mögen Demonstration von diesem können Sie Django's config settings betrachten. Ich werde den entsprechenden Code hier einfügen.

LOGGING = { 
    #snip 
    'handlers': { 
     'null': { 
      'level': 'DEBUG', 
      'class': 'logging.NullHandler', 
     }, 
     'console':{ 
      'level': 'DEBUG', 
      'class': 'logging.StreamHandler', 
      'formatter': 'simple' 
     }, 
     'mail_admins': { 
      'level': 'ERROR', 
      'class': 'django.utils.log.AdminEmailHandler', 
      'filters': ['special'] 
     } 
    }, 
    'loggers': { 
     #snip 
     'myproject.custom': { 
      # notice how there are two handlers here! 
      'handlers': ['console', 'mail_admins'], 
      'level': 'INFO', 
      'filters': ['special'] 
     } 
    } 
} 

also in der obigen Konfiguration, protokolliert nur getLogger('myproject.custom').info und oben wird für die Protokollierung verarbeitet bekommen. Wenn dies geschieht, gibt die Konsole alle Ergebnisse aus (sie gibt alles aus, weil sie auf DEBUG gesetzt ist), während der mail_admins Logger für alle s, FATAL s und CRITICAL s auftritt.

Ich nehme an, einige Code, die auch helfen könnte nicht Django ist:

import logging.handlers as hand 
import logging as logging 

# to make things easier, we'll name all of the logs by the levels 
fatal = logging.getLogger('fatal') 
warning = logging.getLogger('warning') 
info = logging.getLogger('info') 

fatal.setLevel(logging.FATAL) 
warning.setLevel(logging.WARNING) 
info.setLevel(logging.INFO)  

fileHandler = hand.RotatingFileHandler('rotating.log') 

# notice all three are re-using the same handler. 
fatal.addHandler(fileHandler) 
warning.addHandler(fileHandler) 
info.addHandler(fileHandler) 

# the handler should log everything except logging.NOTSET 
fileHandler.setLevel(logging.DEBUG) 

for logger in [fatal,warning,info]: 
    for level in ['debug','info','warning','error','fatal']: 
     method = getattr(logger,level) 
     method("Debug " + logger.name + " = " + level) 

# now, the handler will only do anything for *fatal* messages... 
fileHandler.setLevel(logging.FATAL) 

for logger in [fatal,warning,info]: 
    for level in ['debug','info','warning','error','fatal']: 
     method = getattr(logger,level) 
     method("Fatal " + logger.name + " = " + level) 

Das ergibt:

Debug fatal = fatal 
Debug warning = warning 
Debug warning = error 
Debug warning = fatal 
Debug info = info 
Debug info = warning 
Debug info = error 
Debug info = fatal 
Fatal fatal = fatal 
Fatal warning = fatal 
Fatal info = fatal 

Auch hier bemerken, wie info etwas bei info angemeldet, warning, error und fatal wenn der Log-Handler auf DEBUG eingestellt war, aber als der Handler auf FATAL gesetzt wurde, wurden plötzlich nur FATAL Nachrichten t o die Datei.

9

Handler repräsentieren verschiedene Zielgruppen für die Protokollierung von Ereignissen. Levels auf Handlern werden verwendet, um die Ausführlichkeit der Ausgabe zu steuern, die von einer bestimmten Zielgruppe gesehen wird, und handeln zusätzlich auf allen auf Loggern festgelegten Ebenen. Protokollebenen werden verwendet, um die Ausführlichkeit der Protokollierung von verschiedenen Teilen einer Anwendung oder Bibliothek zu steuern.

Siehe this diagram für weitere Informationen darüber, wie die Protokollierung von Ereignissen behandelt werden:

enter image description here

Verwandte Themen