2011-09-07 9 views
11

Sono nuovo alla registrazione di Python e posso facilmente vedere come è preferibile la soluzione home-brew che mi è venuta in mente.Disabilita la registrazione per metodo/funzione?

Una domanda a cui non riesco a trovare una risposta: come faccio a silenziare i messaggi di log in base al metodo/funzione?

Il mio modulo ipotetico contiene una singola funzione. Come ho sviluppato, le chiamate di log sono di grande aiuto:

logging.basicConfig(level=logging.DEBUG, 
       format=('%(levelname)s: %(funcName)s(): %(message)s')) 
log = logging.getLogger() 

my_func1(): 
    stuff... 
    log.debug("Here's an interesting value: %r" % some_value) 
    log.info("Going great here!") 
    more stuff... 

Come avvolgo il mio lavoro su 'my_func1' e iniziare a lavorare su una seconda funzione, 'my_func2', i messaggi di registrazione da 'my_func1' cominciare ad andare da "utile" a "ingombro".

C'è un'istruzione magica su una sola riga, come "logging.disabled_in_this_func()" che posso aggiungere all'inizio di "my_func1" per disabilitare tutte le chiamate di registrazione in "my_func1", ma lasciare comunque chiamate di registrazione in tutte altre funzioni/metodi invariati?

Grazie

Linux, Python 2.7.1

+0

Correlato: http://stackoverflow.com/questions/879732/logging-with-filters –

risposta

8

Il trucco è creare più logger.

Ci sono diversi aspetti a questo.

Primo. Non utilizzare logging.basicConfig() all'inizio di un modulo. Usalo solo all'interno l'interruttore principale-import

if __name__ == "__main__": 
    logging.basicConfig(...) 
    main() 
    logging.shutdown() 

Seconda. Non ottenere mai il logger "root", tranne per impostare le preferenze globali.

Terzo. Richiedi ai logger i singoli logger per le cose che potrebbero essere abilitate o disabilitate.

log = logging.getLogger(__name__) 

func1_log = logging.getLogger("{0}.{1}".format(__name__, "my_func1") 

Ora è possibile impostare i livelli di registrazione su ciascun logger denominato.

log.setLevel(logging.INFO) 
func1_log.setLevel(logging.ERROR) 
+0

Grazie per la raccomandazione su come inserire la configurazione di registrazione all'interno dell'interruttore di importazione principale. Buono a sapersi. L'uso del root logger non è raccomandato nemmeno per uno script a modulo singolo come sto lavorando ora? Potresti per favore chiarire i contro per farlo? –

+2

"non è consigliato l'uso del root logger". Periodo. Non usarlo È "anonimo". Vuoi solo logger nominati in modo da poter configurare e filtrare. –

+0

Per elaborare il messaggio chiaro di @ S.Lott: se aggiungi gestori al logger root, inizierai a ricevere messaggi da ** tutti ** altri pacchetti che usi, che possono diventare molto disordinati (ad esempio 'richieste'). E viceversa, quando un altro pacchetto utilizza il pacchetto, i messaggi del pacchetto non possono essere gestiti separatamente. Cattivo design – j08lue

2

Si potrebbe usare un decoratore:

import logging 
import functools 

def disable_logging(func): 
    @functools.wraps(func) 
    def wrapper(*args,**kwargs): 
     logging.disable(logging.DEBUG) 
     result = func(*args,**kwargs) 
     logging.disable(logging.NOTSET) 
     return result 
    return wrapper 

@disable_logging 
def my_func1(...): 
+0

Hah! Mi hai battuto in pochi secondi. Fai attenzione a 'wrapper' dato che non riattiverà la registrazione della chiamata' func() 'genera un'eccezione. Ecco perché uso la frase 'try/finally' per garantire che la registrazione sia riattivata indipendentemente dal fatto che' func() 'abbia successo. –

6

Si potrebbe creare un decoratore che sospendere temporaneamente la registrazione, ala:

from functools import wraps 

def suspendlogging(func): 
    @wraps(func) 
    def inner(*args, **kwargs): 
     previousloglevel = log.getEffectiveLevel() 
     try: 
      return func(*args, **kwargs) 
     finally: 
      log.setLevel(previousloglevel) 
    return inner 

@suspendlogging 
def my_func1(): ... 

Attenzione: che sospenderebbe anche la registrazione per qualsiasi funzione chiamata da my_func 1 quindi fai attenzione a come lo usi.

+0

Buon approccio per molte applicazioni. Grazie! –

+0

Immagino che questa dovrebbe essere stata la fabbrica dei decoratori che ha deciso di sospendere il logger. –

+0

Per favore correggimi se ho torto, ma mi sembra che questo disabiliterebbe solo un logger chiamato 'log'. Se ci sono diversi logger utilizzati contemporaneamente, ad esempio in un'applicazione Django, come può disabilitare tutti i logger? –

0

Mi ci è voluto un po 'di tempo per imparare come implementare i sub-logger come suggerito da S.Lott.

Dato quanto duro è stato quello di capire come impostare la registrazione quando ero agli inizi, Decido che è il lungo tempo passato a condividere quello che ho imparato da allora.

Si prega di tenere presente che questo non è l'unico modo per impostare logger/sub-logger, né è il migliore. È solo il modo in cui uso per portare a termine il lavoro per soddisfare le mie esigenze. Spero che questo sia utile a qualcuno. Non esitate a commentare/condividere/criticare.


Supponiamo di disporre di una semplice libreria che ci piace utilizzare. Dal programma principale, vorremmo essere in grado di controllare i messaggi di registrazione che riceviamo dalla libreria. Ovviamente siamo dei creatori di libri premurosi, quindi configuriamo la nostra libreria per renderla semplice.

In primo luogo, il programma principale:

# some_prog.py 

import os 
import sys 

# Be sure to give Vinay Sajip thanks for his creation of the logging module 
# and tireless efforts to answer our dumb questions about it. Thanks Vinay! 
import logging 

# This module will make understanding how Python logging works so much easier. 
# Also great for debugging why your logging setup isn't working. 
# Be sure to give it's creator Brandon Rhodes some love. Thanks Brandon! 
import logging_tree 

# Example library 
import some_lib 

# Directory, name of current module 
current_path, modulename = os.path.split(os.path.abspath(__file__)) 
modulename = modulename.split('.')[0] # Drop the '.py' 


# Set up a module-local logger 
# In this case, the logger will be named 'some_prog' 
log = logging.getLogger(modulename) 

# Add a Handler. The Handler tells the logger *where* to send the logging 
# messages. We'll set up a simple handler that send the log messages 
# to standard output (stdout) 
stdout_handler = logging.StreamHandler(stream=sys.stdout) 
log.addHandler(stdout_handler) 


def some_local_func(): 
    log.info("Info: some_local_func()") 
    log.debug("Debug: some_local_func()") 


if __name__ == "__main__": 

    # Our main program, here's where we tie together/enable the logging infra 
    # we've added everywhere else. 

    # Use logging_tree.printout() to see what the default log levels 
    # are on our loggers. Make logging_tree.printout() calls at any place in 
    # the code to see how the loggers are configured at any time. 
    # 
    # logging_tree.printout() 

    print("# Logging level set to default (i.e. 'WARNING').") 
    some_local_func() 
    some_lib.some_lib_func() 
    some_lib.some_special_func() 

    # We know a reference to our local logger, so we can set/change its logging 
    # level directly. Let's set it to INFO: 
    log.setLevel(logging.INFO) 
    print("# Local logging set to 'INFO'.") 
    some_local_func() 
    some_lib.some_lib_func() 
    some_lib.some_special_func() 


    # Next, set the local logging level to DEBUG: 
    log.setLevel(logging.DEBUG) 
    print("# Local logging set to 'DEBUG'.") 
    some_local_func() 
    some_lib.some_lib_func() 
    some_lib.some_special_func() 


    # Set the library's logging level to DEBUG. We don't necessarily 
    # have a reference to the library's logger, but we can use 
    # logging_tree.printout() to see the name and then call logging.getLogger() 
    # to create a local reference. Alternately, we could dig through the 
    # library code. 
    lib_logger_ref = logging.getLogger("some_lib") 
    lib_logger_ref.setLevel(logging.DEBUG) 

    # The library logger's default handler, NullHandler() won't output anything. 
    # We'll need to add a handler so we can see the output -- in this case we'll 
    # also send it to stdout. 
    lib_log_handler = logging.StreamHandler(stream=sys.stdout) 
    lib_logger_ref.addHandler(lib_log_handler) 
    lib_logger_ref.setLevel(logging.DEBUG) 

    print("# Logging level set to DEBUG in both local program and library.") 
    some_local_func() 
    some_lib.some_lib_func() 
    some_lib.some_special_func() 


    print("# ACK! Setting the library's logging level to DEBUG output") 
    print("# all debug messages from the library. (Use logging_tree.printout()") 
    print("# To see why.)") 
    print("# Let's change the library's logging level to INFO and") 
    print("# only some_special_func()'s level to DEBUG so we only see") 
    print("# debug message from some_special_func()") 

    # Raise the logging level of the libary and lower the logging level 
    # of 'some_special_func()' so we see only some_special_func()'s 
    # debugging-level messages. 
    # Since it is a sub-logger of the library's main logger, we don't need 
    # to create another handler, it will use the handler that belongs 
    # to the library's main logger. 
    lib_logger_ref.setLevel(logging.INFO) 
    special_func_sub_logger_ref = logging.getLogger('some_lib.some_special_func') 
    special_func_sub_logger_ref.setLevel(logging.DEBUG) 

    print("# Logging level set to DEBUG in local program, INFO in library and") 
    print("# DEBUG in some_lib.some_special_func()") 
    some_local_func() 
    some_lib.some_lib_func() 
    some_lib.some_special_func() 

Avanti, la nostra biblioteca:

# some_lib.py 

import os 
import logging 

# Directory, name of current module 
current_path, modulename = os.path.split(os.path.abspath(__file__)) 
modulename = modulename.split('.')[0] # Drop the '.py' 

# Set up a module-local logger. In this case the logger will be 
# named 'some_lib' 
log = logging.getLogger(modulename) 

# In libraries, always default to NullHandler so you don't get 
# "No handler for X" messages. 
# Let your library callers set up handlers and set logging levels 
# in their main program so the main program can decide what level 
# of messages they want to see from your library. 
log.addHandler(logging.NullHandler()) 

def some_lib_func(): 
    log.info("Info: some_lib.some_lib_func()") 
    log.debug("Debug: some_lib.some_lib_func()") 

def some_special_func(): 
    """ 
    This func is special (not really). It just has a function/method-local 
    logger in addition to the library/module-level logger. 
    This allows us to create/control logging messages down to the 
    function/method level. 

    """ 
    # Our function/method-local logger 
    func_log = logging.getLogger('%s.some_special_func' % modulename) 

    # Using the module-level logger 
    log.info("Info: some_special_func()") 

    # Using the function/method-level logger, which can be controlled separately 
    # from both the library-level logger and the main program's logger. 
    func_log.debug("Debug: some_special_func(): This message can be controlled at the function/method level.") 

Ora cerchiamo di eseguire il programma, insieme con la traccia di commento:

# Logging level set to default (i.e. 'WARNING'). 

Avviso c'è nessun output al livello predefinito poiché non abbiamo generato alcun messaggio a livello di WARNING.

# Local logging set to 'INFO'. 
Info: some_local_func() 

gestori del libreria predefinita per NullHandler(), così vediamo solo l'uscita dal programma principale. Questo è buono.

# Local logging set to 'DEBUG'. 
Info: some_local_func() 
Debug: some_local_func() 

Il programma di registrazione principale è impostato su DEBUG. Non vediamo ancora output dalla libreria. Questo è buono.

# Logging level set to DEBUG in both local program and library. 
Info: some_local_func() 
Debug: some_local_func() 
Info: some_lib.some_lib_func() 
Debug: some_lib.some_lib_func() 
Info: some_special_func() 
Debug: some_special_func(): This message can be controlled at the function/method level. 

Oops.

# ACK! Setting the library's logging level to DEBUG output 
# all debug messages from the library. (Use logging_tree.printout() 
# To see why.) 
# Let's change the library's logging level to INFO and 
# only some_special_func()'s level to DEBUG so we only see 
# debug message from some_special_func() 
# Logging level set to DEBUG in local program, INFO in library and 
# DEBUG in some_lib.some_special_func() 
Info: some_local_func() 
Debug: some_local_func() 
Info: some_lib.some_lib_func() 
Info: some_special_func() 
Debug: some_special_func(): This message can be controlled at the function/method level. 

E 'anche possibile ottenere solo messaggi di debug solo da some_special_func(). Usa logging_tree.printout() per capire quali livelli di registrazione modificare per far si che ciò accada!

Problemi correlati