Quando scrivo un demone Python prendo tutte le eccezioni e poi lancio il file di registro. Non solo uso per il debug, ma anche in produzione. Ho una piccola sceneggiatura che eseguo ogni mattina che cerca qualcosa di sconvolgente nei registri.
Naturalmente aiuta anche a far funzionare il demone.
Qualche codice di esempio (rimuovo le parti non interessanti):
import logging
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO,
format='%(asctime)s %(levelname)s %(message)s',
filename=LOG_FILE,
filemode='w')
logging.info("Sincrod inicializado")
if not DEBUG:
daemonize()
while True:
try:
actua()
except:
logging.error(sys.exc_info())
if (datetime.datetime.now().hour > NOITE_EMPEZA\
and datetime.datetime.now().hour < NOITE_REMATA):
time.sleep(INTERVALO_NOITE)
else:
time.sleep(INTERVALO_DIA)
Dove actua () è il vero demone (scrive anche per accedere). Nota che ho anche una variabile DEBUG in un file di impostazioni, quando è True, non eseguo il fork del demone, quindi viene eseguito sulla console.
Demoni
I demoni sono l'equivalente unix dei servizi di Windows. Sono processi eseguiti in background indipendenti da altri processi. Ciò significa che il loro padre è di solito init e che sono distaccati da qualsiasi tty. Poiché sono indipendenti, non esiste un luogo predefinito in cui inserire il proprio output.
Ci sono molte librerie e frammenti di pitone per creare un demone, nell'esempio sopra uso la mia funzione, che combina alcune idee delle versioni di Steinar Knutsens e Jeff Kunces. È il più semplice possibile, nota che forzo due volte .
def daemonize():
"""Forks this process creating a daemon and killing the original one"""
if (not os.fork()):
# get our own session and fixup std[in,out,err]
os.setsid()
sys.stdin.close()
sys.stdout = NullDevice()
sys.stderr = NullDevice()
if (not os.fork()):
# hang around till adopted by init
ppid = os.getppid()
while (ppid != 1):
time.sleep(0.5)
ppid = os.getppid()
else:
# time for child to die
os._exit(0)
else:
# wait for child to die and then bail
os.wait()
sys.exit()