python - log - ¿El registrador django.request no se propaga a la raíz?
logging in django project (2)
La solución es evitar que Django configure el registro y manejarlo nosotros mismos. Afortunadamente esto es fácil. En settings.py
:
LOGGING_CONFIG = None
LOGGING = {...} # whatever you want, as you already have
import logging.config
logging.config.dictConfig(LOGGING)
ACTUALIZACIÓN ~ marzo de 2015 : Django ha clarified su documentation :
Si la clave disable_existing_loggers en LOGGING dictConfig se establece en Verdadero, se deshabilitarán todos los registradores de la configuración predeterminada. Los registradores deshabilitados no son lo mismo que eliminados; el registrador seguirá existiendo, pero descartará silenciosamente todo lo que se haya registrado, ni siquiera propagará las entradas a un registrador principal. Por lo tanto, debes tener mucho cuidado al usar ''disable_existing_loggers'': True; Probablemente no es lo que quieres. En su lugar, puede establecer disable_existing_loggers en False y redefinir algunos o todos los registradores predeterminados; o puede configurar LOGGING_CONFIG en Ninguno y manejar la configuración de registro usted mismo.
Por posteridad y detalle: ¿ La explicación? Creo que la mayor parte de la confusión se debe a la pobre explanation de disable_existing_loggers
sobre disable_existing_loggers
, que dice que cuando es True, "la configuración predeterminada está completamente anulada". En tu propia respuesta descubriste que eso no es correcto; Lo que sucede es que los registradores existentes, que Django ya configura, están deshabilitados y no se reemplazan.
La documentation registro de Python lo explica mejor (énfasis añadido):
disable_existing_loggers: si se especifica como False, los registradores que existen cuando se realiza esta llamada se quedan solos. El valor predeterminado es Verdadero porque permite el comportamiento antiguo de una manera compatible con versiones anteriores. Este comportamiento es deshabilitar cualquier registrador existente a menos que ellos o sus ancestros tengan un nombre explícito en la configuración de registro.
Según los documentos de Django, creemos que "anulará los valores predeterminados con mi propia configuración de REGISTRO y todo lo que no especifique se disparará ". También me he tropezado con esta expectativa. El comportamiento que esperamos es en la línea de replace_existing_loggers (que no es una cosa real). En su lugar, los registradores Django se callan, no se burbujean .
Necesitamos evitar la configuración de estos registradores Django en primer lugar y aquí los docs Django son más útiles:
Si no desea configurar el registro en absoluto (o si desea configurar manualmente el registro utilizando su propio método), puede configurar LOGGING_CONFIG en Ninguno. Esto deshabilitará el proceso de configuración.
Nota: configurar LOGGING_CONFIG en Ninguno solo significa que el proceso de configuración está deshabilitado, no el registro en sí. Si desactivas el proceso de configuración, Django seguirá haciendo llamadas de registro, y se volverá a adoptar el comportamiento de registro predeterminado.
Django seguirá usando sus registradores, pero como la configuración no los maneja (y luego se deshabilitan) con la configuración, esos registradores se acelerarán como se espera. Una prueba simple con la configuración anterior:
manage.py shell
>>> import logging
>>> logging.warning(''root logger'')
WARNING 2014-03-11 13:35:08,832 root root logger
>>> l = logging.getLogger(''django.request'')
>>> l.warning(''request logger'')
WARNING 2014-03-11 13:38:22,000 django.request request logger
>>> l.propagate, l.disabled
(1, 0)
Usando Django 1.5.1:
DEBUG = False
LOGGING = {
''version'': 1,
''disable_existing_loggers'': True,
''formatters'': {
''verbose'': {
''format'': ''%(levelname)s %(asctime)s %(module)s %(message)s''
},
},
''handlers'': {
''console'': {
''level'': ''DEBUG'',
''class'': ''logging.StreamHandler'',
''formatter'': ''verbose'',
},
},
''loggers'': {
# root logger
'''': {
''handlers'': [''console''],
},
#''django.request'': {
# ''handlers'': [''console''],
# ''level'': ''DEBUG'',
# ''propagate'': False,
#},
}
}
Si elimino el comentario de las líneas comentadas y llamo a una vista que tiene 1/0
, el rastreo se imprime en la consola:
ERROR 2013-11-29 13:33:23,102 base Internal Server Error: /comment/*******/
Traceback (most recent call last):
...
File "*****/comments/views.py", line 10, in post
1/0
ZeroDivisionError: integer division or modulo by zero
WARNING 2013-11-29 13:33:23,103 csrf Forbidden (CSRF cookie not set.): /comment/******/
[29/Nov/2013 13:33:23] "POST /comment/******/ HTTP/1.0" 500 27
Pero si las líneas permanecen comentadas, no se imprime ningún rastreo en la consola, simplemente:
[29/Nov/2013 13:33:23] "POST /comment/******/ HTTP/1.0" 500 27
Pensé que si el registrador django.request
no está configurado, se propagaría al registrador raíz, que imprime todo en la consola.
No encontré ninguna información que django.request
sea especial.
¿Por qué no funciona?
Here leí:
Antes de Django 1.5, la configuración de REGISTRO siempre sobrescribía la configuración de registro de Django predeterminada. Desde Django 1.5 en adelante, es posible obtener la configuración de registro del proyecto fusionada con los valores predeterminados de Django, por lo que puede decidir si desea agregar o reemplazar la configuración existente.
Si la clave disable_existing_loggers en LOGGING dictConfig se establece en True (que es el valor predeterminado), la configuración predeterminada se anulará por completo. Alternativamente, puede redefinir algunos o todos los registradores configurando disable_existing_loggers en False.
En django/utils/log.py
:
# Default logging for Django. This sends an email to the site admins on every
# HTTP 500 error. Depending on DEBUG, all other log records are either sent to
# the console (DEBUG=True) or discarded by mean of the NullHandler (DEBUG=False).
DEFAULT_LOGGING = {
''version'': 1,
''disable_existing_loggers'': False,
''filters'': {
''require_debug_false'': {
''()'': ''django.utils.log.RequireDebugFalse'',
},
''require_debug_true'': {
''()'': ''django.utils.log.RequireDebugTrue'',
},
},
''handlers'': {
''console'':{
''level'': ''INFO'',
''filters'': [''require_debug_true''],
''class'': ''logging.StreamHandler'',
},
''null'': {
''class'': ''django.utils.log.NullHandler'',
},
''mail_admins'': {
''level'': ''ERROR'',
''filters'': [''require_debug_false''],
''class'': ''django.utils.log.AdminEmailHandler''
}
},
''loggers'': {
''django'': {
''handlers'': [''console''],
},
''django.request'': {
''handlers'': [''mail_admins''],
''level'': ''ERROR'',
''propagate'': False,
},
''py.warnings'': {
''handlers'': [''console''],
},
}
}
Entonces, por defecto, django.request
ha propagate = False
. Pero en mi caso tengo ''disable_existing_loggers'': True
.
Ok, entonces el comportamiento es "correcto", pero no esperado. django/conf/__init__.py:65
:
def _configure_logging(self):
...
if self.LOGGING_CONFIG:
from django.utils.log import DEFAULT_LOGGING
# First find the logging configuration function ...
logging_config_path, logging_config_func_name = self.LOGGING_CONFIG.rsplit(''.'', 1)
logging_config_module = importlib.import_module(logging_config_path)
logging_config_func = getattr(logging_config_module, logging_config_func_name)
logging_config_func(DEFAULT_LOGGING)
if self.LOGGING:
# Backwards-compatibility shim for #16288 fix
compat_patch_logging_config(self.LOGGING)
# ... then invoke it with the logging settings
logging_config_func(self.LOGGING)
Lo que está sucediendo es que se aplica la configuración de registro predeterminada y se django.request
registrador django.request
. Entonces mi configuración de LOGGING
personalizada se aplica con disable_existing_loggers = True
, pero Python no elimina el django.request
registrador existente, sino que solo lo desactiva.
Así que tengo que reconfigurar manualmente el registrador django.request
en mi configuración. :(