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 日志
纯文本日志需要 grok/正则解析,容易出错;JSON 日志是结构化的,日志平台可以直接提取字段做检索和聚合,不需要写解析规则。
观测云对照
观测云 DataKit 采集 JSON 格式日志后,Pipeline 可直接提取顶层字段,无需编写 grok 模式;日志在日志查看器中按字段检索,监控器按字段值配置告警。
常见问题(FAQ)
Q:JSON 日志里如何包含调用位置(文件名、行号)?
A:自定义 Formatter 中 record.filename、record.lineno、record.funcName 可获取。
Q:已有大量纯文本日志怎么办?
A:观测云 Pipeline 的 grok 函数可以解析纯文本日志提取字段;逐步迁移到 JSON 格式,新代码直接用结构化日志。
Q:性能有差异吗?
A:JSON 序列化比字符串拼接略慢,但对日志场景影响可忽略。高频日志可用 orjson 替代标准 json。