2009-10-21 23 views
83

Todavía tengo que encontrar la manera de configurar el registro de Python con Django con el que estoy satisfecho. Mis requisitos son bastante simples:Configuración elegante de inicio de sesión de Python en Django

  • diferentes manejadores de registro para diferentes eventos - es decir, quiero ser capaz de acceder a diferentes archivos
  • fácil acceso a los madereros en mis módulos. El módulo debería poder encontrar su registrador con poco esfuerzo.
  • Debe ser fácilmente aplicable a los módulos de línea de comandos. Partes del sistema son procesos independientes de línea de comando o daemon. El registro debe ser fácilmente utilizable con estos módulos.

Mi configuración actual es usar un archivo logging.conf y el registro de configuración en cada módulo desde el que inicio sesión. No se siente bien.

¿Tiene una configuración de registro que le guste? Por favor, detallarlo: cómo configurar la configuración (¿usa logging.conf o configurarla en el código), dónde/cuándo inicia los registradores y cómo puede acceder a ellos en sus módulos, etc.

+1

Puede ser útil el siguiente screencast útil - http://ericholscher.com/blog/2008/aug/29/screencast-2-logging-fun-and-profit/. Además, Simon Willison ha propuesto un mejor soporte para iniciar sesión en Django (ver http://simonwillison.net/2009/Sep/28/ponies/). –

+0

@Dominic Rodger: Ya puedes hacer un registro flexible de aplicaciones en Django, la propuesta de Simon principalmente para facilitar el inicio de sesión en Django internal.Se está trabajando en Python para agregar configuración basada en diccionario al registro de Python, del cual Django podría beneficiarse. –

Respuesta

49

La mejor manera que he encontrado hasta ahora es inicializar la configuración de inicio de sesión en settings.py - en ninguna otra parte. Puede usar un archivo de configuración o hacerlo mediante programación paso a paso; solo depende de sus requisitos. La clave es que normalmente agrego los manejadores que quiero al registrador de raíz, usando niveles y algunas veces registrando. Filtros para obtener los eventos que quiero en los archivos apropiados, consola, syslogs, etc. Por supuesto, puede agregar manejadores a cualquier otro registrador también, pero no hay una necesidad común de esto en mi experiencia.

En cada módulo, que definen un registrador usando

logger = logging.getLogger(__name__) 

y el uso que para el registro de eventos en el módulo (y, si quiero diferenciar aún más) utilizo un registrador que es un hijo del registrador creado encima.

Si mi aplicación va a ser potencialmente utilizados en un sitio que no configurar el registro en settings.py, que definen un NullHandler algún lugar de la siguiente manera:

#someutils.py 

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

null_handler = NullHandler() 

y asegurarse de que una instancia del mismo es agregado a todos los registradores creados en los módulos en mis aplicaciones que usan el registro. (Nota: NullHandler ya está en el paquete de registro para Python 3.1, y estará en Python 2.7.) Por lo tanto:

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

Esto se hace para asegurar que sus módulos desempeñan muy bien en un sitio que no configurar el registro en settings.py, y que no obtiene ningún molesto mensaje "No se encontraron controladores para el registrador XYZ" (que son advertencias sobre el registro potencialmente mal configurado).

Hacerlo de esta manera cumple con los requisitos establecidos:

  • Puede configurar diferentes manejadores de registro para diferentes eventos, como se hace actualmente.
  • Fácil acceso a los registradores en sus módulos - use getLogger(__name__).
  • Fácilmente aplicable a los módulos de línea de comandos: también importan settings.py.

Actualización: Nota que a partir de la versión 1.3, Django incorpora ahora support for logging.

+0

¿No requerirá esto que cada módulo tenga un controlador definido en la configuración (no se puede usar un controlador para que foo maneje foo.bar)? Vea la conversación que tuvimos hace años en http://groups.google.com/group/comp.lang.python/browse_thread/thread/6a199393bcee6c1b/2ddf482a44bc4bb1 –

+1

@andrew cooke: Usted * puede * usar un controlador para 'foo' para manejar eventos registrados en 'foo.bar'. Re. ese hilo - tanto fileConfig como dictConfig ahora tienen opciones para evitar la desactivación de los viejos registradores. Vea este número: http://bugs.python.org/issue3136, que llegó en un par de meses después de su problema http://bugs.python.org/issue2697 - de todos modos, ha sido resuelto desde junio de 2008. –

+0

wouldn ¿No es mejor hacer 'logger = someutils.getLogger (__ name __)' donde 'someutils.getLogger' devuelve el registrador de' logging.getLogger' con un null_handler ya agregado? – 7yl4r

6

Actualmente estoy usando un sistema de registro, que creé yo mismo. Utiliza el formato CSV para el registro.

django-csvlog

Este proyecto aún no tiene la documentación completa, pero estoy trabajando en ello.

6

Inicializamos el registro en el nivel superior urls.py utilizando un archivo logging.ini.

La ubicación de logging.ini se proporciona en settings.py, pero eso es todo.

Cada módulo se hace

logger = logging.getLogger(__name__) 

Para distinguir las pruebas, desarrollo e instancias de producción, que tienen diferentes archivos logging.ini. En su mayor parte, tenemos un "registro de la consola" que va a stderr solo con errores. Tenemos un "registro de aplicación" que utiliza un archivo de registro continuo que va a un directorio de registros.

+0

Terminé usando esto, excepto inicializando en settings.py en lugar de urls.py – Parand

+0

¿Cómo se usa la configuración de settings.py en su archivo logging.ini? Por ejemplo, necesito la configuración BASE_DIR, así puedo decir dónde almacenar mis archivos de registro. – slypete

+0

@slypete: No utilizamos configuraciones en logging.ini. Dado que el registro es en gran parte independiente, no usamos ninguna de las configuraciones de Django. Sí, hay una posibilidad de repetir algo. No, no hace mucha diferencia práctica. –

114

Sé que ya se trata de una respuesta resuelta, pero según django> = 1.3 hay una nueva configuración de registro.

Pasar de viejo a nuevo no es automático, así que pensé que lo escribiría aquí.

Y, por supuesto, salida the django doc para algunos más.

Ésta es la conf básico, creado por defecto con v1.3 django-admin createproject - kilometraje podría cambiar con las últimas versiones de 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, 
     } 
    } 
} 

Esta estructura se basa en el estándar Python logging dictConfig, que dicta el siguiente bloques:

  • formatters - el valor correspondiente será un diccionario en el que cada tecla es un identificador formateador y cada valor es un diccionario que describe cómo configurar la instancia correspondiente del formateador.
  • filters - el valor correspondiente será un dict en el cual cada clave es una identificación de filtro y cada valor es un dict que describe cómo configurar la instancia de filtro correspondiente.
  • handlers - el valor correspondiente será un dict en el que cada clave es una identificación de controlador y cada valor es un dict que describe cómo configurar la instancia de controlador correspondiente. Cada controlador tiene las siguientes claves:

    • class (obligatorio). Este es el nombre completo de la clase de controlador.
    • level (opcional). El nivel del controlador.
    • formatter (opcional). La id del formateador para este controlador.
    • filters (opcional). Una lista de identificadores de los filtros para este controlador.

por lo general lo hago por lo menos esto:

  • añadir un archivo .log
  • configurar mis aplicaciones escribir en este registro

que se traduce en:

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' 
    }, 
} 

edición

Ver request exceptions are now always logged y Ticket #16288:

He actualizado el conf muestra anterior para incluir explícitamente el filtro correcto para mail_admins de manera que, por defecto, los correos electrónicos no se envían cuando depuración es verdadera.

Usted debe agregar un filtro:

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

y aplicarlo al controlador de mail_admins:

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

lo contrario, el django.core.handers.base.handle_uncaught_exception no pasa errores al registrador 'django.request' si los ajustes .DEBUG es verdadero.

Si no se hace esto en Django 1.5 podrás obtener una DeprecationWarning

: No tiene filtros definidos en el manejador de registro de los '' mail_admins: Adición implícita de depuración de falso único filtro

pero las cosas seguirán funcionando correctamente tanto en django 1.4 como en django 1.5.

** ** final de edición

Eso conf está fuertemente inspirado en el conf muestra en el documento de Django, pero la adición de la parte del archivo de registro.

A menudo también haga lo siguiente:

LOG_LEVEL = 'DEBUG' if DEBUG else 'INFO' 

... 
    'level': LOG_LEVEL 
... 

Luego, en mi código Python siempre añadir un NullHandler en caso de que no conf registro se define en absoluto. Esto evita advertencias para ningún controlador especificado. Especialmente útil en las librerías que no necesariamente se llama sólo en 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.') 

Espero que esto ayude!

+0

Stefano, muchas gracias por la respuesta detallada, muy útil. Esto puede hacer que valga la pena actualizar a 1.3. – Parand

+0

Parand, definitivamente (en mi humilde opinión) vale la pena dar un paso hacia django 1.3, aunque hay algunos puntos que debes tener en cuenta para una transición sin problemas: abre una nueva pregunta si tienes problemas ;-) – Stefano

+0

por cierto: Aún utilizo este tipo de configuraciones y el archivo de registro, pero me mudé a [centinela] (https://github.com/dcramer/sentry) para la producción. – Stefano

Cuestiones relacionadas