Mam mały projekt python, który ma następującą strukturę -
Project
-- pkg01
-- test01.py
-- pkg02
-- test02.py
-- logging.conf
Planuję użyć domyślnego modułu rejestrującego do drukowania komunikatów na standardowe wyjście i pliku dziennika. Aby użyć modułu rejestrującego, wymagana jest inicjalizacja -
import logging.config
logging.config.fileConfig('logging.conf')
logger = logging.getLogger('pyApp')
logger.info('testing')
Obecnie wykonuję tę inicjalizację w każdym module przed rozpoczęciem rejestrowania komunikatów. Czy można wykonać tę inicjalizację tylko raz w jednym miejscu, tak aby te same ustawienia były ponownie używane po zalogowaniu się w całym projekcie?
fileConfig
w każdym module logującym się, chyba że maszif __name__ == '__main__'
logikę we wszystkich. odpowiedź prost nie jest dobrą praktyką, jeśli pakiet jest biblioteką, ale może ci się przydać - nie należy konfigurować rejestrowania pakietów bibliotek, oprócz dodawaniaNullHandler
.package/__init__.py
. To zwykle nie jest miejsce, w którym umieszczaszif __name__ == '__main__'
kod. Przykład prost wygląda na to, że przy imporcie wywoła kod konfiguracji bezwarunkowo, co nie wydaje mi się właściwe. Zasadniczo rejestrowanie kodu konfiguracyjnego powinno odbywać się w jednym miejscu i nie powinno być efektem ubocznym importu, z wyjątkiem importowania __main__.if __name__ == '__main__'
? (nie jest to wyraźnie wspomniane, jeśli tak jest)Odpowiedzi:
Najlepszą praktyką jest, aby w każdym module zdefiniować rejestrator w następujący sposób:
u góry modułu, a następnie w innym kodzie w module wykonaj np
Jeśli chcesz podzielić rejestrowanie w module, użyj np
i loguj się
loggerA
iloggerB
odpowiednio.W głównym programie lub programach wykonaj np .:
lub
Zobacz tutaj, aby zalogować się z wielu modułów, a tutaj, aby zalogować się do konfiguracji kodu, który będzie używany jako moduł biblioteki przez inny kod.
Aktualizacja: Podczas dzwonienia
fileConfig()
możesz określić,disable_existing_loggers=False
czy używasz języka Python 2.6 lub nowszego ( więcej informacji znajdziesz w dokumentacji ). Domyślną wartością jestTrue
kompatybilność wsteczna, co powoduje, że wszystkie istniejące programy rejestrujące są wyłączone,fileConfig()
chyba że oni lub ich przodek są wyraźnie nazwani w konfiguracji. Przy ustawionej wartościFalse
istniejące rejestratory są pozostawione same sobie. Jeśli używasz Python 2.7 / Python 3.2 lub nowszy, możesz rozważyćdictConfig()
API, które jest lepsze niżfileConfig()
ponieważ daje większą kontrolę nad konfiguracją.źródło
disable_existing_loggers
flagę, która jestTrue
domyślnie, ale można ją ustawić naFalse
.W rzeczywistości każdy program rejestrujący jest dzieckiem programu rejestrującego pakiet nadrzędny (tzn.
package.subpackage.module
Dziedziczy konfiguracjępackage.subpackage)
, więc wystarczy tylko skonfigurować program rejestrujący root. Można to osiągnąć za pomocąlogging.config.fileConfig
(własnej konfiguracji programów rejestrujących ) lublogging.basicConfig
(ustawia program rejestrujący root) Skonfiguruj logowanie do modułu wejściowego (__main__.py
lub cokolwiek, co chcesz uruchomić, na przykładmain_script.py
.__init__.py
Działa również)using basicConfig:
using fileConfig:
a następnie utwórz każdy rejestrator za pomocą:
Aby uzyskać więcej informacji, zobacz Zaawansowany samouczek rejestrowania .
źródło
__main__.py
(np. Czy chcę użyć modułu w skrypcie, który nie ma programu rejestrującego)logging.getLogger(__name__)
nadal będzie logować się w module, czy spowoduje wyjątek?Zawsze robię to jak poniżej.
Użyj pojedynczego pliku Pythona, aby skonfigurować mój dziennik jako wzorzec singletonu o nazwie „
log_conf.py
”W innym module wystarczy zaimportować konfigurację.
Jest to singletonowy wzór do rejestrowania, prosty i wydajny.
źródło
Kilka z tych odpowiedzi sugeruje, że u góry modułu robisz
Rozumiem, że jest to uważane za bardzo złą praktykę . Powodem jest to, że konfiguracja pliku domyślnie wyłączy wszystkie istniejące programy rejestrujące. Na przykład
A w głównym module:
Teraz dziennik określony w logowaniu.ini będzie pusty, ponieważ istniejący rejestrator został wyłączony przez wywołanie fileconfig.
Chociaż z pewnością można to obejść (disable_existing_Loggers = False), realistycznie wielu klientów twojej biblioteki nie będzie wiedziało o tym zachowaniu i nie otrzyma twoich logów. Ułatw swoim klientom, zawsze wywołując lokalnie logowanie.getLogger. Hat Tip: Dowiedziałem się o tym zachowaniu ze strony Victora Lin .
Dlatego dobrą praktyką jest zawsze lokalne wywoływanie rejestrowania.getLogger. Na przykład
Ponadto, jeśli używasz fileconfig w głównym, ustaw disable_existing_loggers = False, na wypadek, gdyby projektanci bibliotek używali instancji modułu rejestrującego na poziomie modułu.
źródło
logging.config.fileConfig('logging.ini')
wcześniejimport my_module
? Jak sugerowano w tej odpowiedzi .logger = logging.getLogger(__name__)
”Prostym sposobem użycia jednej instancji biblioteki rejestrowania w wielu modułach było dla mnie następujące rozwiązanie:
base_logger.py
Inne pliki
źródło
Rzucanie w innym rozwiązaniu.
W moim module init .py mam coś takiego:
Następnie w każdym module potrzebuję rejestratora:
Gdy brakuje dzienników, możesz odróżnić ich źródło od modułu, z którego pochodzą.
źródło
Możesz również wymyślić coś takiego!
Teraz możesz używać wielu rejestratorów w tym samym module i całym projekcie, jeśli powyższe jest zdefiniowane w osobnym module i zaimportowane w innych modułach, jeśli wymagane jest rejestrowanie.
źródło
@ Rozwiązanie Yarkee wydawało się lepsze. Chciałbym coś jeszcze dodać -
LoggerManager może być podłączany do całej aplikacji. Mam nadzieję, że to ma sens i wartość.
źródło
Istnieje kilka odpowiedzi. Skończyło się na podobnym, ale innym rozwiązaniu, które ma dla mnie sens, być może ma to również sens dla ciebie. Moim głównym celem była możliwość przekazywania dzienników do programów obsługi według ich poziomu (dzienniki poziomu debugowania do konsoli, ostrzeżenia i wyżej do plików):
utworzył ładny plik util o nazwie logger.py:
flask.app jest zakodowaną wartością w kolbie. rejestrator aplikacji zawsze zaczyna się od flask.app jako nazwy modułu.
teraz w każdym module mogę go używać w następującym trybie:
Spowoduje to utworzenie nowego dziennika dla „app.flask.MODULE_NAME” przy minimalnym wysiłku.
źródło
Najlepszą praktyką byłoby utworzenie modułu osobno, który ma tylko jedną metodę, której zadaniem jest przekazanie funkcji wywołującej program rejestrujący do metody wywołującej. Zapisz ten plik jako m_logger.py
Teraz wywołuj metodę getlogger (), ilekroć potrzebna jest obsługa programu rejestrującego.
źródło
--debug
opcję w aplikacji i chcesz ustawić poziom rejestrowania we wszystkich rejestratorach w aplikacji na podstawie tego parametru ...get_logger(level=logging.INFO)
aby zwrócić jakiś singleton, więc kiedy wywołano go po raz pierwszy z głównej aplikacji, inicjuje program rejestrujący i moduły obsługi z odpowiednim poziomem, a następnie zwraca ten samlogger
obiekt do wszystkich innych metod.Nowy w Pythonie, więc nie wiem, czy jest to wskazane, ale działa świetnie, aby nie przepisywać płyty głównej.
Twój projekt musi mieć plik inicjujący .py, aby można go było załadować jako moduł
sys._getframe(1)
sugestia pochodzi stądNastępnie, aby użyć rejestratora w dowolnym innym pliku:
Ostrzeżenia:
import [your module]
nie będzie działać:python -m [your module name].[your filename without .py]
__main__
, ale w każdym używającym rozwiązaniu__name__
będzie występować ten problem.źródło