1

我有一个在分叉的 Gunicorn 环境中运行的 Flask 应用程序,但堆栈跟踪在日志文件中交错。每个分叉可以有自己的日志文件吗?还是每个记录器在写入日志时都可以拥有独占访问权限?

4

2 回答 2

3

每个分叉可以有自己的日志文件吗?

是的,尽管您可能不需要或不想要那个。最简单的方法是os.getpid()在文件名中的某个位置粘贴。

还是每个记录器在写入日志时都可以拥有独占访问权限?

有几种方法可以做到这一点,但显而易见的一种方法是将默认值threading.RLock替换loggingmultiprocessing.RLock.

根据文档,您可以通过覆盖createLockacquirerelease. 所以:

class CrossProcessFileHandler(logging.FileHandler):
    def createLock(self):
        self.lock = multiprocessing.RLock()
    def acquire(self):
        self.lock.acquire()
    def release(self):
        self.lock.release()

现在只需使用它而不是FileHandler.

只要确保在父进程中初始化记录器;如果每个孩子都创建自己单独的跨进程锁,那将无济于事。


请注意,如果您关心跨平台可移植性,那么显而易见的琐碎代码可能在 POSIX 上按预期工作,但在 Windows 上却不行。(我gunicorn对 Windows 上的工作原理知之甚少……)但是您可以通过不锁定 Windows 来解决这个问题,因为默认情况下,FileHandler打开文件以进行独占访问、写入和关闭,这意味着文件系统是已经为你做你的锁定。(这个技巧在 POSIX 上不起作用,因为没有 Windows 风格的独占访问——或者,更确切地说,在大多数平台和文件系统上都有等价物,但它们不是可移植的,你必须走出你的不管你是否想要它,而不是默认获取它。)


CPython 2.3 到 3.3 的所有内置处理程序的实现acquirerelease每个替代实现一直是这样的:

if self.lock:
    self.lock.acquire()

因此,您将看到仅通过覆盖createLock. 我自己已经多次这样做了,并且在各种不同的第三方项目中看到了它。但实际上,文档并不能保证这一点,因此您也应该覆盖其他两个。

于 2013-06-06T22:17:53.067 回答
0

@abarnert 解决方案效果很好,但是它需要对项目中使用的每个处理程序进行子类化。它可以通过类装饰器来简化:

def multiprocess_handler(cls):
    class MultiProcessHandler(cls):
        def createLock(self):
            self.lock = multiprocessing.RLock()
    return MultiProcessHandler

MFileHandler = multiprocess_handler(logging.FileHandler)
MRotatingFileHandler = multiprocess_handler(logging.handlers.RotatingFileHandler)
# etc.
于 2016-09-25T21:04:08.883 回答