python 设置警告时避免格式问题,captureWarnings(True)

fhity93d  于 2023-01-24  发布在  Python
关注(0)|答案(1)|浏览(153)

我已经创建了一个日志处理程序,它记录到一个数据库表中,我还想将程序发出的警告捕获到另一个表中,所以使用了warnings.captureWarnings(True)
我在py.warnings日志记录器中的消息格式方面遇到了一些问题-消息总是显示为%s。我将其三角定位到日志库代码中的此行(logger.warning("%s", s)),当captureWarnings为True时,该代码实现警告发射。
当它被替换为logger.warning(s)时,消息显示如预期。因此,我推测这是某种格式问题,但我不知道是什么。
我还看到了BPO-46557,它实际上实现了这个行为,似乎是出于不相关的原因(但只是针对Python3.11+,我在3.10上)。
下面是我的DB日志处理程序代码。有没有办法在不升级到Python 3.11的情况下修复这个问题--看起来应该没有必要。
运行主代码前调用的代码:

logging.captureWarnings(True)
warnings_logger = logging.getLogger("py.warnings")
warnings_logger.setLevel(logging.DEBUG)
from db_logging import SQLAlchemyWarningHandler
handler = SQLAlchemyWarningHandler()
warnings_logger.addHandler(handler)

处理程序和LogRecord代码(db_logging.py)。然而,我不相信它是这个代码中的任何东西,因为我得到:<LogRecord: py.warnings, 30, /usr/lib/python3.10/warnings.py, 110, "%s">当我在记录发出之前打印它时

from database import database

# lib imports
from sqlalchemy import Column
from sqlalchemy.types import DateTime, Integer, String
from sqlalchemy.sql import func
from sqlalchemy.ext.declarative import declarative_base, declared_attr
from sqlalchemy.orm import sessionmaker
from sqlalchemy import DDL, event

# stdlib imports
import logging
import traceback
import sys

class Base(object):
    @declared_attr
    def __tablename__(cls):
        return cls.__name__.lower()

    __table_args__ = {"schema": "logs"}
    id = Column(Integer, primary_key=True) # auto incrementing
    logger = Column(String) # the name of the logger. (e.g. myapp.views)
    level = Column(String) # info, debug, or error?
    trace = Column(String) # the full traceback printout
    msg = Column(String) # any custom log you may have included
    created_at = Column(DateTime, default=func.now()) # the current timestamp
    source_loc = Column(String)

    def __init__(self, logger=None, level=None, trace=None, msg=None, source_loc=None):
        self.logger = logger
        self.level = level
        self.trace = trace
        self.msg = msg
        self.source_loc = source_loc

    def __unicode__(self):
        return self.__repr__()

    def __repr__(self):
        return "<Log: %s - %s>" % (self.created_at.strftime('%m/%d/%Y-%H:%M:%S'), self.msg[:50])


Base = declarative_base(cls=Base)
event.listen(Base.metadata, 'before_create', DDL("CREATE SCHEMA IF NOT EXISTS logs"))

class Logs(Base):
    "log class which writes all main db logs"
    pass

class WarningLogs(Base):
    "seperate log class for deprecation warnings which writes to a different db table"
    pass

class SQLAlchemyHandler(logging.Handler):
    "A very basic logger that commits a LogRecord to the SQL Db"
    def __init__(self):
        logging.Handler.__init__(self)
        Base.metadata.create_all(database.engine)
        Session = sessionmaker(bind=database.engine)
        self.session = Session()
        self.log_class = getattr(sys.modules[__name__], 'Logs')

    def emit(self, record):
        trace = None
        exc = record.__dict__['exc_info']
        if exc:
            trace = traceback.format_exc()
        log = self.log_class(
            logger=record.__dict__['name'],
            level=record.__dict__['levelname'],
            trace=trace,
            msg=record.__dict__['msg'],
            source_loc=f"{record.__dict__['pathname']}:{record.__dict__['lineno']}")
        self.session.add(log)
        self.session.commit()

    class SQLAlchemyWarningHandler(SQLAlchemyHandler):
    "Extends SQLAlchemyHandler to use WarningLog objects, which use a different table"
    def __init__(self,  **kwargs):
        super().__init__(**kwargs)
        self.log_class = getattr(sys.modules[__name__], 'WarningLogs')
jum4pzuy

jum4pzuy1#

看起来您正在阅读LogRecord上的msg属性并将其存储,而您不应该这样做。(根据文件,特别是它对msgmessage属性的说明。)它包含一个可能未格式化的字符串,缺少用户提供的参数。在警告捕获的情况下,整个消息作为参数提供,正如您已经找到的那样。
替换您的行:msg=record.__dict__['msg']msg=record.getMessage(),它将按预期工作。

相关问题