Pythonic方式实现bot.py与keepalive.py的日志共享配置
Pythonic方式在bot.py和keepalive.py之间共享日志记录器
这个问题其实挺典型的——你之前尝试传递logger实例的思路走不通,核心原因是:当keepalive用subprocess重启bot时,会启动一个全新的Python进程,两个进程的内存空间完全隔离,根本没法直接传递内存中的对象。
正确的Pythonic做法是利用logging模块的原生设计:它的logger是按名称层级全局注册的,咱们只需要做集中式的日志配置,让两个脚本(包括重启后的bot进程)都加载相同的日志规则,就能实现统一的日志输出。
步骤1:创建公共日志配置模块
先写一个单独的log_config.py,把所有日志相关的配置(级别、格式、输出目标)都集中在这里,这样bot和keepalive都能复用:
import logging from logging.handlers import RotatingFileHandler import sys def setup_logger(name="bot_system"): # 获取指定名称的logger(全局唯一) logger = logging.getLogger(name) logger.setLevel(logging.INFO) # 避免重复添加处理器(比如多次调用setup_logger时) if logger.handlers: return logger # 定义日志格式:包含时间、logger名称、进程ID、级别、内容 formatter = logging.Formatter( '%(asctime)s - %(name)s - %(process)d - %(levelname)s - %(message)s' ) # 控制台输出处理器 console_handler = logging.StreamHandler(sys.stdout) console_handler.setFormatter(formatter) logger.addHandler(console_handler) # 文件输出处理器(按大小分割,避免日志文件过大) file_handler = RotatingFileHandler( 'bot_system.log', maxBytes=5*1024*1024, # 5MB backupCount=3, # 保留3个备份 encoding='utf-8' ) file_handler.setFormatter(formatter) logger.addHandler(file_handler) return logger
步骤2:在bot.py中使用日志
直接导入公共配置,获取logger即可——不管是直接运行bot,还是被keepalive启动,都会加载相同的日志规则:
from log_config import setup_logger # 获取bot专属的logger(指定名称方便区分日志来源) logger = setup_logger("bot") def main(): logger.info("Bot 启动成功!") # 这里写你的bot核心逻辑 # 比如监听某个套接字端口,供keepalive检测 # ... if __name__ == "__main__": main()
步骤3:在keepalive.py中使用日志
同样导入公共配置,获取keepalive专属的logger,这样日志里能清晰区分是keepalive还是bot的输出:
import subprocess import time import socket from log_config import setup_logger # 获取keepalive专属的logger logger = setup_logger("keepalive") # 配置bot的检测参数 BOT_CHECK_PORT = 12345 # bot需要监听这个端口,供keepalive检测 BOT_START_CMD = ["python", "bot.py"] def is_bot_alive(): """检测bot是否存活(通过套接字连接)""" try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(5) # 尝试连接bot的监听端口 connect_result = sock.connect_ex(('localhost', BOT_CHECK_PORT)) sock.close() return connect_result == 0 except Exception as e: logger.error(f"检测bot存活时出错:{str(e)}") return False def restart_bot(): """重启bot进程""" logger.warning("Bot 已离线,正在重启...") # 可选:杀掉残留的bot进程(根据实际情况处理) # ... # 启动新的bot进程 subprocess.Popen(BOT_START_CMD) logger.info("Bot 重启完成") def main(): logger.info("Keepalive 服务启动,开始监控bot状态") while True: if not is_bot_alive(): restart_bot() # 每小时检测一次 time.sleep(3600) if __name__ == "__main__": main()
为什么这是Pythonic的?
- 符合
logging模块的设计哲学:logger是全局注册的,相同名称的logger在同一个进程中是单例,不同进程通过加载相同配置保证日志规则一致。 - 遵循DRY原则:日志配置只写一次,所有脚本复用,避免重复代码。
- 解决进程隔离问题:重启后的bot进程会重新加载日志配置,不需要传递任何内存对象,完美适配keepalive的重启场景。
额外优化建议
- 如果需要更灵活的配置(比如不同环境用不同日志级别),可以用
logging.config.dictConfig把配置写成字典,或者用fileConfig从配置文件加载。 - 日志格式里的
%(process)d(进程ID)能帮你快速区分不同bot进程的日志。 - 可以根据需求调整日志轮转的大小和备份数量,避免日志文件占用过多磁盘空间。
内容的提问来源于stack exchange,提问作者user3556757
相关产品推荐
相关产品推荐

