我有一个小的python项目,它有以下结构-
Project
-- pkg01
-- test01.py
-- pkg02
-- test02.py
-- logging.conf
我计划使用默认日志记录模块将消息打印到标准输出和日志文件。
要使用日志记录模块,需要进行一些初始化
import logging.config
logging.config.fileConfig('logging.conf')
logger = logging.getLogger('pyApp')
logger.info('testing')
目前,在开始记录消息之前,我在每个模块中执行此初始化。是否可以只在一个地方执行一次初始化,以便通过记录整个项目来重用相同的设置?
你也可以想出这样的东西!
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
现在你可以在同一个模块和整个项目中使用多个记录器,如果上面的定义在一个单独的模块中,并在其他模块中导入日志记录是必需的。
a=get_logger("__app___")
b=get_logger("__basic_log__")
a.info("Starting logging!")
b.debug("Debug Mode")
有几个答案。我最终得到了一个类似但不同的解决方案,对我来说有意义,也许对你也有意义。
我的主要目标是能够按级别将日志传递给处理程序(调试级别的日志传递给控制台,警告和以上级别的日志传递给文件):
from flask import Flask
import logging
from logging.handlers import RotatingFileHandler
app = Flask(__name__)
# make default logger output everything to the console
logging.basicConfig(level=logging.DEBUG)
rotating_file_handler = RotatingFileHandler(filename="logs.log")
rotating_file_handler.setLevel(logging.INFO)
app.logger.addHandler(rotating_file_handler)
创建了一个名为logger.py的util文件:
import logging
def get_logger(name):
return logging.getLogger("flask.app." + name)
长颈瓶。App是flask中硬编码的值。应用程序记录器总是从flask开始。App作为它的模块名。
现在,在每个模块中,我能够在以下模式中使用它:
from logger import get_logger
logger = get_logger(__name__)
logger.info("new log")
这将为“app.flask”创建一个新的日志。MODULE_NAME”。
这些答案中有几个建议在模块的顶部
import logging
logger = logging.getLogger(__name__)
据我所知,这是非常糟糕的做法。原因是文件配置默认情况下将禁用所有现有的记录器。如。
#my_module
import logging
logger = logging.getLogger(__name__)
def foo():
logger.info('Hi, foo')
class Bar(object):
def bar(self):
logger.info('Hi, bar')
在主模块中:
#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()
现在logging.ini中指定的日志将为空,因为现有的记录器已被fileconfig调用禁用。
虽然这当然是可能的(disable_existing_Loggers=False),但实际上你库的许多客户端不会知道这个行为,也不会接收到你的日志。通过始终调用logging使您的客户更容易。在本地getlog。温馨提示:我是从Victor Lin的网站上了解到这种行为的。
因此,好的做法是总是调用日志记录。在本地getlog。如。
#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')
同样,如果你在main中使用fileconfig,设置disable_existing_loggers=False,以防你的库设计人员使用模块级记录器实例。
最好的做法是单独创建一个模块,该模块只有一个方法,我们的任务是为调用方法提供一个记录器处理程序。将该文件保存为m_logger.py
import logger, logging
def getlogger():
# logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# create console handler and set level to debug
#ch = logging.StreamHandler()
ch = logging.FileHandler(r'log.txt')
ch.setLevel(logging.DEBUG)
# create formatter
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
# add formatter to ch
ch.setFormatter(formatter)
# add ch to logger
logger.addHandler(ch)
return logger
现在,只要需要记录器处理程序,就调用getlogger()方法。
from m_logger import getlogger
logger = getlogger()
logger.info('My mssg')
@Yarkee的解决方案似乎更好。我想再加一些
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)
所以LoggerManager可以插入到整个应用程序中。
希望它有意义和价值。