TaskPython: personalizzato di registrazione in tutti i moduli
Ho una collezione di script e mi piacerebbe loro di produrre messaggi di log unificati con alterazioni minime a moduli che fanno registrare i messaggi attuali.
Ho scritto un piccolo modulo 'custom_logger' che ho intenzione di chiamare dall'applicazione principale una volta, restituire un logger, che quindi continuerei a utilizzare.
I sottomoduli sarei importando in app devono solo (o meglio li augurare)
- dovrebbe solo "la registrazione di importazione come log" - in modo che nulla di specifico per il mio sito è tenuto a li eseguono solo se qualcun altro li trova utili.
- dovrebbe solo registrare i messaggi con log.info/error('message ') senza aggiungere nulla di specifico al sito
- deve utilizzare il logger "root" già configurato con tutte le sue formattazioni e handler e non influisce sul logger del root configurazione
* * custom_logger.py
import logging
import logging.handlers
import os
import sys
def getLogger(name='root', loglevel='INFO'):
logger = logging.getLogger(name)
# if logger 'name' already exists, return it to avoid logging duplicate
# messages by attaching multiple handlers of the same type
if logger.handlers:
return logger
# if logger 'name' does not already exist, create it and attach handlers
else:
# set logLevel to loglevel or to INFO if requested level is incorrect
loglevel = getattr(logging, loglevel.upper(), logging.INFO)
logger.setLevel(loglevel)
fmt = '%(asctime)s %(filename)-18s %(levelname)-8s: %(message)s'
fmt_date = '%Y-%m-%dT%T%Z'
formatter = logging.Formatter(fmt, fmt_date)
handler = logging.StreamHandler()
handler.setFormatter(formatter)
logger.addHandler(handler)
if logger.name == 'root':
logger.warning('Running: %s %s',
os.path.basename(sys.argv[0]),
' '.join(sys.argv[1:]))
return logger
Poi viene il modulo che ha un paio di messaggi di prova con esempi di cosa funziona e cosa no.
submodule.py
import sys
import custom_logger
import logging
class SubClass(object):
def __init__(self):
# NOK (no idea why since by default (no name parameter), it should return the root logger)
#log = logging.getLogger()
#log.info('message from SubClass/__init__')
# OK (works as expected)
#log = logging.getLogger('root')
#log.info('message from SubClass/__init__')
# OK (works as expected)
log = custom_logger.getLogger('root')
log.info('message from SubClass/__init__')
def SomeMethod(self):
# OK but I'd have to define `log` for every method, which is unacceptable
# Please see question below all code snippets
log = custom_logger.getLogger('root')
log.info('message from SubClass/SomeMethod')
E l'applicazione principale: app.py Niente di speciale qui:
#!/usr/bin/python
import custom_logger
import submodule
log = custom_logger.getLogger('root', loglevel='DEBUG')
log.debug('debug message')
log.info('info message')
log.warning('warning message')
log.error('error message')
a = submodule.SubClass() # this should produce a log message
a.SomeMethod() # so should this
uscita che sto cercando e che sto ricevendo, solo in un modo terribilmente brutto:
% ./app.py
2013-04-08T03:07:46BST custom_logger.py WARNING : Running: app.py
2013-04-08T03:07:46BST app.py DEBUG : debug message
2013-04-08T03:07:46BST app.py INFO : info message
2013-04-08T03:07:46BST app.py WARNING : warning message
2013-04-08T03:07:46BST app.py ERROR : error message
2013-04-08T03:07:46BST submodule.py INFO : message from SubClass/__init__
2013-04-08T03:07:46BST submodule.py INFO : message from SubClass/SomeMethod
Desidero essere in grado di definire un logger in app.py e quindi nei sottomoduli utilizzare solo la libreria di registrazione Python standard per utilizzare un logger già configurato nell'app.py.
Inoltre, una brutta soluzione: se metto il codice qui sotto dopo le importazioni in submodule.py:
log = custom_logger.getLogger('root')
verrà eseguito prima del mio registratore è configurato in app.py, di fatto rendendo il modulo, non è la mia app a configurare la registrazione.
Un'altra soluzione ho considerato: all'interno del constuctor della classe SubClass, potrei definire
self.log = custom_logger.getLogger('root')
e poi usare self.log.error ('un errore'). Ci deve essere un modo più carino - se puoi suggerire qualcosa di utile o indicare dove ho frainteso la documentazione, sarei molto grato!
PS. Ho passato un bel po 'di tempo a leggere il log di Python howto (base e avanzato) e il ricettario, quindi se mi sono perso qualcosa di utile lì, per favore segnalalo.
Grazie!
Grazie Mihai. Pensavo di avere più tempo per esaminarlo, ma dovrò aspettare il weekend. Finora sono stato in grado di far funzionare la mia classe che fa tutto (allegando formattatori, gestori e impostazione di loglevel) definendo il log come oggetto getLogger nel submodule.py. Speravo che ciò potesse essere fatto senza mettere le cose al di fuori della definizione della classe. La mia domanda era più di "perché alcuni approcci che ho fatto non funzionavano come previsto, come mi piacerebbe capire il motivo dietro di esso, al contrario di ottenere un codice consegnato a me, ma apprezzo il tuo aiuto: –
Ho aggiornato la mia risposta.Altre quindi che è possibile esaminare il codice del modulo.Possibile vedere che il logger root è istanziato durante l'importazione.Non capisco davvero perché getLogger ("root") non funzioni lo stesso in tutte le situazioni (puoi fare getLogger() in app.py e getLogger ("root") in submodule.py e ottieni ciò che ti serve, ma non viceversa). – Mihai
Come farlo funzionare con il reindirizzamento stdout al file es. python ./app.py >> file.log? –