Rejestrowanie w Pythonie niczego nie wyświetla


97

W skrypcie Pythona, który piszę, próbuję rejestrować zdarzenia za pomocą modułu logowania. Mam następujący kod do skonfigurowania mojego loggera:

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)

Kiedy próbuję uruchomić logging.debug("Some string"), nie dostaję żadnych danych wyjściowych do konsoli, mimo że na tej stronie w dokumentacji jest napisane, że logging.debuggłówny rejestrator powinien wypisać komunikat. Dlaczego mój program nic nie wyświetla i jak mogę to naprawić?

Odpowiedzi:


103

Domyślnym poziomem rejestrowania jest ostrzeżenie. Ponieważ nie zmieniłeś poziomu, poziom głównego programu rejestrującego wciąż ostrzega. Oznacza to, że zignoruje wszelkie rejestrowanie z poziomem niższym niż ostrzeżenie, w tym rejestrowanie debugowania.

Jest to wyjaśnione w samouczku :

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

Linia „info” nic nie drukuje, ponieważ poziom jest wyższy niż info.

Aby zmienić poziom, po prostu ustaw go w głównym rejestratorze:

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

Innymi słowy, nie wystarczy zdefiniować procedurę obsługi z level = DEBUG, rzeczywisty poziom rejestrowania musi również być DEBUG, aby mógł cokolwiek wypisywać.


7
Dokumentacja mówi, że jej domyślnym poziomem jest NOTSET, czyli poziom 0, który powinien wypisać wszystko ... Dlaczego to nieprawda?
— Ben

@ Ben, gdzie to jest napisane? Wszystko, co widzę, to „Poziom domyślny to OSTRZEŻENIE, co oznacza, że ​​śledzone będą tylko zdarzenia tego poziomu i wyższych, chyba że w pakiecie rejestrowania skonfigurowano inaczej”.
— Omri Barel


1
@Ben zgodnie z dokumentacją, przez które loggery są przeszukiwane, aby znaleźć pierwszego rodzica z level != NOTSETlub root (jeśli nie znaleziono). Katalog główny ma WARNINGdomyślnie poziom. Jest to napisane w sekcji, z którą utworzyłeś link ( Logger.setLevel).
— Omri Barel

5
Pamiętaj, że po zaimportowaniu loggingmusisz zadzwonić logging.basicConfig()co najmniej raz. W przeciwnym razie możesz być bardzo zdziwiony, że programy logujące potomne nic nie wydrukują. Funkcje rejestrujące w głównym programie rejestrującym wywołują to leniwie.
— Hubert Grzeskowiak

74

Wiele lat później wydaje się, że nadal występuje problem z użytecznością programu rejestrującego Python. Oto kilka wyjaśnień wraz z przykładami:

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)

Częstym źródłem nieporozumień jest źle zainicjowany program rejestrujący root. Rozważ to:

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

Wynik:

woot
WARNING:myapp:woot

W zależności od środowiska wykonawczego i poziomów rejestrowania, pierwszy wiersz dziennika (przed podstawową konfiguracją) może nie pojawić się nigdzie .


Moje logowanie nie działa, ponieważ nie tworzy żadnego pliku wyjściowego. Czy widzisz coś, co robię, co jest wyraźnie niewłaściwe? logging.basicConfig( filename='logging.txt', level=logging.DEBUG) logger = logging.getLogger() logger.info('Test B') logging.info('Test A')
— Rylan Schaeffer

Plik dziennika nawet nie został utworzony
— Rylan Schaeffer

Zauważyłem, że po upuszczeniu punktu przerwania logger = logging.getLogger()poziom jest ustawiony na OSTRZEŻENIE, mimo że określiłem poziom jako DEBUG. Czy wiesz, co robię źle?
— Rylan Schaeffer

Cześć @RylanSchaeffer, możesz utworzyć nowe pytanie i podać więcej szczegółów. Dzięki temu inni będą mogli Ci pomóc.
— Hubert Grześkowiak

Zrobiłem. Często zadawanie komentarzy jest szybszym sposobem na znalezienie odpowiedzi, ponieważ przynajmniej jedna
— znająca się na

26

Dla każdego, kto szuka super prostej odpowiedzi: po prostu ustaw żądany poziom wyświetlania. Na górze wszystkich moich skryptów po prostu umieściłem:

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

Następnie, aby wyświetlić cokolwiek na tym poziomie lub powyżej:

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

Jest to hierarchiczny zestaw pięciu poziomów, dzięki czemu dzienniki będą wyświetlane na ustawionym lub wyższym poziomie . Więc jeśli chcesz wyświetlić błąd, możesz użyćlogging.error("The plumbus is broken") .

Poziomy te w rosnącej kolejności nasilenia, są DEBUG, INFO, WARNING, ERRORi CRITICAL. Ustawienie domyślne toWARNING .

To jest dobry artykuł zawierający te informacje wyrażone lepiej niż moja odpowiedź:
https://www.digitalocean.com/community/tutorials/how-to-use-logging-in-python-3


14

Może spróbuj tego? Wygląda na to, że problem został rozwiązany po usunięciu wszystkich modułów obsługi w moim przypadku.

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

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

SyntaxError: invalid syntax
— Eric

2
Dlaczego jest to konieczne? Jakie programy obsługi są dostarczane z rejestratorem języka Python i dlaczego są tam na początku? A może pytanie brzmi, dlaczego basicConfig ich nie nadpisuje / nie zastępuje?
— jrh
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.