Skip to main content
 首页 » 编程设计

python之使用来自多个模块的 python 日志记录写入文件和 RotatingFileHandler

2025年05月04日9cloudgamer

我正在使用以下模块在我的模块中记录事件。我这样调用它:

模块 1

from tools.debug_logger import debug_logger 
self.logger = debug_logger().start_logger('module1') 
self.logger.debug("Top left corner found") 

模块 2:

from tools.debug_logger import debug_logger 
self.logger = debug_logger().start_logger('module2') 
self.logger.debug("Top left corner found") 

这里是文件/tools/debug_logger.py

import logging, logging.handlers 
import sys 
class debug_logger(object): 
    def start_logger(self,name): 
        logger = logging.getLogger(name) 
        logger.setLevel(logging.DEBUG) 
        if not len(logger.handlers): 
            fh = logging.handlers.RotatingFileHandler('log/pokerprogram.log', maxBytes=1000000, backupCount=10) 
            fh.setLevel(logging.DEBUG) 
            fh2 = logging.handlers.RotatingFileHandler('log/pokerprogram_info_only.log', maxBytes=1000000, backupCount=5) 
            fh2.setLevel(logging.INFO) 
            er = logging.handlers.RotatingFileHandler('log/errors.log', maxBytes=2000000, backupCount=2) 
            er.setLevel(logging.WARNING) 
            ch = logging.StreamHandler(sys.stdout) 
            ch.setLevel(1) 
            fh.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')) 
            fh2.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')) 
            er.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')) 
            ch.setFormatter(logging.Formatter('%(name)s - %(levelname)s - %(message)s')) 
            logger.addHandler(fh) 
            logger.addHandler(fh2) 
            logger.addHandler(ch) 
            logger.addHandler(er) 
        return logger 

一切正常,我得到了各个级别的日志文件,但是当调用 RotatingFileHandler 时,我有时会遇到错误。就好像各种实例都想同时进行轮换,尽管我很确定这不应该发生,因为我确保只有 1 个处理程序带有 if not len(logger.handlers) 此处推荐:Duplicate log output when using Python logging module .

任何可能在轮换期间导致此文件访问冲突的建议都将不胜感激。

PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'C:\\Users\\Nicolas\\Dropbox\\PythonProjects\\Poker\\log\\pokerprogram.log' -> 'C:\\Users\\Nicolas\\Dropbox\\PythonProjects\\Poker\\log\\pokerprogram.log.1' 

我认为权限错误的发生是因为当轮换发生时其他模块仍在写入文件。

当我写入文件并使用此 RotatingFileHandler 时,从多个模块进行日志记录的最佳方式是什么?有什么最佳实践吗?

请您参考如下方法:

我相信您的日志记录设置有误。设置日志记录的推荐方法是不在模块中定义任何处理程序或日志记录级别,而是在主文件中定义所有配置。

例如在module1.py中:

import logging 
 
logger = logging.getLogger(__name__) 
 
# use logger.info/logger.debug etc. 

在 module2.py 中,你输入完全相同的代码:

import logging 
 
logger = logging.getLogger(__name__) 
 
# use logger.info/logger.debug etc. 

请注意,__name__ 是模块名称,因此它类似于 package.module1 或 package.module2。使用点分名称会自动创建记录器的层次结构,因此这就是为什么通常只使用模块的 __name__ 来获取记录器的原因。

module1 和 module2 不需要包含与日志记录相关的任何其他内容。他们不应该决定日志输出的位置或其级别,因为这是启动应用程序的人应该控制的事情。因此最好在主可执行文件中处理。

现在在您的主要可执行文件中定义您的处理程序:

import logging, logging.handlers 
 
fh = logging.handlers.RotatingFileHandler('log/pokerprogram.log', maxBytes=1000000, backupCount=10) 
fh.setLevel(logging.DEBUG) 
fh2 = logging.handlers.RotatingFileHandler('log/pokerprogram_info_only.log', maxBytes=1000000, backupCount=5) 
fh2.setLevel(logging.INFO) 
er = logging.handlers.RotatingFileHandler('log/errors.log', maxBytes=2000000, backupCount=2) 
er.setLevel(logging.WARNING) 
ch = logging.StreamHandler(sys.stdout) 
ch.setLevel(1) 
fh.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')) 
fh2.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')) 
er.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')) 
ch.setFormatter(logging.Formatter('%(name)s - %(levelname)s - %(message)s')) 

最后,您只需将处理程序添加到根记录器,并将根记录器的级别设置为处理程序中的最低级别:

root = logging.getLogger() 
root.setLevel(logging.DEBUG) 
# alternatively: 
# root.setLevel(min([fh.level, fh2.level, ch.level, er.level]) 
 
root.addHandler(fh) 
root.addHandler(fh2) 
root.addHandler(ch) 
root.addHandler(er) 

这是由于记录器的分层性质。当调用 module1.logger.debug 时,如果记录器没有处理程序,它将把日志记录传递给它的父记录器,父记录器将继续这样做,直到根记录器最终使用它的处理程序处理日志记录。

还需要设置根记录器级别,因为它默认为WARNING,而其他记录器默认为NOTSET(这会导致前面提到的委托(delegate))。

或者,您可以显式地将相同的处理程序添加到两个模块记录器:

from <package> import module1, module2 
 
module1.logger.setLevel(logging.DEBUG) 
module2.logger.setLevel(logging.DEBUG) 
 
module1.logger.addHandler(fh) 
module2.logger.addHandler(fh) 
module1.logger.addHandler(fh2) 
module2.logger.addHandler(fh2) 
module1.logger.addHandler(ch) 
module2.logger.addHandler(ch) 
module1.logger.addHandler(er) 
module2.logger.addHandler(er) 

将相同的处理程序对象添加到多个记录器没有坏处。这可确保处理程序不会尝试同时旋转文件。