在Python守护进程中维护日志记录和/或stdout/stderr
我发现在Python中创建守护进程的每一个方法都涉及两次分叉(对于Unix),然后关闭所有打开的文件描述符。(参见示例) 这一切都很简单,但我似乎有一个问题。在我正在设置的生产机器上,我的守护进程正在中止,因为所有打开的文件描述符都已关闭。我目前在调试这个问题时遇到了一个棘手的问题,我想知道捕捉和记录这些错误的正确方法是什么在Python守护进程中维护日志记录和/或stdout/stderr,python,logging,fork,daemon,Python,Logging,Fork,Daemon,我发现在Python中创建守护进程的每一个方法都涉及两次分叉(对于Unix),然后关闭所有打开的文件描述符。(参见示例) 这一切都很简单,但我似乎有一个问题。在我正在设置的生产机器上,我的守护进程正在中止,因为所有打开的文件描述符都已关闭。我目前在调试这个问题时遇到了一个棘手的问题,我想知道捕捉和记录这些错误的正确方法是什么 什么是设置日志的正确方法,以便它在后台监控后继续工作?在后台监控之后,我是否需要再次调用logging.basicConfig()?捕获stdout和stderr的正确方法
什么是设置日志的正确方法,以便它在后台监控后继续工作?在后台监控之后,我是否需要再次调用
logging.basicConfig()
?捕获stdout
和stderr
的正确方法是什么?我不清楚为什么所有文件都关闭了。理想情况下,我的主代码可以只调用守护进程\u start(pid\u文件)
,日志记录将继续工作。我使用python守护进程库进行守护行为
此处描述的接口:
在这里实施:
它允许指定files\u preserve
参数,以指示在后台监控时不应关闭的任何文件描述符
如果在后台监控之前和之后需要通过相同的处理程序实例进行日志记录,则可以:
首先,使用basicConfig
或dictConfig
或其他方法设置日志处理程序
原木
确定处理程序所依赖的文件描述符。不幸的是,这依赖于处理程序
子类。如果您第一次安装的处理程序
是流处理程序
,则它是logging.root.handlers[0].stream.fileno()的值
;如果第二个安装的处理程序是SyslogHandler
,则需要logging.root.handlers[1].socket.fileno()
;等等,这很混乱:-(
通过创建一个DaemonContext
,并将files\u preserve
与您在步骤3中确定的文件描述符列表相等,来监控您的进程
继续日志记录;您的日志文件不应在双分叉期间关闭
另一种方法可能是,正如@Exelian所建议的,在守护进程之前和之后实际使用不同的处理程序
实例。在守护进程之后,立即销毁现有的处理程序(通过del
从logger.root.handlers
?)并创建相同的新对象;由于@dave mankoff指出的问题,您不能只重新调用basicConfig
。如果您将日志处理程序对象与根日志记录器对象分开设置,然后将处理程序对象作为一个独立步骤添加,而不是一次性全部添加,则可以简化代码e、 以下内容应该适合您
import daemon
import logging
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
fh = logging.FileHandler("./foo.log")
logger.addHandler(fh)
context = daemon.DaemonContext(
files_preserve = [
fh.stream,
],
)
logger.debug( "Before daemonizing." )
context.open()
logger.debug( "After daemonizing." )
我们刚刚遇到了一个类似的问题,由于一些事情超出了我的控制范围,守护进程的内容与创建记录器的内容是分开的。但是,记录器有一个.handlers和.parent属性,这使得以下内容成为可能:
self.files_preserve = self.getLogFileHandles(self.data.logger)
def getLogFileHandles(self,logger):
""" Get a list of filehandle numbers from logger
to be handed to DaemonContext.files_preserve
"""
handles = []
for handler in logger.handlers:
handles.append(handler.stream.fileno())
if logger.parent:
handles += self.getLogFileHandles(logger.parent)
return handles
在后台监控之后调用日志配置确实是一种方法。我注意到日志文档中有这样一条评论:“如果根日志记录器已经为该函数配置了处理程序,则该函数不会执行任何操作。”如果我想在守护进程之前和之后进行日志记录,这会对情况产生什么影响?如果我是正确的,那么可以在初始化日志记录程序之后添加处理程序/过滤器。这意味着您可以在启动守护进程上下文之前添加一个FileHandler,在启动守护进程上下文之后添加另一个FileHandler。不过,我不能完全确定这是否有效。@Exelian谢谢,您是一个终身的守护进程aver!此解决方案与后台监控python自定义管理命令配合使用。请记住调用或使用语句。