我有一个在分叉的Gunicorn环境中运行的Flask应用程序,但堆栈跟踪在日志文件中交叉存取。每个fork都可以拥有自己的日志文件吗?或者每个记录器在写入日志时都可以独占访问吗?
答案 0 :(得分:3)
每个fork都可以拥有自己的日志文件吗?
是的,虽然您可能不需要或不想要。最简单的方法是在文件名中的某处粘贴os.getpid()
。
或者每个记录器在写入日志时都可以独占访问吗?
有几种方法可以做到这一点,但显而易见的方法是用threading.RLock
替换logging
中的默认multiprocessing.RLock
。
根据the docs,您可以通过覆盖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
会打开文件进行独占访问,写入和关闭,这意味着文件系统已经在为您锁定。 (这个技巧在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])