You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python守护进程日志仅在__init__生效,如何修复并复用Logger?

Fixing Logging in Python Daemon's Child Class run Method

Got it, let's break down why your logs only work in the parent Daemon class's __init__ method but not in the child class's run method, and how to fix this while reusing your logger.

The Root Cause

Most daemon implementations perform two forks and then close all open file descriptors to detach from the parent process and terminal. If you set up your logging handler in the parent class's __init__ which runs before daemonization, the file descriptor for your application.log gets closed during the daemon's cleanup process. That's why your run method which executes after daemonization can't write to the log anymore—its handler is pointing to a closed file descriptor.

Step-by-Step Solution

We'll adjust when we set up the logger to ensure it happens after the daemon has finished cleaning up file descriptors, and we'll make sure the logger is reusable across the parent and child classes.

1. Modify the Parent Daemon Class

Move the logging setup out of __init__ into a dedicated method, and call this method after the daemon is fully initialized post-fork and file descriptor cleanup:

import os
import sys
import logging
import resource
import time

class Daemon:
    def __init__(self, pidfile, logfile='application.log'):
        self.pidfile = pidfile
        self.logfile = logfile
        # Don't set up logging here—we'll do it later
        self.logger = None

    def setup_logging(self):
        """Initialize logger once after daemonization"""
        self.logger = logging.getLogger('daemon_logger')
        self.logger.setLevel(logging.INFO)
        
        # Prevent duplicate handlers if setup is called multiple times
        if not self.logger.handlers:
            formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
            # Create file handler AFTER daemonization so its FD isn't closed
            file_handler = logging.FileHandler(self.logfile)
            file_handler.setFormatter(formatter)
            self.logger.addHandler(file_handler)

    def start(self):
        # First fork: detach from parent process
        try:
            pid = os.fork()
            if pid > 0:
                sys.exit(0)
        except OSError as e:
            sys.stderr.write(f"First fork failed: {e}\n")
            sys.exit(1)

        # Set new session and umask
        os.setsid()
        os.umask(0)

        # Second fork: ensure daemon can't reattach to terminal
        try:
            pid = os.fork()
            if pid > 0:
                sys.exit(0)
        except OSError as e:
            sys.stderr.write(f"Second fork failed: {e}\n")
            sys.exit(1)

        # Close all open file descriptors
        for fd in range(resource.getrlimit(resource.RLIMIT_NOFILE)[0]):
            try:
                os.close(fd)
            except OSError:
                pass

        # Redirect stdin/stdout/stderr to /dev/null
        sys.stdin = open('/dev/null', 'r')
        sys.stdout = open('/dev/null', 'w')
        sys.stderr = open('/dev/null', 'w')

        # NOW set up logging after FD cleanup
        self.setup_logging()
        # Call the child class's run method
        self.run()

    # Add standard daemon methods like stop/restart as needed
    def stop(self):
        # Your stop logic here
        pass

    def restart(self):
        self.stop()
        self.start()

2. Update the Child MyDaemon Class

Now you can directly use the pre-configured logger in your run method without redefining anything:

class MyDaemon(Daemon):
    def run(self):
        # Use the logger from the parent class
        self.logger.info("MyDaemon run method started successfully!")
        # Your daemon logic here
        while True:
            self.logger.debug("Daemon is running...")
            # Example work task
            time.sleep(5)

3. Verify Real-Time Logging

Once your daemon is running, you can use tailf or tail -f to watch the logs in real time:

tailf application.log

Key Notes

  • No Duplicate Handlers: The check if not self.logger.handlers: ensures we don't add multiple file handlers if setup_logging is called more than once e.g., during restarts.
  • File Permissions: Make sure the user running the daemon has write permissions for application.log e.g., if it's in /var/log, you might need to adjust ownership or permissions.
  • Avoid Print Statements: Since we redirect stdout/stderr to /dev/null, any print calls in your daemon won't show up—always use self.logger instead.

内容的提问来源于stack exchange,提问作者Yener

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:46:57