如何格式化终止进程的异常?能否用logging模块输出JSON格式报错无需try/except?
实现方案
完全可以实现,核心思路是替换Python全局的sys.excepthook钩子捕获所有未处理异常,结合logging的自定义格式化器输出JSON结构日志,不需要修改业务代码加try/except,也不需要手动调用logging.exception。
具体实现步骤
1. 依赖安装(可选)
用第三方JSON格式化库可以简化开发,不想引入依赖也可以自己手写格式化逻辑:
pip install python-json-logger
2. 全局配置代码
只需要在程序入口位置添加如下配置即可,原有业务代码无需任何改动:
import sys import logging from pythonjsonlogger import jsonlogger # 配置logging输出 log_handler = logging.StreamHandler() # 定义JSON输出字段,可按需增减 formatter = jsonlogger.JsonFormatter( fmt="%(levelname)s %(exc_info)s %(asctime)s %(message)s", rename_fields={"levelname": "level", "exc_info": "exc_info", "asctime": "timestamp"} ) log_handler.setFormatter(formatter) root_logger = logging.getLogger() root_logger.addHandler(log_handler) root_logger.setLevel(logging.ERROR) # 自定义全局异常钩子 def global_excepthook(exc_type, exc_val, exc_tb): # 跳过键盘中断这类正常退出的异常,不需要可以删除这段 if issubclass(exc_type, KeyboardInterrupt): sys.__excepthook__(exc_type, exc_val, exc_tb) return # 传入异常信息输出日志 root_logger.error("uncaught exception", exc_info=(exc_type, exc_val, exc_tb)) sys.excepthook = global_excepthook
3. 效果验证
把你原有的业务代码放在配置后面:
# 原有业务代码无需修改 foo = 1 bar = foo + 2 raise ValueError("FIXME")
执行python foo.py后输出的日志格式如下:
{"level": "ERROR", "exc_info": "Traceback (most recent call last):\n File \"/opt/app/foo.py\", line 32, in <module>\n raise ValueError(\"FIXME\")\nValueError: FIXME", "timestamp": "2024-05-20 14:22:31,123", "message": "uncaught exception"}
注意事项
- 如果不想引入第三方依赖,可以自己继承
logging.Formatter实现自定义格式化逻辑,在format方法中手动把日志字段拼接成JSON字符串即可 - Python 3.8+版本如果用到多线程,需要额外配置
threading.excepthook捕获子线程未处理异常 - 多进程场景下需要在每个子进程启动时重新注册一遍
sys.excepthook才会生效
内容的提问来源于stack exchange,提问作者aiven
相关产品推荐
相关产品推荐

