O registro Python não produz nada


94

Em um script python que estou escrevendo, estou tentando registrar eventos usando o módulo de registro. Tenho o seguinte código para configurar meu logger:

ERROR_FORMAT = "%(levelname)s at %(asctime)s in %(funcName)s in %(filename) at line %(lineno)d: %(message)s"
DEBUG_FORMAT = "%(lineno)d in %(filename)s at %(asctime)s: %(message)s"
LOG_CONFIG = {'version':1,
              'formatters':{'error':{'format':ERROR_FORMAT},
                            'debug':{'format':DEBUG_FORMAT}},
              'handlers':{'console':{'class':'logging.StreamHandler',
                                     'formatter':'debug',
                                     'level':logging.DEBUG},
                          'file':{'class':'logging.FileHandler',
                                  'filename':'/usr/local/logs/DatabaseUpdate.log',
                                  'formatter':'error',
                                  'level':logging.ERROR}},
              'root':{'handlers':('console', 'file')}}
logging.config.dictConfig(LOG_CONFIG)

Quando tento executar logging.debug("Some string"), não obtenho nenhuma saída para o console, embora esta página nos documentos diga que logging.debugo logger root deve mostrar a mensagem. Por que meu programa não está exibindo nada e como posso corrigir isso?

Respostas:


98

O nível de log padrão é aviso. Como você não alterou o nível, o nível do logger root ainda está avisando. Isso significa que ele irá ignorar qualquer registro com um nível inferior a aviso, incluindo registros de depuração.

Isso é explicado no tutorial :

import logging
logging.warning('Watch out!') # will print a message to the console
logging.info('I told you so') # will not print anything

A linha 'info' não imprime nada, porque o nível é mais alto do que info.

Para alterar o nível, basta configurá-lo no logger raiz:

'root':{'handlers':('console', 'file'), 'level':'DEBUG'}

Em outras palavras, não é suficiente definir um manipulador com nível = DEBUG, o nível de registro real também deve ser DEBUG para que ele produza qualquer coisa.


6
A documentação diz que seu nível padrão é NOTSET, que é um nível 0 que deve mostrar tudo ... Por que isso não é verdade?
— Ben

@Ben, onde diz isso? Tudo o que posso ver é "O nível padrão é WARNING, o que significa que apenas eventos deste nível e acima serão rastreados, a menos que o pacote de registro seja configurado para fazer o contrário."
— Omri Barel


1
@Ben de acordo com os documentos que os loggers são percorridos para encontrar o primeiro pai level != NOTSETou a raiz (se nenhum for encontrado). A raiz tem WARNINGnível por padrão. Isso está escrito na seção que você vinculou a ( Logger.setLevel).
— Omri Barel,

5
Lembre-se de que, após a importação, loggingvocê precisa ligar logging.basicConfig()pelo menos uma vez. Caso contrário, você pode se surpreender ao saber que os registradores de crianças não imprimirão nada. As funções de registro no logger root o chamam de maneira preguiçosa.
— Hubert Grzeskowiak

58

Muitos anos depois, parece ainda haver um problema de usabilidade com o logger do Python. Aqui estão algumas explicações com exemplos:

import logging
# This sets the root logger to write to stdout (your console).
# Your script/app needs to call this somewhere at least once.
logging.basicConfig()

# By default the root logger is set to WARNING and all loggers you define
# inherit that value. Here we set the root logger to NOTSET. This logging
# level is automatically inherited by all existing and new sub-loggers
# that do not set a less verbose level.
logging.root.setLevel(logging.NOTSET)

# The following line sets the root logger level as well.
# It's equivalent to both previous statements combined:
logging.basicConfig(level=logging.NOTSET)


# You can either share the `logger` object between all your files or the
# name handle (here `my-app`) and call `logging.getLogger` with it.
# The result is the same.
handle = "my-app"
logger1 = logging.getLogger(handle)
logger2 = logging.getLogger(handle)
# logger1 and logger2 point to the same object:
# (logger1 is logger2) == True


# Convenient methods in order of verbosity from highest to lowest
logger.debug("this will get printed")
logger.info("this will get printed")
logger.warning("this will get printed")
logger.error("this will get printed")
logger.critical("this will get printed")


# In large applications where you would like more control over the logging,
# create sub-loggers from your main application logger.
component_logger = logger.getChild("component-a")
component_logger.info("this will get printed with the prefix `my-app.component-a`")

# If you wish to control the logging levels, you can set the level anywhere 
# in the hierarchy:
#
# - root
#   - my-app
#     - component-a
#

# Example for development:
logger.setLevel(logging.DEBUG)

# If that prints too much, enable debug printing only for your component:
component_logger.setLevel(logging.DEBUG)


# For production you rather want:
logger.setLevel(logging.WARNING)

Uma fonte comum de confusão vem de um logger root mal inicializado. Considere isto:

import logging
log = logging.getLogger("myapp")
log.warning("woot")
logging.basicConfig()
log.warning("woot")

Resultado:

woot
WARNING:myapp:woot

Dependendo do seu ambiente de tempo de execução e níveis de registro, a primeira linha de registro (antes da configuração básica) pode não aparecer em qualquer lugar .


Meu registro não está funcionando, pois não produz nenhum arquivo de saída. Você vê alguma coisa que estou fazendo que está claramente errada? logging.basicConfig( filename='logging.txt', level=logging.DEBUG) logger = logging.getLogger() logger.info('Test B') logging.info('Test A')
— Rylan Schaeffer

O arquivo de registro ainda nem foi criado
— Rylan Schaeffer

Percebi que, depois de eliminar um ponto de interrupção logger = logging.getLogger(), o nível está definido como WARNING, embora eu tenha especificado o nível como DEBUG. Você sabe o que estou fazendo de errado?
— Rylan Schaeffer

Olá @RylanSchaeffer, talvez você queira criar uma nova pergunta e fornecer mais alguns detalhes. Isso também dará a outras pessoas a chance de ajudá-lo.
— Hubert Grzeskowiak

Eu fiz. Frequentemente, fazer um comentário é uma maneira mais rápida de encontrar uma resposta, porque pelo menos uma pessoa com conhecimento verá minha pergunta
— Rylan Schaeffer

20

Para qualquer um aqui que deseja uma resposta super simples: basta definir o nível que deseja exibir. No topo de todos os meus scripts, acabei de colocar:

import logging
logging.basicConfig(level = logging.INFO)

Em seguida, para exibir qualquer coisa nesse nível ou acima:

logging.info("Hi you just set your fleeb to level plumbus")

É um conjunto hierárquico de cinco níveis para que os logs sejam exibidos no nível que você definir ou superior . Portanto, se você quiser exibir um erro, pode usar logging.error("The plumbus is broken").

Os níveis, em ordem crescente de severidade, são DEBUG, INFO, WARNING, ERROR, e CRITICAL. A configuração padrão é WARNING.

Este é um bom artigo que contém essas informações expressas melhor do que minha resposta:
https://www.digitalocean.com/community/tutorials/how-to-use-logging-in-python-3


14

Talvez tente isso? Parece que o problema foi resolvido após remover todos os manipuladores do meu caso.

for handler in logging.root.handlers[:]:
    logging.root.removeHandler(handler)

logging.basicConfig(filename='output.log', level=logging.INFO)

SyntaxError: invalid syntax
— Eric

2
Por que isso é necessário? Quais manipuladores vêm com o logger python e por que eles estão lá para começar? Ou talvez a questão seja: por que o basicConfig não os substitui / substitui?
— jrh
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.