Django Setup Default Logging


94

Não consigo descobrir como configurar um logger "padrão" para minha instalação do Django. Eu gostaria de usar a nova LOGGINGconfiguração do Django 1.3 em settings.py.

Eu olhei o exemplo do Django Logging Doc , mas me parece que eles apenas configuram manipuladores que farão o registro para loggers específicos. No caso do exemplo deles, eles configuraram o manipulador para os loggers chamados 'django', 'django.request' e 'myproject.custom'.

Tudo que eu quero fazer é configurar um padrão logging.handlers.RotatingFileHandlerque irá controlar todos os loggers por padrão. ou seja, se eu fizer um novo módulo em algum lugar do meu projeto e ele for denotado por algo como my_app_name.my_new_module:, devo ser capaz de fazer isso e fazer com que todos os logs vão para os logs do arquivo rotativo.

# In file './my_app_name/my_new_module.py'
import logging
logger = logging.getLogger('my_app_name.my_new_module')
logger.debug('Hello logs!') # <-- This should get logged to my RotatingFileHandler that I setup in `settings.py`!

Respostas:


153

Descobri ...

Você define o 'catch all' logger referenciando-o com a cadeia vazia: ''.

Como exemplo, na configuração a seguir, tenho todos os eventos de log sendo salvos em logs/mylog.log, com exceção dos django.requesteventos de log que serão salvos em logs/django_request.log. Como 'propagate'está definido como Falsepara meu django.requestlogger, o evento de log nunca alcançará o logger 'catch all'.

LOGGING = {
    'version': 1,
    'disable_existing_loggers': True,
    'formatters': {
        'standard': {
            'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s'
        },
    },
    'handlers': {
        'default': {
            'level':'DEBUG',
            'class':'logging.handlers.RotatingFileHandler',
            'filename': 'logs/mylog.log',
            'maxBytes': 1024*1024*5, # 5 MB
            'backupCount': 5,
            'formatter':'standard',
        },  
        'request_handler': {
            'level':'DEBUG',
            'class':'logging.handlers.RotatingFileHandler',
            'filename': 'logs/django_request.log',
            'maxBytes': 1024*1024*5, # 5 MB
            'backupCount': 5,
            'formatter':'standard',
        },
    },
    'loggers': {
        '': {
            'handlers': ['default'],
            'level': 'DEBUG',
            'propagate': True
        },
        'django.request': {
            'handlers': ['request_handler'],
            'level': 'DEBUG',
            'propagate': False
        },
    }
}

2
Chris, os documentos do Django sobre isso não são confusos. Obrigado por isso.

5
Correção minúscula: o comentário implica que o log sql seria afetado pelo logger django.request. Para redirecionar o log do sql, você definiria um logger para 'django.db'. O logger django.request lida com respostas http 5xx e 4xx.
rych

Isso ajuda outros novatos como eu: O logger criará os arquivos de log, mas você deve criar a logs/pasta primeiro :-). Caso contrário, você obterá um erro ao executar ./manange.py runserver. @Chris W. Obrigado por suas configurações de registro de exemplo. Me ajudou muito!
hobbes3,

3
@arindamroychowdhury Com a configuração acima, se você fizer logger = logging.getLogger('foo'); logger.warn('bar');isso, o defaultmanipulador irá capturar esse registro e algo como <time> WARN: foo: barterminará emlogs/mylog.log
Chris W.

8
Obrigado, parece que isso '' significa logger root. Esta informação útil não foi encontrada na documentação do Django.
Eino Mäkitalo

25

Como você disse em sua resposta , Chris, uma opção para definir um logger padrão é usar a string vazia como sua chave.

No entanto, acho que a forma pretendida é definir um logger especial sob a rootchave do dicionário de configuração de log. Eu encontrei isso na documentação do Python :

root - esta será a configuração para o logger root. O processamento da configuração será como para qualquer registrador, exceto que a propagateconfiguração não será aplicável.

Aqui está a configuração de sua resposta alterada para usar a rootchave:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': True,
    'formatters': {
        'standard': {
            'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s'
        },
    },
    'handlers': {
        'default': {
            'level':'DEBUG',
            'class':'logging.handlers.RotatingFileHandler',
            'filename': 'logs/mylog.log',
            'maxBytes': 1024*1024*5, # 5 MB
            'backupCount': 5,
            'formatter':'standard',
        },  
        'request_handler': {
            'level':'DEBUG',
            'class':'logging.handlers.RotatingFileHandler',
            'filename': 'logs/django_request.log',
            'maxBytes': 1024*1024*5, # 5 MB
            'backupCount': 5,
            'formatter':'standard',
        },
    },
    'root': {
        'handlers': ['default'],
        'level': 'DEBUG'
    },
    'loggers': {
        'django.request': {
            'handlers': ['request_handler'],
            'level': 'DEBUG',
            'propagate': False
        },
    }
}

Para ser justo, não consigo ver nenhuma diferença de comportamento entre as duas configurações. Parece que definir um logger com uma chave de string vazia modificará o logger raiz, porque logging.getLogger('')retornará o logger raiz.

A única razão que eu prefiro 'root'mais ''é que ele é explícito sobre como modificar o logger raiz. Caso você esteja curioso, 'root'substitui ''se você definir ambos, apenas porque a entrada raiz é processada por último.


Sim, isso mesmo, desculpe o erro de correção! Embora usar '' em vez de 'root' seja um tanto lógico, ainda acho um pouco inconsistente mover a rootentrada para a raiz do dict no processo de transição suave de uma lógica 2.6 fileConfig para 2.7 dictConfig.
Antony Hatchkins de

2
import logging
logger = logging.getLogger(__name__)

depois de adicionar:

logging.basicConfig(
    level = logging.DEBUG,
    format = '%(name)s %(levelname)s %(message)s',
)

podemos mudar o formato para:

format = '"%(levelname)s:%(name)s:%(message)s"  ',

ou

format = '%(name)s %(asctime)s %(levelname)s %(message)s',

0

Fiz uma amostra rápida para verificar qual configuração é usada quando a rootchave e o ''logger vazio são referenciados no config dict.

import logging.config

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'fmt1': {
            'format': '[FMT1] %(asctime)-15s %(message)s',
        },
        'fmt2': {
            'format': '[FMT2] %(asctime)-15s %(message)s',
        }
    },
    'handlers': {
        'console1': {
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'fmt1',
        },
        'console2': {
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'fmt2',
        },
    },
    # First config for root logger: console1 -> fmt1
    'root': {
        'handlers': ['console1'],
        'level': 'DEBUG',
        'propagate': True,
    },
    'loggers': {
        # Second config for root logger: console2 -> fmt2
        '': {
            'handlers': ['console2'],
            'level': 'DEBUG',
            'propagate': True,
        },
    },
}

logging.config.dictConfig(LOGGING)

l1 = logging.getLogger()
l2 = logging.getLogger('')
root = logging.root

l1.info("l1")
l2.info("l2")
root.info("root logger")

Imprime o seguinte resultado:

[FMT1] 2018-12-18 17:24:47,691 l1
[FMT1] 2018-12-18 17:24:47,691 l2
[FMT1] 2018-12-18 17:24:47,691 root logger

indicando que a configuração na rootchave tem a prioridade mais alta. Se o bloco for removido, o resultado será:

[FMT2] 2018-12-18 17:25:43,757 l1
[FMT2] 2018-12-18 17:25:43,757 l2
[FMT2] 2018-12-18 17:25:43,757 root logger

Em ambos os casos, consegui depurar e determinar que todos os três registradores ( l1, l2e root) fizeram referência à mesma instância do registrador, o registrador raiz.

Espero que ajude outras pessoas que, como eu, ficaram confusas com as 2 maneiras diferentes de configurar o logger de root.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.