2012-11-01 59 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

相關問題