如何处理来自不同Gunicorn叉的交错异常?

时间:2013-06-06 22:02:19

标签: python logging flask fork gunicorn

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

2 个答案:

答案 0 :(得分:3)

  

每个fork都可以拥有自己的日志文件吗?

是的,虽然您可能不需要或不想要。最简单的方法是在文件名中的某处粘贴os.getpid()

  

或者每个记录器在写入日志时都可以独占访问吗?

有几种方法可以做到这一点,但显而易见的方法是用threading.RLock替换logging中的默认multiprocessing.RLock

根据the docs,您可以通过覆盖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风格的独占访问 - 或者说,在大多数平台和文件系统上都有等价物,但它们不可移植,你必须离开你的无论你是否愿意,都可以这样做,而不是默认获取它。)


The implementation of acquire and release for all built-in handlers for CPython 2.3 to 3.3并且每个替代实现都是这样的:

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

所以,你会看到仅通过覆盖createLock而作弊的代码。我自己已经多次这样做了,我已经在各种不同的第三方项目中看到了它。但实际上,文档并不能保证,所以你也应该覆盖其他两个。

答案 1 :(得分:0)

@abarnert解决方案非常有效,但它需要子类化项目中使用的每个Handler。它可以由类装饰器简化:

self.ref!.child("Books").childByAutoId().setValue(["title": arrayOfNames[0] as! NSString, "author": arrayOfNames[1] as! NSString , "pages_count":arrayOfNames[2] as! NSString])