You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Python自定义Formatter无法处理RuntimeWarning日志?

问题:RuntimeWarning未被自定义JSON日志格式化器处理

我试图让Python应用的所有日志消息都通过pythonjsonlogger的JsonFormatter格式化,但发现numpy抛出的RuntimeWarning(比如__main__:1: RuntimeWarning: divide by zero encountered in true_divide)没有被处理成期望的JSON结构(示例:{"name": "root", "funcName": "<module>", "level": null, "lineno": 1, "threadName": "MainThread", "message": "RuntimeWarning: divide by zero encountered in true_divide"})。虽然已经配置了root logger使用自定义的json_handler,但该警告依然以默认格式输出。

复现代码:

import logging
import os
import sys
import numpy as np
import pandas as pd
from pythonjsonlogger import jsonlogger
from logging import getLogger, config


log_level = os.environ.get("LOG_LEVEL", "INFO")
log_format = "%(name)s %(funcName)s %(levelname)s %(lineno)d %(threadName)s %(message)s"

config.dictConfig({
    'version': 1,
    'formatters': {'json': {
        '()': jsonlogger.JsonFormatter,
        'format': log_format,
    }},
    'handlers': {
        'json_handler': {
            'class': 'logging.StreamHandler',
            'formatter': 'json',
            'level': log_level,
            'stream': sys.stdout
        }
    },
    'loggers': {
        '': {
            'handlers': ['json_handler'],
            'level': log_level,
            'propagate': False
        },
       
    },
    'root': {
        'level': log_level,
        'handlers': ['json_handler'],
    },
    'disable_existing_loggers': True
})

logging.info("test") # 这条日志能正常格式化

series_raw = pd.Series([0, float('nan'), 1,4,6,-1], [0,1,2,3,4,5])

x = series_raw.values

values = np.where(np.logical_or(x == 0, np.isnan(x)), np.nan, 10 /x) # 这里抛出的警告无法被格式化
原因分析

RuntimeWarning是Python的warnings模块发出的,并非直接通过logging模块生成。默认情况下,warnings会直接输出到标准错误流,不会经过logging系统,所以你的logging配置对它无效。

解决方案

要让警告被logging系统处理,需要:

  • 启用logging对warnings的捕获功能
  • 确保处理警告的logger(默认是py.warnings)使用你的自定义格式化器

具体修改步骤:

  1. 导入warnings模块
  2. 调用logging.captureWarnings(True),将warnings转发到logging系统
  3. 在logging配置中,为py.warningslogger配置使用json_handler,或者让它的日志 propagate 到root logger
修改后的代码
import logging
import os
import sys
import warnings
import numpy as np
import pandas as pd
from pythonjsonlogger import jsonlogger
from logging import getLogger, config

# 启用捕获warnings到logging系统
logging.captureWarnings(True)

log_level = os.environ.get("LOG_LEVEL", "INFO")
log_format = "%(name)s %(funcName)s %(levelname)s %(lineno)d %(threadName)s %(message)s"

config.dictConfig({
    'version': 1,
    'formatters': {'json': {
        '()': jsonlogger.JsonFormatter,
        'format': log_format,
    }},
    'handlers': {
        'json_handler': {
            'class': 'logging.StreamHandler',
            'formatter': 'json',
            'level': log_level,
            'stream': sys.stdout
        }
    },
    'loggers': {
        # 配置py.warnings logger使用json_handler
        'py.warnings': {
            'handlers': ['json_handler'],
            'level': log_level,
            'propagate': False
        },
        '': {
            'handlers': ['json_handler'],
            'level': log_level,
            'propagate': False
        },
    },
    'root': {
        'level': log_level,
        'handlers': ['json_handler'],
    },
    'disable_existing_loggers': True
})

logging.info("test") # 正常格式化

series_raw = pd.Series([0, float('nan'), 1,4,6,-1], [0,1,2,3,4,5])

x = series_raw.values

values = np.where(np.logical_or(x == 0, np.isnan(x)), np.nan, 10 /x) # 现在警告会被JSON格式化

注:原log_format中的占位符存在错误,比如%(level)应改为%(levelname),%(name)需补充s变为%(name)s,否则会导致格式化异常,上述代码已修正这些问题。

内容的提问来源于stack exchange,提问作者Sam Comber

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 20:45:29