在Python守护程序中维护日志记录和/或stdout/stderr

dav*_*off 16 python logging fork daemon

我在Python中创建守护进程的每个配方都涉及两次(对于Unix),然后关闭所有打开的文件描述符.(有关示例,请参阅http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/).

这很简单,但我似乎有一个问题.在我正在设置的生产机器上,我的守护程序正在中止 - 因为所有打开的文件描述符都已关闭,所以它是静默的.我正在调试当前问题的棘手时间,并且想知道捕获和记录这些错误的正确方法是什么.

设置日志记录的正确方法是什么,以便在守护进程后继续工作?logging.basicConfig()在守护进程后我第二次打电话吗?什么是捕捉到正确的方式stdoutstderr?我对所有文件关闭的细节很模糊.理想情况下,我的主要代码可能只是调用daemon_start(pid_file)和日志记录将继续工作.

Max*_*y-B 18

我使用该python-daemon库来实现我的守护行为.

这里描述的接口:

在这里实施:

它允许指定一个files_preserve参数,以指示在守护进程时应该关闭的任何文件描述符.

如果您需要在daemonizing之前和之后通过相同的 Handler实例进行日志记录,您可以:

  1. 首先使用设置你的日志处理程序basicConfigdictConfig或什么的.
  2. 记录东西
  3. 确定您所Handler依赖的文件描述符.不幸的是,这取决于Handler子类.如果您的首次安装Handler是a StreamHandler,那么它的值是logging.root.handlers[0].stream.fileno(); 如果你的第二个安装Handler是a SyslogHandler,你想要的值logging.root.handlers[1].socket.fileno(); 这是凌乱的:-(
  4. 通过创建一个守护进程的过程中DaemonContextfiles_preserve等于你在步骤3中确定的文件描述符的列表.
  5. 继续记录; 在双分叉期间,您的日志文件不应该被关闭.

正如@Exelian建议的那样,另一种方法可能是在守护程序Handler之前和之后实际使用不同的实例.在守护进程之后,立即销毁现有的处理程序(通过del它们logger.root.handlers?)并创建相同的新处理程序; basicConfig由于@ dave-mankoff指出的问题,你不能只是重新打电话.


mpo*_*ett 9

如果您将记录处理程序对象与根记录器对象分开设置,然后将处理程序对象作为独立步骤添加,而不是一次性完成所有操作,则可以简化此代码.以下内容适合您.

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." )
Run Code Online (Sandbox Code Playgroud)


Tom*_*Kid 5

我们遇到了类似的问题,由于一些我无法控制的事情,守护进程的东西与创建记录器的东西是分开的.但是,logger具有.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
Run Code Online (Sandbox Code Playgroud)