我有一个并发运行的程序,我想为每个子进程创建一个日志。我将首先描述我的设置,然后描述我面临的问题。以下是我的主要模块:
mp_handler.py:
import logging
import multiprocessing as mp
def mp_handler(target, args_list):
# configure logs
for args in args_list:
logger_id = args[0] # first arg suffices to id a process, in my case
logger = logging.getLogger(logger_id)
handler = logging.FileHandler(logger_id + '.log')
logger.setLevel(logging.INFO)
logger.addHandler(handler)
mp.set_start_method('spawn') # bug fix, see below
# build each process
for args in args_list:
p = mp.Process(target = target, args = args)
p.start()
mp_worker.py:
import logging
from deco_module import deco
from my_module import function_with_open_cv
@deco
def mp_worker(args):
logger_id = arg[0]
logger = logging.getLogger(logger_id)
log.info("Information about process %s" % log_id)
# do a lot of stuff with openCV3
function_with_open_cv(args) # also logs to this child's log file
deco_module.py:这个模块做了一些异常处理,我不知道它为什么会干扰但是我想我会包含它以防万一。
from functools import wraps
import logging
def deco(function):
@wraps(function)
def wrapper(*args):
logger_id = *args[0]
logger = logging.getLogger(logger_id)
try:
function(*args)
except:
logger.info('a message in case the child fails.')
return wrapper
现在,关于我的问题。我收到了这篇文章中描述的错误:https://github.com/opencv/opencv/issues/5150。因此,我在mp.set_start_method('spawn')
中写了mp_handler()
行。
然而,在调试之后,我发现该行导致logger = logging.getLogger(logger_id)
行mp_worker()
创建一个新的记录器而不是获取在父节点中创建的记录器,即mp_handler()
。我能够通过在父模块和子模块中打印hex(id(logger))
来看到这一点,并看到内存中的位置是不同的。事实上,正如我所说,写mp.set_start_method('fork')
避免了这个问题(这对我来说非常粗糙,因为我的理解是spawn将为记录器创建一个新的空间)。
主要问题:问题是,我如何处理我需要将start方法设置为' spawn'为了OpenCV但需要将其关闭以便在模块之间进行日志通信(即为了使mp_worker能够识别其正确的logger_id以便记录到正确的文件)?作为良好实践的一部分,我希望将所有日志配置保留在子项和子模块之外。
次要问题:假设我忽略了我需要OpenCV并将方法设置为' fork。'在这种情况下,我注意到function_with_open_cv()
函数中的所有logging.info()语句都没有到达日志!因此,假设您的建议确实涉及将其设置为fork,那么这里的工作是什么?编辑:固定!这也是由OpenCV引起的。所以问题仍然存在......如何使用生成过程而不丢失我的记录器ID?
非常感谢你!
答案 0 :(得分:0)
您不应该在生成进程之前配置日志记录,但之后。有关如何正确执行此操作的示例,请参阅the documentation。这适用于Python 3,但如果您需要在Python 2下运行它,则可以使用logutils package,它提供curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
和QueueListener
类。
日志食谱包含更多与使用QueueHandler
进行日志记录相关的示例代码。