python日志记录是否支持多处理?

Kra*_* Li 23 python python-multiprocessing

有人告诉我,日志记录不能用于多处理.在多处理混淆日志的情况下,您必须执行并发控制.

但我做了一些测试,似乎在使用多处理登录时没有问题

import time
import logging
from multiprocessing import Process, current_process, pool


# setup log
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S',
                    filename='/tmp/test.log',
                    filemode='w')


def func(the_time, logger):
    proc = current_process()
    while True:
        if time.time() >= the_time:
            logger.info('proc name %s id %s' % (proc.name, proc.pid))
            return



if __name__ == '__main__':

    the_time = time.time() + 5

    for x in xrange(1, 10):
        proc = Process(target=func, name=x, args=(the_time, logger))
        proc.start()
Run Code Online (Sandbox Code Playgroud)

正如您从代码中看到的那样.

我故意让子进程在同一时刻(开始后5s)写日志以增加冲突的可能性.但是根本没有冲突.

所以我的问题是我们可以在多处理中使用日志记录吗?为什么这么多帖子说我们不能?

mat*_*ino 20

从多个进程写入单个文件是不安全的.

根据https://docs.python.org/3/howto/logging-cookbook.html#logging-to-a-single-file-from-multiple-processes

虽然记录是线程安全的,并登录到从多个线程在单个进程中一个单独的文件支持,记录从多个进程的单个文件不支持,因为能够连续访问多个单个文件没有标准的方法Python中的进程.

一种可能的解决方案是让每个进程写入自己的文件.您可以通过编写自己的处理程序来实现此目的,该处理程序将进程pid添加到文件的末尾:

import logging.handlers
import os


class PIDFileHandler(logging.handlers.WatchedFileHandler):

    def __init__(self, filename, mode='a', encoding=None, delay=0):
        filename = self._append_pid_to_filename(filename)
        super(PIDFileHandler, self).__init__(filename, mode, encoding, delay)

    def _append_pid_to_filename(self, filename):
        pid = os.getpid()
        path, extension = os.path.splitext(filename)
        return '{0}-{1}{2}'.format(path, pid, extension)
Run Code Online (Sandbox Code Playgroud)

然后你只需要打电话addHandler:

logger = logging.getLogger('foo')
fh = PIDFileHandler('bar.log')
logger.addHandler(fh)
Run Code Online (Sandbox Code Playgroud)


han*_*ast 17

正如Matino正确解释的那样:登录多处理设置并不安全,因为多个进程(对现有的其他进程不了解)正在写入同一个文件,可能相互干预.

现在发生的是每个进程都拥有一个打开的文件句柄并对该文件进行"追加写入".问题是在什么情况下追加写入是"原子的"(也就是说,不能被例如写入同一文件并混合其输出的另一个进程中断).这个问题适用于每种编程语言,因为最终他们会对内核进行系统调用.这个答案回答了在哪种情况下共享日志文件是可以的.

它归结为检查管道缓冲区大小,在linux上定义的/usr/include/linux/limits.h是4096字节.对于其他操作系统,您可以在这里找到一个很好

这意味着:如果您的日志行小于4'096字节(如果在Linux上),则附加是安全的,如果磁盘是直接连接的(即中间没有网络).但是有关详细信息,请查看我的答案中的第一个链接.要测试这个,您可以logger.info('proc name %s id %s %s' % (proc.name, proc.pid, str(proc.name)*5000))使用不同的长度.以5000为例,我已经混入了日志行/tmp/test.log.

这个问题中已经有很多解决方案,所以我不会在这里添加自己的解决方案.

更新:Flask和多处理

如果由uwsgi或nginx托管,那么像flask这样的Web框架将在多个worker中运行.在这种情况下,多个进程可以写入一个日志文件.会有问题吗?

烧瓶中的错误处理是通过stdout/stderr完成的,然后由网络服务器(uwsgi,nginx等)完成,这需要注意以正确的方式写入日志(参见例如[此烧瓶+ nginx示例])(http://flaviusim.com/blog/Deploying-Flask-with-nginx-uWSGI-and-Supervisor/),可能还添加了流程信息,因此您可以将错误行与流程相关联.来自烧瓶文件:

默认情况下,从Flask 0.11开始,错误会自动记录到您的Web服务器日志中.但警告不是.

因此,如果您使用warn并且消息超出管道缓冲区大小,您仍然会遇到此问题的混合日志文件.