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

Nic*_*ick 1 python logging

我正在使用以下模块记录模块中的事件.我称之为:

模块1

from tools.debug_logger import debug_logger
self.logger = debug_logger().start_logger('module1')
self.logger.debug("Top left corner found")
Run Code Online (Sandbox Code Playgroud)

模块2:

from tools.debug_logger import debug_logger
self.logger = debug_logger().start_logger('module2')
self.logger.debug("Top left corner found")
Run Code Online (Sandbox Code Playgroud)

这里是文件/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
Run Code Online (Sandbox Code Playgroud)

一切正常,我得到各个级别的日志文件,但是当调用RotatingFileHandler时,我有时会收到错误.就好像各种实例都希望同时进行旋转一样,即使我非常确定这不应该发生,因为我确保这里只有1个处理程序 if not len(logger.handlers):使用Python日志记录模块时重复日志输出.

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

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'
Run Code Online (Sandbox Code Playgroud)

我相信会发生权限错误,因为当轮换发生时,其他模块仍在写入文件.

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

Bak*_*riu 9

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

例如module1.py:

import logging

logger = logging.getLogger(__name__)

# use logger.info/logger.debug etc.
Run Code Online (Sandbox Code Playgroud)

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

import logging

logger = logging.getLogger(__name__)

# use logger.info/logger.debug etc.
Run Code Online (Sandbox Code Playgroud)

请注意,这__name__是模块名称,因此它将类似于package.module1package.module2.使用虚线名称会自动创建记录器的层次结构,这就是为什么习惯使用__name__模块来获取记录器.

有没有必要module1module2包含其他任何相关记录.他们应该没有决定在哪里日志输出变为或其水平,因为这一点是谁启动应用程序应该控制.因此,最好在主可执行文件中处理.

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

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'))
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)

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

有必要设置根记录器级别,因为它默认为WARNING,而其他记录器默认为NOTSET(这导致之前提到的委托).

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

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)
Run Code Online (Sandbox Code Playgroud)

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