首页 > 解决方案 > 阻止日志脚本被多个线程访问

问题描述

我有一个名为myLog.py的模块,项目中的多个其他模块正在访问该模块。该myLog.py模块有两个处理程序:file_handler将日志输入文件并将stream_handler日志输出到控制台。对于没有发生线程的模块,即myLog.py仅由单个进程访问,日志被正确插入,但对于正在实现线程的模块,即myLog.py同时被多个进程访问,我得到同一行的多个日志被插入我的log_file.txt.

在浏览日志文档时,我发现日志模块是thread_safe,但我的实现方式不同。我应该如何初始化函数setLogger()myLog.py以便如果它同时被多个线程访问,它会给出正确的输出?

#myLog.py

#setup of logger
def setLogger(logfile_name = "log_file.txt"):
    logger = logging.getLogger(__name__)
    logger.setLevel(logging.INFO)
    formatter = logging.Formatter('%(message)s')
    file_handler = logging.FileHandler(logfile_name)
    file_handler.setFormatter(formatter)
    stream_handler = logging.StreamHandler()
    logger.addHandler(file_handler)
    logger.addHandler(stream_handler)
    return logger

因此,假设它被一个名为 parser.py 的模块访问,该模块实现了线程,然后日志语句以非常随机的重复方式打印出来。

#parser.py

import threading
import myLog

logger = myLog.setLogger()

class investigate(threading.Thread):
    def __init__(self, section, file, buffer, args):
        threading.Thread.__init__(self)
        self.section = section
        self.file = file
        self.buffer = buffer
        self.args = args
        self.sig = self.pub = None
        self.exc = None

    def run(self):
        aprint("Starting section %d file %d" % (self.section, self.file))
        self.exc = None
        try:
            self.sign()
            aprint("Done section %d file %d" % (self.section, self.file))
        except:
            self.exc = sys.exc_info()

    def sign(self):
        self.sig, self.pub = sign_hsm(self.buffer, self.args)
        if self.sig is None or self.pub is None:
            raise Exception("Empty signing result")

    def store(self, bot):
        sec = filter(lambda x: x.type == self.section, bot.sections)[0]
        if self.file == 0xFF:
            signature = sec.signature
        else:
            signature = sec.files[self.file].signature
        signature.sig = self.sig
        signature.pub = self.pub

    def join(self, *args, **kwargs):
        threading.Thread.join(self, *args, **kwargs)
        if self.exc:
            msg = "Thread '%s' threw an exception: %s" % (self.getName(), self.exc[1])
            new_exc = Exception(msg)
            raise new_exc.__class__, new_exc, self.exc[2]

def PrintVersion():
    logger.info("This is output.")

print_lock = threading.RLock()
def aprint(*args, **kwargs):
    if verbosityLevel > 0:
        with print_lock:
            return logger.info(*args, **kwargs)


def multipleTimes():
    logger.info("Multiple times.")

if __name__ == "__main__":
    PrintVersion()
    for investigate in investigations:
       investigate.start()
      .......
      .......
      .......
    logger.info("This gets repeated")
    multipleTimes()

因此,由于多个线程正在尝试访问setLogger()我得到的logger.info()输出,例如:

This is output.
This is output.
This is output.
This is output.
This is output.
This gets repeated.
This gets repeated.
This gets repeated.
Multiple times.
Multiple times.
Multiple times.
Multiple times.
Multiple times.
Multiple times.

我应该得到什么:

This is output.
This gets repeated.
Multiple times.

标签: pythonloggingprocessthread-safetyhandler

解决方案


推荐阅读