Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python守护进程中维护日志记录和/或stdout/stderr_Python_Logging_Fork_Daemon - Fatal编程技术网

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

在Python守护进程中维护日志记录和/或stdout/stderr,python,logging,fork,daemon,Python,Logging,Fork,Daemon,我发现在Python中创建守护进程的每一个方法都涉及两次分叉(对于Unix),然后关闭所有打开的文件描述符。(参见示例) 这一切都很简单,但我似乎有一个问题。在我正在设置的生产机器上,我的守护进程正在中止,因为所有打开的文件描述符都已关闭。我目前在调试这个问题时遇到了一个棘手的问题,我想知道捕捉和记录这些错误的正确方法是什么 什么是设置日志的正确方法,以便它在后台监控后继续工作?在后台监控之后,我是否需要再次调用logging.basicConfig()?捕获stdout和stderr的正确方法

我发现在Python中创建守护进程的每一个方法都涉及两次分叉(对于Unix),然后关闭所有打开的文件描述符。(参见示例)

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


什么是设置日志的正确方法,以便它在后台监控后继续工作?在后台监控之后,我是否需要再次调用
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自定义管理命令配合使用。请记住调用或使用语句。