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

Python可手动启停日志脚本开发及sys.args参数监听需求

Python 终端日志脚本:优雅持续运行与命令行控制

核心实现思路

针对你的需求,我们可以用命令行参数解析+信号监听/事件驱动替代生硬的while True,同时实现启动/停止的命令行控制。以下是完整的可运行代码,附带详细说明:


一、完整代码实现

import argparse
import time
import logging
import os
import signal
import sys
from threading import Event

# 配置日志与PID文件路径
LOG_FILE = "app.log"
PID_FILE = "app.pid"

# 全局停止事件(线程安全的退出标志)
stop_event = Event()

def setup_logging():
    """配置日志写入规则,以追加模式写入文件"""
    logging.basicConfig(
        filename=LOG_FILE,
        level=logging.INFO,
        format="%(asctime)s - %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S"
    )

def handle_signals(signum, frame):
    """处理系统终止信号(Ctrl+C、kill命令)"""
    logging.info("收到终止信号,准备优雅退出...")
    stop_event.set()

def start_logging():
    """启动持续日志写入服务"""
    # 检查是否已有运行实例
    if os.path.exists(PID_FILE):
        with open(PID_FILE, "r") as f:
            pid = f.read().strip()
        print(f"脚本已在运行,PID: {pid}")
        sys.exit(1)
    
    # 记录当前进程PID到文件
    with open(PID_FILE, "w") as f:
        f.write(str(os.getpid()))
    
    # 注册信号处理函数,捕捉终止信号
    signal.signal(signal.SIGINT, handle_signals)
    signal.signal(signal.SIGTERM, handle_signals)
    
    setup_logging()
    logging.info("日志服务启动成功")
    
    # 用事件驱动替代while True,支持可控退出
    while not stop_event.is_set():
        logging.info("服务持续运行中...")
        time.sleep(2)  # 模拟业务间隔,可根据需求调整
    
    # 退出前清理资源
    logging.info("日志服务已停止")
    os.remove(PID_FILE)

def stop_logging():
    """停止运行中的日志服务"""
    if not os.path.exists(PID_FILE):
        print("没有运行中的日志服务")
        sys.exit(1)
    
    with open(PID_FILE, "r") as f:
        pid = int(f.read().strip())
    
    try:
        # 发送终止信号给目标进程
        os.kill(pid, signal.SIGTERM)
        print(f"已发送停止信号到PID: {pid}")
        # 等待进程退出后清理PID文件
        time.sleep(1)
        if os.path.exists(PID_FILE):
            os.remove(PID_FILE)
    except ProcessLookupError:
        print(f"PID {pid} 不存在,已清理无效PID文件")
        os.remove(PID_FILE)
    except PermissionError:
        print(f"无权限终止PID {pid}")
        sys.exit(1)

if __name__ == "__main__":
    # 解析命令行参数
    parser = argparse.ArgumentParser(description="终端日志服务脚本")
    subparsers = parser.add_subparsers(dest="command", required=True)
    
    # 注册启动/停止子命令
    subparsers.add_parser("start", help="启动日志服务")
    subparsers.add_parser("stop", help="停止日志服务")
    
    args = parser.parse_args()
    
    if args.command == "start":
        start_logging()
    elif args.command == "stop":
        stop_logging()

二、关键优化点说明

  1. 替代while True的优雅方案
    用threading.Event作为可触发的停止标志,配合系统信号监听(SIGINT对应Ctrl+C,SIGTERM对应kill命令),实现可控的优雅退出,避免强制终止导致的资源泄漏(比如未关闭的文件句柄)。

  2. 命令行参数的规范处理
    用argparse替代直接解析sys.argv,自动生成帮助文档(运行python script.py -h即可查看),参数结构清晰,新手更容易维护。

  3. 进程实例管理
    通过PID文件记录运行中的进程ID,确保同一时间只有一个实例运行,同时stop命令可以精准定位并终止目标进程。


三、使用方法

  • 启动日志服务:
    python script.py start
    
  • 停止日志服务(新开终端执行):
    python script.py stop
    
  • 也可以直接用Ctrl+C在启动终端停止服务,脚本会自动清理PID文件并写入退出日志。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 20:17:31