Python 中如何以 JSON 格式输出日志?
Python 输出 JSON 格式日志的方法:json-logging 库、python-json-logger 库、或自定义 logging.Formatter。本文对比三种方案及各自的适用场景。
三种主流方式:json-logging 库(最简单,一行初始化)、python-json-logger 库(formatter 替换,灵活)、自定义 logging.Formatter(无第三方依赖,完全可控)。
方法一:json-logging 库
pip install json-logging
import logging, json_logging
json_logging.init_non_web(enable_json=True)
logging.info("这是一条 JSON 日志")
Web 框架用对应的初始化函数:json_logging.init_flask()、init_sanic() 等。
方法二:python-json-logger 库
pip install python-json-logger
import logging
from pythonjsonlogger import jsonlogger
handler = logging.StreamHandler()
handler.setFormatter(jsonlogger.JsonFormatter(
'%(asctime)s %(name)s %(levelname)s %(message)s'
))
logger = logging.getLogger()
logger.addHandler(handler)
logger.setLevel(logging.INFO)
logger.info("用户登录", extra={"user_id": 42, "ip": "1.2.3.4"})
extra 传入的字段会成为 JSON 的顶层字段。
方法三:自定义 Formatter(无依赖)
import logging, json
from datetime import datetime, timezone
class JsonFormatter(logging.Formatter):
def format(self, record):
log = {
"time": datetime.now(timezone.utc).isoformat(),
"level": record.levelname,
"logger": record.name,
"message": record.getMessage(),
}
if record.exc_info:
log["exception"] = self.formatException(record.exc_info)
return json.dumps(log, ensure_ascii=False)
handler = logging.StreamHandler()
handler.setFormatter(JsonFormatter())
logging.getLogger().addHandler(handler)
为什么要用 JSON 日志
JSON 明确区分字段和值,可减少从文本猜测字段边界的工作。接入观测云时,可按 DataKit 日志采集文档启用 json_as_fields 提取顶层字段,再用一条测试日志核对数字类型、时间和级别;嵌套字段及重命名仍需配置解析。
常见问题(FAQ)
Q:JSON 日志里如何包含调用位置(文件名、行号)?
A:自定义 Formatter 中 record.filename、record.lineno、record.funcName 可获取。
Q:已有大量纯文本日志怎么办?
A:保留匹配现有格式的解析规则,先让新代码输出 JSON,再按服务逐步迁移;用相同样本比较关键字段,避免切换格式后查询失效。
Q:性能有差异吗?
A:JSON 序列化比字符串拼接略慢,但对日志场景影响可忽略。高频日志可用 orjson 替代标准 json。