
本文介绍如何从 json 文件中正确读取日志级别(如 `"logging.info"`),并将其转换为 `logging` 模块可识别的整数值,避免因字符串未解析导致的 `valueerror: unknown level` 错误。
在实际项目中,将日志级别(如 INFO、DEBUG)写入 JSON 配置文件是一种常见做法,但直接读取后传给 logger.setLevel() 会引发问题——因为 JSON 解析出的值始终是字符串(例如 "logging.INFO"),而 setLevel() 期望的是整数常量(如 logging.INFO == 20)或标准级别字符串(如 "INFO")。若强行传入 "logging.INFO",Python 不会自动执行字符串求值,而是抛出 ValueError: Unknown level: 'logging.INFO'。
✅ 推荐方案:映射字典(安全、清晰、可维护)
最安全且符合 Python 最佳实践的方式是预定义一个字符串到日志级别常量的映射字典,而非使用 eval() 或 getattr() 动态解析模块属性(后者存在安全隐患和可读性风险):
import logging
# 定义合法日志级别映射(支持带/不带 'logging.' 前缀)
LOG_LEVEL_MAP = {
"DEBUG": logging.DEBUG,
"INFO": logging.INFO,
"WARNING": logging.WARNING,
"WARN": logging.WARNING, # 别名兼容
"ERROR": logging.ERROR,
"CRITICAL": logging.CRITICAL,
"FATAL": logging.CRITICAL,
# 如需支持旧式写法(不推荐):
"logging.DEBUG": logging.DEBUG,
"logging.INFO": logging.INFO,
"logging.WARNING": logging.WARNING,
"logging.ERROR": logging.ERROR,
"logging.CRITICAL": logging.CRITICAL,
}
# 加载配置
with open("export_tool_config.json", "r") as f:
config = json.load(f)
log_level_str = config.get("loglevel", "INFO") # 默认 INFO,增强健壮性
if log_level_str not in LOG_LEVEL_MAP:
raise ValueError(f"Unsupported log level: {log_level_str!r}. "
f"Supported: {list(LOG_LEVEL_MAP.keys())}")
logger = logging.getLogger(__name__)
logger.setLevel(LOG_LEVEL_MAP[log_level_str])⚠️ 注意事项与最佳实践
- 禁止使用 eval() 或 exec():虽然 eval("logging.INFO") 在技术上可行,但它会执行任意代码,严重违背配置即数据的安全原则,一旦配置被篡改或注入恶意字符串(如 "__import__('os').system('rm -rf /')"),将导致远程代码执行(RCE)。
-
优先使用标准字符串级别:logging 模块原生支持 "INFO"、"DEBUG" 等字符串(见 官方文档),因此 JSON 中应首选:
{ "loglevel": "INFO" }这样可直接调用 logger.setLevel(config["loglevel"]),无需额外映射——更简洁、更安全、更符合惯例。
- 添加错误处理与默认值:使用 .get("loglevel", "INFO") 避免 KeyError;校验输入值是否存在映射,提前失败(fail-fast),便于调试。
- 扩展性考虑:如需支持自定义级别,可在 LOG_LEVEL_MAP 中添加对应键值对,并确保所有日志器初始化前完成注册。
✅ 总结
从 JSON 读取日志级别时,核心原则是解耦配置与执行:配置只负责声明意图(如 "INFO"),代码负责安全、明确地将其转化为运行时值。通过静态映射字典,你既能保持配置灵活性,又能杜绝动态求值风险,同时提升代码可读性与可维护性。强烈建议在 JSON 中采用 "INFO" 形式,并在代码中做健壮性校验——这才是生产环境推荐的工程化方案。
立即学习“Python免费学习笔记(深入)”;









