如何配置Ray以在多进程中使用标准Python Logger?
问题
尝试用Ray提升进程运行速度,希望将日志消息传递给标准Python Logger,实现日志的格式化、过滤与存储。但使用Ray时,日志未按自定义Logger配置格式化,也未传递至根Logger。已在ray.init()中设置log_to_driver=True和configure_logging=True,问题仍存在。
复现代码
from ray.util.multiprocessing import Pool import pathlib import logging import json def setup_logging(config_file: pathlib.Path): with open(config_file) as f_in: config = json.load(f_in) logging.config.dictConfig(config) logger = logging.getLogger(__name__) config_file = pathlib.Path(__file__).parent / "log_setup/config_logging.json" setup_logging(config_file=config_file) def f(index): logger.warning(f"index: {index}") return (index, "model") if __name__ == "__main__": logger.warning("Starting") pool = Pool(1) results = pool.map(f, range(10)) print(list(results))
Logger配置文件(log_setup/config_logging.json)
{ "version": 1, "disable_existing_loggers": false, "formatters": { "detailed": { "format": "[%(levelname)s|%(name)s|%(module)s|L%(lineno)d] %(asctime)s: %(message)s", "datefmt": "%Y-%m-%dT%H:%M:%S%z" } }, "handlers": { "stdout": { "class": "logging.StreamHandler", "level": "INFO", "formatter": "detailed" } }, "loggers": { "root": { "level": "DEBUG", "handlers": [ "stdout" ] } } }
输出对比
Python原生map输出
[WARNING|__main__|ray_trial|L28] 2024-03-27T15:14:21+0100: Starting [WARNING|__main__|ray_trial|L22] 2024-03-27T15:14:21+0100: index: 0 [WARNING|__main__|ray_trial|L22] 2024-03-27T15:14:21+0100: index: 1 [WARNING|__main__|ray_trial|L22] 2024-03-27T15:14:21+0100: index: 2 [WARNING|__main__|ray_trial|L22] 2024-03-27T15:14:21+0100: index: 3 [WARNING|__main__|ray_trial|L22] 2024-03-27T15:14:21+0100: index: 4 [WARNING|__main__|ray_trial|L22] 2024-03-27T15:14:21+0100: index: 5 [WARNING|__main__|ray_trial|L22] 2024-03-27T15:14:21+0100: index: 6 [WARNING|__main__|ray_trial|L22] 2024-03-27T15:14:21+0100: index: 7 [WARNING|__main__|ray_trial|L22] 2024-03-27T15:14:21+0100: index: 8 [WARNING|__main__|ray_trial|L22] 2024-03-27T15:14:21+0100: index: 9
Ray Pool输出
2024-03-27 14:54:55,064 INFO worker.py:1743 -- Started a local Ray instance. View the dashboard at 127.0.0.1:8265 (PoolActor pid=43261) index: 0 (PoolActor pid=43261) index: 1 (PoolActor pid=43261) index: 2 (PoolActor pid=43261) index: 3 (PoolActor pid=43261) index: 4 (PoolActor pid=43261) index: 5 (PoolActor pid=43261) index: 6 (PoolActor pid=43261) index: 7 (PoolActor pid=43261) index: 8 (PoolActor pid=43261) index: 9
解决方案
Ray的进程(包括Pool中的Actor)是独立的Python进程,主进程的日志配置不会自动传递到子进程,且Ray默认会覆盖部分日志设置,需从以下几个方面调整:
1. 在Ray子进程中重新初始化日志配置
Ray启动的子进程不会继承主进程的日志配置,需在任务函数内部重新加载日志配置:
修改任务函数f:
def f(index): # 子进程中重新初始化日志 config_file = pathlib.Path(__file__).resolve().parent / "log_setup/config_logging.json" setup_logging(config_file=config_file) logger = logging.getLogger(__name__) # 重新获取Logger实例 logger.warning(f"index: {index}") return (index, "model")
2. 禁用Ray的默认日志配置
在初始化Ray时,关闭自动日志配置,避免Ray覆盖自定义设置:
if __name__ == "__main__": import ray # 禁用Ray默认日志配置,避免干扰自定义Logger ray.init(configure_logging=False, log_to_driver=False) logger.warning("Starting") pool = Pool(1) results = pool.map(f, range(10)) print(list(results))
log_to_driver=False会关闭Ray默认的日志转发,确保日志完全由自定义Logger处理。
3. 使用Ray日志适配器保留进程标识
如果需要保留Ray的进程标识(如(PoolActor pid=xxx)),同时应用自定义格式,可以使用RayLoggerAdapter包装Logger:
from ray.util.log import RayLoggerAdapter def f(index): config_file = pathlib.Path(__file__).resolve().parent / "log_setup/config_logging.json" setup_logging(config_file=config_file) logger = logging.getLogger(__name__) # 包装成Ray日志适配器,保留进程信息 ray_logger = RayLoggerAdapter(logger, {"actor_name": "PoolActor"}) ray_logger.warning(f"index: {index}") return (index, "model")
内容的提问来源于stack exchange,提问作者gabrown86
相关产品推荐
相关产品推荐

