[英]How do I handle interleaved exceptions from different Gunicorn forks?
我有一个在分叉的Gunicorn环境中运行的Flask应用程序,但堆栈跟踪在日志文件中交叉存取。 每个fork都可以拥有自己的日志文件吗? 或者每个记录器在写入日志时都可以独占访问吗?
每个fork都可以拥有自己的日志文件吗?
是的,虽然你可能不需要或不想要。 最简单的方法是在文件名中的某处粘贴os.getpid()
。
或者每个记录器在写入日志时都可以独占访问吗?
有几种方法可以做到这一点,但显而易见的一种方法是在使用multiprocessing.RLock
进行logging
时替换默认的threading.RLock
。
根据文档 ,您可以通过覆盖createLock
, acquire
和release
。 所以:
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
打开文件以进行独占访问,写入和关闭,这意味着filesystem已经为你做了锁定。 (这个技巧在POSIX上不起作用,因为没有Windows风格的独占访问 - 或者说,在大多数平台和文件系统上都有等价物,但它们不可移植,你必须离开你的无论你是否愿意,都可以这样做,而不是默认获取它。)
对于CPython 2.3到3.3以及每个替代实现的所有内置处理程序的acquire
和release
实现总是如下所示:
if self.lock:
self.lock.acquire()
所以,你会看到仅通过覆盖createLock
而作弊的代码。 我自己已经多次这样做了,我已经在各种不同的第三方项目中看到了它。 但实际上,文档并不能保证,所以你应该覆盖其他两个。
@abarnert解决方案非常有效,但它需要子类化项目中使用的每个Handler。 它可以由类装饰器简化:
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.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.