2012-11-01 60 views
11

我发现的用于在Python中创建守护进程的每个配方都涉及分叉两次(对于Unix),然后关闭所有打开的文件描述符。 (例如http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/)。在Python守护进程中维护日志记录和/或标准输出/ stderr

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

什么是正确的方式来设置日志,使它在守护进程后继续工作?在守护进程之后,我是否第二次调用logging.basicConfig()?什么是正确的方式来捕获stdoutstderr?我对所有文件为什么关闭的细节都很模糊。理想情况下,我的主要代码可以调用daemon_start(pid_file)并且日志记录将继续工作。

+1

呼叫日志记录配置后daemonizing确实是要走的路。 – Exelian

+1

我在日志记录文档中注意到了这个注释:“如果根日志记录器已经为它配置了处理程序,则此函数不会执行任何操作。”如果我想在守护进程之前和之后进行日志记录,那么这是如何影响情况的? –

+1

如果我是正确的,可以在初始化记录器后添加处理程序/过滤器。这意味着您可以在启动守护程序上下文之前添加FileHandler,并在启动守护程序之后添加另一个文件句柄。我不完全确定这个工程虽然。 – Exelian

回答

17

我使用python-daemon库进行守护程序行为。

接口描述这里:

实现此:

它允许指定files_preserve参数,用于指示任何文件描述符,应该在守护进程时关闭而不是

如果你需要之前和之后daemonizing通过相同Handler情况下登录,您可以:

  1. 首先设置你的日志处理程序使用basicConfigdictConfig或什么的。
  2. 日志文件
  3. 确定您的Handlers依赖于哪些文件描述符。不幸的是,这取决于Handler子类。如果您的第一个安装的HandlerStreamHandler,则它的值为logging.root.handlers[0].stream.fileno();如果您的第二个安装的HandlerSyslogHandler,则需要值logging.root.handlers[1].socket.fileno();等等,这是凌乱:-(
  4. 守护进程的过程中通过创建files_preserve等于文件描述符的列表DaemonContext您在步骤3
  5. 确定继续记录;你的日志文件不应该在关闭双叉。

另一种可能是,作为@Exelian建议,实际上Handler实例之前和之后daemonziation使用不同。daemonizing后,立即销毁现存的处理器(由荷兰国际集团del他们logger.root.handlers?)和创建相同的新的;因为你不能只是重新呼叫basicConfig @ dave-mankoff指出的问题。

+0

这个答案是救命的,谢谢! – Drachenfels

7

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

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.") 
+0

请记住调用['context.close()'](https://pagure.io/python-daemon/blob/master/f/daemon/daemon.py#_400)或使用['with'](https: //docs.python.org/3/reference/compound_stmts.html#the-with-statement)声明。 –

4

我们刚刚也有类似的问题,因为我无法控制的一些东西,守护的东西是从东西创造了记录器分开。然而,记录仪具有.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 
+0

此解决方案可用于守护python自定义管理命令。 – phicou

相关问题