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.