如何修改Python logging模块的路径分隔符?兼谈跨OS适配问题
Python logging模块自定义JSON日志的路径分隔符问题
问题描述
想用Python的logging模块生成自定义JSON格式日志,需要记录pathname变量,但Windows下logging输出的路径用反斜杠\,导致JSON解析时出现Invalid escape character错误。
问题一:路径分隔符是否依赖操作系统?
是的,路径分隔符完全由操作系统决定:
- Windows系统默认使用**反斜杠
\**作为路径分隔符 - Unix类系统(Linux、macOS等)默认使用**正斜杠
/**作为路径分隔符
代码部署到Unix系统后,pathname会自动使用正斜杠,不会出现JSON转义问题,但Windows环境下需要手动处理。
问题二:如何修改分隔符解决JSON错误?
可以通过两种方式处理,目标是将路径中的反斜杠替换为正斜杠,或者转义为双反斜杠(符合JSON语法要求):
测试代码
config.json
{ "version": 1, "disable_existing_loggers": true, "formatters": { "standard": { "format": "{\"timestamp\":%(created)f,\"time\":\"%(asctime)s\",\"path\":\"%(pathname)s\",\"file\":\"%(filename)s\",\"line\":%(lineno)d,\"level\":\"%(levelname)s\",\"text\":\"%(message)s\"}", "datefmt": "%Y/%m/%d-%H:%M:%S" } }, "handlers": { "console": { "class": "logging.StreamHandler", "formatter": "standard", "level": "DEBUG", "stream": "ext://sys.stdout" } }, "loggers": { "": { "handlers": ["console"], "level": "DEBUG", "propagate": false } } }
example.py
import logging import json import logging.config with open("./config.json", "r", encoding="UTF_8") as file: config = json.load(file) logging.config.dictConfig(config) logger = logging.getLogger(__name__) logger.info("This is an info log.")
当前输出(Windows下)
{"timestamp":1726603464.416349,"time":"2024/09/17-23:34:24","path":"d:\python\project\example.py","file":"example.py","line":9,"level":"INFO","text":"This is an info log."}
期望输出
# 方式一:转义成双反斜杠 {"timestamp":1726603464.416349,"time":"2024/09/17-23:34:24","path":"d:\\python\\project\\example.py","file":"example.py","line":9,"level":"INFO","text":"This is an info log."} # 方式二:替换为正斜杠 {"timestamp":1726603464.416349,"time":"2024/09/17-23:34:24","path":"d:/python/project/example.py","file":"example.py","line":9,"level":"INFO","text":"This is an info log."}
解决方案
方案1:自定义Formatter类处理路径分隔符
创建自定义Formatter,在格式化日志时替换路径中的反斜杠:
import logging import json import logging.config class JsonFormatter(logging.Formatter): def format(self, record): # 替换反斜杠为正斜杠,若要转成双反斜杠则用replace("\\", "\\\\") record.pathname = record.pathname.replace("\\", "/") return super().format(record) # 加载配置并替换formatter with open("./config.json", "r", encoding="UTF_8") as file: config = json.load(file) logging.config.dictConfig(config) # 为所有handler设置自定义Formatter for handler in logging.getLogger().handlers: handler.setFormatter(JsonFormatter( fmt=config["formatters"]["standard"]["format"], datefmt=config["formatters"]["standard"]["datefmt"] )) logger = logging.getLogger(__name__) logger.info("This is an info log.")
方案2:用json.dumps生成合法JSON(推荐)
避免手动拼接JSON字符串,直接构造字典后用json.dumps序列化,自动处理转义:
import logging import json import logging.config class JsonFormatter(logging.Formatter): def format(self, record): log_dict = { "timestamp": record.created, "time": self.formatTime(record, self.datefmt), "path": record.pathname.replace("\\", "/"), # 替换为正斜杠,去掉该行则json.dumps自动转义反斜杠 "file": record.filename, "line": record.lineno, "level": record.levelname, "text": record.getMessage() } return json.dumps(log_dict) # 简化配置,无需在config中写JSON字符串 config = { "version": 1, "disable_existing_loggers": True, "handlers": { "console": { "class": "logging.StreamHandler", "level": "DEBUG", "stream": "ext://sys.stdout" } }, "loggers": { "": { "handlers": ["console"], "level": "DEBUG", "propagate": False } } } logging.config.dictConfig(config) for handler in logging.getLogger().handlers: handler.setFormatter(JsonFormatter(datefmt="%Y/%m/%d-%H:%M:%S")) logger = logging.getLogger(__name__) logger.info("This is an info log.")
该方案避免了手动拼接JSON的转义错误,稳定性更高。
内容的提问来源于stack exchange,提问作者Aria AAs
相关产品推荐
相关产品推荐

