Moduł logging to standardowe narzędzie Pythona do prowadzenia logów. Wprowadza hierarchię loggerów i obsługuje poziomy logowania (severity levels): DEBUG, INFO, WARNING, ERROR, CRITICAL. Prawidłowe użycie pozwala na centralne zarządzanie wyjściem, zapisywanie logów do plików, wysyłanie ich e-mailem, filtrowanie według poziomu itp.
Główna idea to tworzenie loggerów z nazwami (logging.getLogger(__name__)) w każdym module, nie tworzenie globalnego loggera root od nowa w każdym miejscu. Konfiguracja (format, handlerzy, poziom) jest wykonywana centralnie na starcie aplikacji.
Przykład konfiguracji:
import logging logging.basicConfig(format='%(levelname)s:%(name)s:%(message)s', level=logging.INFO) logger = logging.getLogger(__name__) def foo(): logger.info('Informacyjna wiadomość') logger.error('Błąd!') foo()
Dlaczego nie można wywoływać logging.basicConfig() w każdym module? Co się stanie, jeśli to zrobimy?
Odpowiedź: logging.basicConfig() konfiguruje logger root tylko raz na sesję Pythona. Powtórne wywołania, jeśli logger root został już zainicjowany, będą ignorowane. W rezultacie, jeśli różne moduły próbują wywołać basicConfig() z własnymi formatami/poziomami — zadziała tylko ten pierwszy!
Historia
W dużym projekcie każdy programista konfigurował logging według własnych upodobań przez basicConfig i lokalne handlerzy. Z tego powodu niektóre logi w ogóle się nie wyświetlały, inne były duplikowane dziesięciokrotnie, a wiadomości z różnych modułów nie zmieściły się w jednym pliku.
Historia
Podczas migracji usługi internetowej na wielopoziomowe logowanie zapomniano wskazać nazwę loggera przez getLogger(__name__), wszędzie pisano do loggera root. W rezultacie niemożliwe było ustalenie, skąd pochodził konkretny log.
Historia
Używano funkcji logger.error() do zapisywania wszystkich wiadomości, nawet tych niebędących błędami. W rezultacie automatyczne systemy monitorowania ciągle "podnosiły alarm", ponieważ widziały wysoki poziom błędów, chociaż były to zwykłe wiadomości debug/info.