我有一个叫main.py
的顶级core.py
。我希望两个文件都写入相同的时间。我的代码:
文件main.py
:
import core
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
logger.addHandler(ch)
fh = logging.FileHandler("main.log",mode="w")
fh.setLevel(logging.DEBUG)
logger.addHandler(fh)
logger.info("I am in main.")
core.myclass()
文件core.py
:
import logging
class myclass():
def __init__(self):
logger = logging.getLogger("main")
print(logger)
logger.debug("Debug message")
logger.warn("Warning message")
据我了解,
logger = logging.getLogger("main")
应该获得原始日志的引用,因此无需再次设置。但是,来自core.py
的消息处于默认警告级别,不会写入文件。
是否可以在不同模块之间维护相同的设置?
答案 0 :(得分:1)
最好的方法是创建一个基本的日志记录模块,并将其导入并在所有文件中使用。
示例如下
class BaseLogging():
def __init__(self):
self.logger = logging.getLogger(__name__)
self.logger.setLevel(logging.INFO)
self.formatter = logging.Formatter('%(asctime)s:%(mod_name)s,%(levelname)s:%(message)s')
self.file_handler = logging.FileHandler('debug.log')
self.file_handler.setFormatter(self.formatter)
self.logger.addHandler(self.file_handler)
def debug(self, msg):
module_stack = inspect.stack()[1][1]
mod_name = inspect.getmodulename(module_stack)
d = {'mod_name': mod_name}
self.logger.debug(msg, extra=d)
我在这里只显示了调试代码,但是类似地,您可以 编写警告,关键和全部警告的方法。
然后只需将该BaseLogging导入到所需的模块中,就可以轻松记录消息。记录器会将所有日志消息写到一个文件中,并指出写入日志条目的模块。
答案 1 :(得分:1)
我不打算发布自己的答案,但是我不同意其他答案,所以我们开始:)
我看不到创建基本日志模块的意义。已经有一个叫logging
,在我看来它做得很好。
另一个答案中概述的解决方案有一个缺陷:尽管它确实创建了一个记录器*,但是它还创建了多个处理程序和格式化程序,每次实例化BaseLogging
时都设置一个。
* 因为__name__
在BaseLogging
中没有更改,无论您从何处导入。这也是打破%(module)s
属性并要求inspect
进行“ hacks”以获取调用方模块名称的原因
core.py
from base_logging import BaseLogging
class myclass():
def __init__(self):
# just instantiate the class, don't even call any method on it
blogger = BaseLogging()
main.py
from base_logging import BaseLogging
import core
blog = BaseLogging() # fist instance, one handler and one formatter attached to the logger
core.myclass() # creates the second instance during instantiation
blog.debug("Can I get a sibling, mommy?")
注意:在base_logging.BaseLogging中,我向初始化器添加了self.logger.setLevel(logging.DEBUG)
,以使这项工作有效,而无需实现WARNING
及更高版本的方法。
如果您现在运行main.py
,则日志将如下所示:
2019-01-16 11:54:23,305:main,DEBUG:Can I get a sibling, mommy?
2019-01-16 11:54:23,305:main,DEBUG:Can I get a sibling, mommy?
logging
已在全局名称空间中工作。您一次创建和配置的记录器可从过程中的任何位置访问。您只需要知道要问哪个。您可以随时随地查看logging.Logger.manager.loggerDict
,以查看当前已知的记录器。
(注意:它可能不应该被认为是正式API的一部分,因此,我宁愿不使用它生产,但我发现它在开发和调试中很有用):
main.py
[your main.py up to this point]
print("before:", logging.Logger.manager.loggerDict)
#logger.info("I am in main.")
core.myclass()
print("after:", logging.Logger.manager.loggerDict)
core.py
class myclass():
def __init__(self):
logger = logging.getLogger("main")
print("in myclass", logging.Logger.manager.loggerDict)
#logger.debug("Debug message")
#logger.warn("Warning message")
输出:
before: {'__main__': <Logger __main__ (DEBUG)>}
in myclass {'__main__': <Logger __main__ (DEBUG)>, 'main': <Logger main (WARNING)>}
after: {'__main__': <Logger __main__ (DEBUG)>, 'main': <Logger main (WARNING)>}
因此,您需要确保的是,如果要获得相同的记录器,请使用相同的名称,即在这种情况下使用logger = logging.getLogger("__main__")
,或者更好的是,使用专用名称正确从一开始就避免__name__
的值基于脚本是执行还是导入而具有不同值的问题。
main.py
[...]
logger = logging.getLogger("main_logger")
[...]
core.py
# in myclass.__init__()
[...]
logger = logging.getLogger("main_logger")
[...]
=> main.log
I am in main.
Debug message
Warning message