我有一个分叉Gunicorn环境中运行的应用程序瓶,但踪迹在日志文件中得到交错。 每个叉都可以有自己的日志文件? 或者可以每个记录有独家访问,同时写入日志?
Answer 1:
每个叉都可以有自己的日志文件?
是的,虽然你可能不需要,或者想,那个。 要做到这一点最简单的方法是只要坚持os.getpid()
某处的文件名。
或者可以每个记录有独家访问,同时写入日志?
有几个方法可以做到这一点,但明显的是只需更换默认threading.RLock
中logging
了multiprocessing.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
打开进行独占访问文件,写和关闭,这意味着文件系统已经在做你锁定你。 (这招不会对POSIX因为因为没有这种东西的工作Windows风格的独家访问,或者说,有在大多数平台和文件系统等价,但它们不是便携式的,你必须走出去的你办法做到这一点,而不是默认情况下,无论你想不想要得到它的。)
实施acquire
和release
为CPython的2.3至3.3所有内置处理器和每隔实施一直只是被这样的:
if self.lock:
self.lock.acquire()
所以,你会看到,仅覆盖作弊代码createLock
。 我已经是多次做我自己,我已经在各种不同的第三方项目看到它。 不过说真的,文档并不能保证,所以你应该重写其他两个为好。
Answer 2:
@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.