Korzystanie z Pythona logowanie do wielu modułów
Mam mały projekt Pythona, który ma następującą strukturę -
Project
-- pkg01
-- test01.py
-- pkg02
-- test02.py
-- logging.conf
Planuję użyć domyślnego modułu logowania do drukowania wiadomości na stdout i pliku dziennika. Aby użyć modułu logging, wymagana jest pewna inicjalizacja -
import logging.config
logging.config.fileConfig('logging.conf')
logger = logging.getLogger('pyApp')
logger.info('testing')
Obecnie wykonuję tę inicjalizację w każdym module, zanim zacznę rejestrować wiadomości. Czy możliwe jest przeprowadzenie tej inicjalizacji tylko raz w jednym miejscu tak, że te same ustawienia są ponownie używane przez logowanie całego projektu?
7 answers
Najlepszą praktyką w każdym module jest zdefiniowanie loggera w następujący sposób:
import logging
logger = logging.getLogger(__name__)
W górnej części modułu, a następnie w innym kodzie w module do np.
logger.debug('My message with %s', 'variable data')
Jeśli chcesz podzielić aktywność logowania wewnątrz modułu, użyj np.
loggerA = logging.getLogger(__name__ + '.A')
loggerB = logging.getLogger(__name__ + '.B')
Oraz odpowiednio log do loggerA
i loggerB
.
W Twoim głównym programie lub programach wykonaj np.:
def main():
"your program code"
if __name__ == '__main__':
import logging.config
logging.config.fileConfig('/path/to/logging.conf')
main()
Lub
def main():
import logging.config
logging.config.fileConfig('/path/to/logging.conf')
# your program code
if __name__ == '__main__':
main()
Zobacz tutaj dla logowania z wielu modułów, i tutaj do logowania konfiguracji kodu, który będzie używany jako moduł biblioteki przez inny kod.
Update: podczas wywoływania fileConfig()
, możesz określić disable_existing_loggers=False
Jeśli używasz Pythona 2.6 lub nowszego (zobacz dokumenty aby uzyskać więcej informacji). Domyślną wartością jest True
dla zgodności wstecznej, co powoduje, że wszystkie istniejące Rejestratory są wyłączone przez fileConfig()
, chyba że są one lub ich przodek są jawnie nazwane w konfiguracji. Z wartością ustawioną na False
pozostaną istniejące rejestratory sam. Jeśli używasz Pythona 2.7/Pythona 3.2 lub nowszego, możesz rozważyć API dictConfig()
, które jest lepsze niż fileConfig()
, ponieważ daje większą kontrolę nad konfiguracją.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-13 07:47:38
Właściwie każdy rejestrator jest potomkiem rodzica (np. package.subpackage.module
dziedziczy konfigurację z package.subpackage)
, więc wystarczy tylko skonfigurować rejestrator główny. Można to osiągnąć poprzez logging.config.fileConfig
(własny config dla loggerów) lub logging.basicConfig
(ustawia root logger). Konfiguracja logowania w module wejściowym (__main__.py
lub cokolwiek chcesz uruchomić, na przykład main_script.py
. __init__.py
działa również)
Używanie basicConfig:
# package/__main__.py
import logging
import sys
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
Za pomocą fileConfig:
# package/__main__.py
import logging
import logging.config
logging.config.fileConfig('logging.conf')
A następnie utwórz każdy logger używając:
# package/submodule.py
# or
# package/subpackage/submodule.py
import logging
log = logging.getLogger(__name__)
log.info("Hello logging!")
Aby uzyskać więcej informacji, zobacz Advanced Logging Tutorial.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-20 08:34:01
Zawsze robię to jak poniżej.
Użyj pojedynczego pliku Pythona, aby skonfigurować mój dziennik jako wzorzec Singletona o nazwie 'log_conf.py
'
#-*-coding:utf-8-*-
import logging.config
def singleton(cls):
instances = {}
def get_instance():
if cls not in instances:
instances[cls] = cls()
return instances[cls]
return get_instance()
@singleton
class Logger():
def __init__(self):
logging.config.fileConfig('logging.conf')
self.logr = logging.getLogger('root')
W innym module, po prostu zaimportuj konfigurację.
from log_conf import Logger
Logger.logger.info("Hello World")
Jest to wzór Singletona do logowania, prosto i efektywnie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-07 12:08:15
@ Yarkee rozwiązanie wydawało się lepsze. Chciałbym dodać coś do niego -
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances.keys():
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class LoggerManager(object):
__metaclass__ = Singleton
_loggers = {}
def __init__(self, *args, **kwargs):
pass
@staticmethod
def getLogger(name=None):
if not name:
logging.basicConfig()
return logging.getLogger()
elif name not in LoggerManager._loggers.keys():
logging.basicConfig()
LoggerManager._loggers[name] = logging.getLogger(str(name))
return LoggerManager._loggers[name]
log=LoggerManager().getLogger("Hello")
log.setLevel(level=logging.DEBUG)
Więc LoggerManager może być podłączany do całej aplikacji. Mam nadzieję, że to ma sens i wartość.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-06 09:28:23
Dorzucam inne rozwiązanie.
W głównym module init mam coś takiego:
import logging
def get_module_logger(mod_name):
logger = logging.getLogger(mod_name)
handler = logging.StreamHandler()
formatter = logging.Formatter(
'%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)
return logger
Następnie w każdej klasie potrzebuję loggera, robię:
from [modname] import get_module_logger
logger = get_module_logger(__name__)
Gdy logi zostaną pominięte, możesz odróżnić ich źródło po module, z którego pochodzą.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-12 01:11:58
Kilka z tych odpowiedzi sugeruje, że na górze modułu robisz
import logging
logger = logging.getLogger(__name__)
Rozumiem, że jest to uważane za bardzo złą praktykę. Powodem jest to, że plik config domyślnie wyłączy wszystkie istniejące rejestratory. Np.
#my_module
import logging
logger = logging.getLogger(__name__)
def foo():
logger.info('Hi, foo')
class Bar(object):
def bar(self):
logger.info('Hi, bar')
I w głównym module:
#main
import logging
# load my module - this now configures the logger
import my_module
# This will now disable the logger in my module by default, [see the docs][1]
logging.config.fileConfig('logging.ini')
my_module.foo()
bar = my_module.Bar()
bar.bar()
Teraz log określony w logowaniu.ini będzie puste, ponieważ istniejący rejestrator został wyłączony przez wywołanie fileconfig.
Podczas gdy jest z pewnością możliwe, aby obejść to (disable_existing_Loggers=False), realistycznie wielu klientów twojej Biblioteki nie będzie wiedzieć o tym zachowaniu i nie otrzyma Twoich dzienników. Ułatw to swoim klientom, zawsze dzwoniąc do logowania.getLogger lokalnie. Hat Tip: dowiedziałem się o tym zachowaniu z strony internetowej Victora Lin.
Więc dobrą praktyką jest zawsze wywoływanie logowania.getLogger lokalnie. Np.
#my_module
import logging
logger = logging.getLogger(__name__)
def foo():
logging.getLogger(__name__).info('Hi, foo')
class Bar(object):
def bar(self):
logging.getLogger(__name__).info('Hi, bar')
Również, jeśli używasz fileconfig w głównym, Ustaw disable_existing_loggers=False, na wszelki wypadek projektanci bibliotek używają instancji rejestratora poziomu modułów.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-18 11:34:02
Możesz też wymyślić coś takiego!
def get_logger(name=None):
default = "__app__"
formatter = logging.Formatter('%(levelname)s: %(asctime)s %(funcName)s(%(lineno)d) -- %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
log_map = {"__app__": "app.log", "__basic_log__": "file1.log", "__advance_log__": "file2.log"}
if name:
logger = logging.getLogger(name)
else:
logger = logging.getLogger(default)
fh = logging.FileHandler(log_map[name])
fh.setFormatter(formatter)
logger.addHandler(fh)
logger.setLevel(logging.DEBUG)
return logger
Teraz możesz użyć wielu loggerów w tym samym module i w całym projekcie, jeśli powyższy jest zdefiniowany w oddzielnym module i zaimportowany w innych modułach wymagane jest logowanie.
a=get_logger("__app___")
b=get_logger("__basic_log__")
a.info("Starting logging!")
b.debug("Debug Mode")
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-11 18:29:24