18

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

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

设置日志记录以使其在守护进程后继续工作的正确方法是什么?我只是logging.basicConfig()在守护进程后第二次调用吗?stdout捕获和的正确方法是什么stderr?我不清楚为什么所有文件都被关闭的细节。理想情况下,我的主要代码可以调用daemon_start(pid_file)并且日志记录将继续工作。

4

3 回答 3

20

我将该python-daemon库用于我的守护进程行为。

此处描述的接口:

这里的实现:

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

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

  1. basicConfig首先使用or或其他设置您的日志记录处理程序dictConfig
  2. 记录东西
  3. Handler确定您的 s 所依赖的文件描述符。不幸的是,这取决于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之前和之后实际使用不同的实例。在守护进程之后,立即销毁现有的处理程序(通过dellogger.root.handlers?)并创建相同的新处理程序;basicConfig由于@dave-mankoff 指出的问题,您不能只是重新打电话。

于 2012-12-04T05:01:26.113 回答
10

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

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." )
于 2013-03-11T00:07:40.613 回答
5

We just had a similar issue, and due to some things beyond my control, the daemon stuff was separate from the stuff creating the logger. However, logger has a .handlers and .parent attributes that make it possible with something like:

    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
于 2014-06-19T03:38:21.927 回答