2009-10-21 18 views
83

Devo ancora trovare un modo per configurare la registrazione Python con Django di cui sono felice. I miei requisiti sono abbastanza semplici:Configurazione elegante della registrazione Python in Django

  • Diversi gestori di registro per i differenti eventi - cioè, voglio essere in grado di accedere ai file diversi
  • Facile accesso a logger nei miei moduli. Il modulo dovrebbe essere in grado di trovare il suo logger con un piccolo sforzo.
  • Dovrebbe essere facilmente applicabile ai moduli della riga di comando. Parti del sistema sono processi daemon o linea di comando autonomi. La registrazione dovrebbe essere facilmente utilizzabile con questi moduli.

La mia configurazione attuale consiste nell'utilizzare un file logging.conf e nel registro di installazione in ciascun modulo da cui registro. Non sembra giusto.

Avete una configurazione di registrazione che vi piace? Dettagli: come si configura la configurazione (si usa logging.conf o si configura nel codice), dove/quando si avviano i logger e in che modo si ottiene l'accesso ai moduli, ecc.

+1

È possibile trovare il seguente screencast utile: http://ericholscher.com/blog/2008/aug/29/screencast-2-logging-fun-and-profit/. Inoltre, un miglior supporto per l'accesso a Django è stato proposto da Simon Willison (vedi http://simonwillison.net/2009/Sep/28/ponies/). –

+0

@Dominic Rodger - È già possibile eseguire la registrazione flessibile di app in Django, la proposta di Simon principalmente per facilitare la registrazione negli interni di Django.C'è del lavoro in Python per aggiungere la configurazione basata sul dizionario alla registrazione Python, da cui Django potrebbe trarne beneficio. –

risposta

49

Il modo migliore che ho trovato finora è quello di inizializzare la configurazione della registrazione in settings.py - da nessun'altra parte. Puoi utilizzare un file di configurazione o farlo passo passo in modo programmatico: dipende solo dalle tue esigenze. La cosa fondamentale è che di solito aggiungo i gestori che voglio al logger root, usando i livelli e qualche volta loggando. Filtri per ottenere gli eventi che voglio nei file, console, syslogs appropriati ecc. Puoi ovviamente aggiungere gestori ad altri logger anche, ma non c'è comunemente bisogno di questo nella mia esperienza.

In ogni modulo, definisco un logger utilizzando

logger = logging.getLogger(__name__) 

e l'uso che per la registrazione di eventi nel modulo (e, se voglio differenziare ulteriormente) uso un registratore che è un figlio del logger creato sopra.

Se la mia applicazione sta per essere potenzialmente utilizzato in un sito che non configurare la registrazione in settings.py, definisco un NullHandler da qualche parte nel modo seguente:

#someutils.py 

class NullHandler(logging.Handler): 
    def emit(self, record): 
     pass 

null_handler = NullHandler() 

e assicurarsi che un'istanza di esso è aggiunto a tutti i logger creati nei moduli nelle mie app che utilizzano la registrazione. (Nota: NullHandler è già nel pacchetto di registrazione per Python 3.1, e sarà in Python 2.7.) Quindi:

logger = logging.getLogger(__name__) 
logger.addHandler(someutils.null_handler) 

Questo viene fatto per garantire che i moduli funzionano molto bene in un sito che non configurare la registrazione in settings.py, e che non si ottiene alcun fastidio "Non è possibile trovare gestori per i messaggi XYZ del logger" (che sono avvisi relativi alla registrazione potenzialmente errata).

Facendo in questo modo soddisfa le vostre esigenze dichiarati:

  • È possibile impostare diversi gestori di log relativi a eventi, come si fa attualmente.
  • Facile accesso ai logger nei moduli: utilizzare getLogger(__name__).
  • Facilmente applicabile ai moduli della riga di comando: importano anche settings.py.

Aggiornamento: Si noti che a partire dalla versione 1.3, Django ora incorpora support for logging.

+0

Questo non richiede che ogni modulo abbia un gestore definito nella configurazione (non è possibile usare un gestore per foo.bar)? Guarda la conversazione che abbiamo avuto anni fa su http://groups.google.com/group/comp.lang.python/browse_thread/thread/6a199393bcee6c1b/2ddf482a44bc4bb1 –

+1

@ andrew cooke: tu * puoi * usare un gestore per 'foo' per gestire gli eventi registrati su 'foo.bar'. Ri. quel thread - sia fileConfig che dictConfig ora hanno opzioni per impedire di disabilitare i vecchi logger. Vedi questo problema: http://bugs.python.org/issue3136, che è arrivato in un paio di mesi dopo il tuo problema http://bugs.python.org/issue2697 - in ogni caso, è stato risolto da giugno 2008. –

+0

wouldn è meglio fare 'logger = someutils.getLogger (__ name __)' dove 'someutils.getLogger' restituisce il logger da' logging.getLogger' con un gestore_destinato già aggiunto? – 7yl4r

6

Attualmente sto usando un sistema di registrazione, che ho creato da solo. Utilizza il formato CSV per la registrazione.

django-csvlog

Questo progetto non ha ancora la documentazione completa, ma sto lavorando su di esso.

6

Inizializziamo la registrazione nel livello superiore urls.py utilizzando un file logging.ini.

La posizione di logging.ini è fornita in settings.py, ma questo è tutto.

Ogni modulo poi fa

logger = logging.getLogger(__name__) 

Per distinguere i test, sviluppo e istanze di produzione, abbiamo diverse file logging.ini. Per la maggior parte, abbiamo un "log della console" che va solo a stderr con errori. Abbiamo un "registro delle applicazioni" che utilizza un normale file di registro progressivo che va a una directory dei registri.

+0

Ho finito per usare questo, tranne l'inizializzazione in settings.py invece di urls.py – Parand

+0

Come usi le impostazioni da settings.py nel file logging.ini? Ad esempio, ho bisogno dell'impostazione BASE_DIR, così posso dire dove conservare i miei file di registro. – slypete

+0

@slypete: non utilizziamo le impostazioni nel file logging.ini. Dal momento che la registrazione è ampiamente indipendente, non usiamo nessuna delle impostazioni di Django. Sì, c'è la possibilità di ripetere qualcosa. No, non fa molta differenza pratica. –

114

So che questa è già una risposta risolta, ma come per django> = 1.3 c'è una nuova impostazione di registrazione.

Lo spostamento dal vecchio al nuovo non è automatico, quindi ho pensato di scriverlo qui.

E naturalmente il check-out the django doc per altri ancora.

Questa è la conf base, creato da default con django-admin createproject v1.3 - chilometraggio potrebbe cambiare con le ultime versioni di Django:

LOGGING = { 
    'version': 1, 
    'disable_existing_loggers': False, 
    'handlers': { 
     'mail_admins': { 
      'level': 'ERROR', 
      'class': 'django.utils.log.AdminEmailHandler', 
     } 
    }, 
    'loggers': { 
     'django.request': { 
      'handlers': ['mail_admins'], 
      'level': 'ERROR', 
      'propagate': True, 
     } 
    } 
} 

Questa struttura si basa sullo standard Python logging dictConfig, che determina i seguenti blocchi:

  • formatters - il valore corrispondente sarà un dict in cui ogni tasto è un formattatore id e ogni valore è un dict descrive come configurare l'istanza di formattazione corrispondente.
  • filters - il valore corrispondente sarà un dict in cui ogni chiave è un id filtro e ogni valore è un dict che descrive come configurare l'istanza filtro corrispondente.
  • handlers - il valore corrispondente sarà un dict in cui ogni chiave è un id del gestore e ogni valore è un dict che descrive come configurare l'istanza dell'handler corrispondente. Ogni gestore ha i seguenti tasti:

    • class (obbligatorio). Questo è il nome completo della classe del gestore.
    • level (facoltativo). Il livello del conduttore.
    • formatter (facoltativo). L'id del formattatore per questo gestore.
    • filters (opzionale). Un elenco di ID dei filtri per questo gestore.

faccio di solito, almeno questo:

  • aggiungere un file di log
  • configurare le mie applicazioni di scrivere questo registro

che si traduce in:

LOGGING = { 
    'version': 1, 
    'disable_existing_loggers': False, 
    'formatters': { 
     'verbose': { 
      'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s' 
     }, 
     'simple': { 
      'format': '%(levelname)s %(message)s' 
     }, 
    }, 
    'filters': { 
     'require_debug_false': { 
      '()': 'django.utils.log.RequireDebugFalse' 
     } 
    }, 
    'handlers': { 
     'null': { 
      'level':'DEBUG', 
      'class':'django.utils.log.NullHandler', 
     }, 
     'console':{ 
      'level': 'DEBUG', 
      'class': 'logging.StreamHandler', 
      'formatter': 'simple' 
     }, 
     # I always add this handler to facilitate separating loggings 
     'log_file':{ 
      'level': 'DEBUG', 
      'class': 'logging.handlers.RotatingFileHandler', 
      'filename': os.path.join(VAR_ROOT, 'logs/django.log'), 
      'maxBytes': '16777216', # 16megabytes 
      'formatter': 'verbose' 
     }, 
     'mail_admins': { 
      'level': 'ERROR', 
      'filters': ['require_debug_false'], 
      'class': 'django.utils.log.AdminEmailHandler', 
      'include_html': True, 
     } 
    }, 
    'loggers': { 
     'django.request': { 
      'handlers': ['mail_admins'], 
      'level': 'ERROR', 
      'propagate': True, 
     }, 
     'apps': { # I keep all my of apps under 'apps' folder, but you can also add them one by one, and this depends on how your virtualenv/paths are set 
      'handlers': ['log_file'], 
      'level': 'INFO', 
      'propagate': True, 
     }, 
    }, 
    # you can also shortcut 'loggers' and just configure logging for EVERYTHING at once 
    'root': { 
     'handlers': ['console', 'mail_admins'], 
     'level': 'INFO' 
    }, 
} 

modificare

Vedi request exceptions are now always logged e Ticket #16288:

ho aggiornato il conf campione sopra per includere esplicitamente il filtro corretto per mail_admins in modo che, per impostazione predefinita, messaggi di posta elettronica non vengono inviati quando il debug è True.

Si dovrebbe aggiungere un filtro:

'filters': { 
    'require_debug_false': { 
     '()': 'django.utils.log.RequireDebugFalse' 
    } 
}, 

e applicarlo al gestore mail_admins:

'mail_admins': { 
     'level': 'ERROR', 
     'filters': ['require_debug_false'], 
     'class': 'django.utils.log.AdminEmailHandler', 
     'include_html': True, 
    } 

Altrimenti il ​​django.core.handers.base.handle_uncaught_exception non passa errori al logger 'django.request' se le impostazioni .DEBUG è vero.

Se non si esegue questa operazione in Django 1.5 si otterrà un DeprecationWarning

: Non ci sono filtri definiti sulla gestore registrazione dei 'mail_admins': aggiunta implicita filtrare debug-falso-only

ma le cose funzioneranno correttamente ENTRAMBE in django 1.4 e django 1.5.

** ** di modifica fine

Questo conf è fortemente ispirato dalla conf campione nel doc Django, ma aggiungendo la parte del file di registro.

spesso anche effettuare le seguenti operazioni:

LOG_LEVEL = 'DEBUG' if DEBUG else 'INFO' 

... 
    'level': LOG_LEVEL 
... 

Poi nel mio codice python ho sempre aggiungere un NullHandler nel caso in cui non conf registrazione è definito alcun tipo. Questo evita avvisi per nessun gestore specificato. Particolarmente utile per librerie che non sono necessariamente chiamato solo a Django (ref)

import logging 
# Get an instance of a logger 
logger = logging.getLogger(__name__) 
class NullHandler(logging.Handler): #exists in python 3.1 
    def emit(self, record): 
     pass 
nullhandler = logger.addHandler(NullHandler()) 

# here you can also add some local logger should you want: to stdout with streamhandler, or to a local file... 

[...]

logger.warning('etc.etc.') 

Spero che questo aiuti!

+0

Stefano, grazie mille per la risposta dettagliata, molto utile. In questo modo potrebbe essere utile effettuare l'aggiornamento a 1.3. – Parand

+0

Parand, è sicuramente (IMHO!) Degno di un passo verso django 1.3, anche se ci sono alcuni punti di cui occuparsi per una transizione senza intoppi: apri una nuova domanda SO se ti trovi nei guai ;-) – Stefano

+0

tra l'altro: Uso ancora questo tipo di impostazioni e il registro dei file, ma mi sono spostato su [sentry] (https://github.com/dcramer/sentry) per la produzione! – Stefano

Problemi correlati