Python

[Python] python-daemon에서 logging 모듈로 로그 파일 작성하기

메바동 2023. 1. 10. 21:44
728x90

지난 포스팅에 작성했던 python-daemon 패키지를 이용한 데몬 프로세스에서 로그 작성을 txt 파일을 열어 작성하는 것이 아닌 logging 모듈을 이용해서 로그를 작성하려고 하였다.

 

import daemon
from daemon.pidfile import PIDLockFile

import logging
import time

log_path = '{파일 경로}/pydaemon.log'


logging.basicConfig(filename=log_path, encoding='utf-8', level=logging.DEBUG,
                    format='[%(asctime)s][%(levelname)s] %(message)s', datefmt='%Y/%m/%d %p %l:%M:%S')
log = logging.getLogger('pydaemon')


def main_program():
    while True:
        log.info('pydaemon write.')
        time.sleep(5)


pid_lock_file = PIDLockFile(
    '{파일 경로}/pydaemon.pid')
if pid_lock_file.is_locked():
    log.error('pydaemon is already running')
    exit(1)

context = daemon.DaemonContext(
    working_directory='{파일 경로}/pydaemon',
    umask=0o002,
    pidfile=pid_lock_file,
)


with context:
    main_program()

 

그래서 기존에 있던 코드를 위와 같이 수정하여 실행하였는데

 

 

위와 같이 데몬 프로세스가 실행되고 있음에도 pydaemon.log에는 아무런 내용이 작성되고 있지 않았다.

 

어째서 pydaemon.log에 내용이 작성되지 않을까 하고 찾아보다가 PEP 3143 문서를 읽다가 답을 알게 되었다.

해당 파일에서는 유닉스 데몬 프로세스가 되기 위한 조건은 다음과 같다고 한다.

 

  • 열려 있는 모든 파일 설명자(file descriptors)를 닫는다.
  • 현재 작업 디렉터리를 변경한다.
  • file access creation mask를 재설정한다.
  • 백그라운드에서 실행된다.
  • 프로세스 그룹과 분리한다.
  • 터미널 I/O 신호를 무시한다.
  • 제어 터미널과 분리한다.
  • 제어 터미널을 다시 획득하지 않는다.
  • 다음과 같은 상황을 올바르게 처리
    • System V init 프로세스에 의해 시작된다.
    • SIGTERM 신호에 의해 데몬이 종료된다.
    • 자식 프로세스가 SIGCLD 신호를 생성한다.

 

여기서 pydaemon.log에 내용이 작성되지 않는 이유는 1번 항목에 의해서 daemonize 될 때 pydaemon.log 파일을 닫기 때문에 로그를 작성하지 않는 것이었다.

 

python-deamon은 데몬이 시작될 때 닫지 않을 파일을 지정하기 위해 DaemonContext의 인수 중에 files_preserve이라는 항목에 파일을 지정하면 파일을 닫지 않도록 지정할 수 있다.

 

log_path = '{파일 경로}/pydaemon.log'
log_formatter = logging.Formatter(
    fmt='[%(asctime)s][%(levelname)s] %(message)s', datefmt='%Y/%m/%d %p %l:%M:%S')

log = logging.getLogger('pydaemon')
log.setLevel(logging.DEBUG)

log_handler = logging.FileHandler(log_path)
log_handler.setLevel(logging.DEBUG)
log_handler.setFormatter(log_formatter)

log.addHandler(log_handler)

 

위와 같이 로그 핸들러를 만들어 준 뒤, 

 

context = daemon.DaemonContext(
    working_directory='/',
    umask=0o002,
    pidfile=pid_lock_file,
    files_preserve=[
        log_handler.stream.fileno(),
    ],
)

 

해당 로그 핸들러의 stream.fileno()를 사용하여 파일 설명자를 배열로 전달하면 다음과 같이 pydaemon.log에 내용이 정상적으로 작성되는 것을 확인할 수 있다.

 

728x90