Skip to content

[Bug] MysqlDB 连接失败日志格式化参数数量错误,导致真实异常信息丢失 #315

Description

@LiYilin56

需知

升级feapder,保证feapder是最新版,若BUG仍然存在,则详细描述问题

pip install --upgrade feapder

问题
在 feapder/db/mysqldb.py 的 MysqlDB.init() 方法中,连接失败时的错误日志存在格式化参数数量不匹配的问题。

When the MySQL connection fails in MysqlDB.init(), the error logging has a format argument mismatch bug.

截图

Image

代码

except Exception as e:
    log.error(
        """
    连接失败:
    ip: {}
    port: {}
    db: {}
    user_name: {}
    user_pass: {}
    exception: {}
    """.format(
            ip, port, db, user_name, user_pass, charset, e
        )
    )

问题分析 / Analysis

格式字符串中有 6 个 {} 占位符,但 .format() 传入了 7 个参数

占位符位置 实际填充的值 期望填充的值
ip: {} ip ip
port: {} port port
db: {} db db
user_name: {} user_name user_name
user_pass: {} user_pass user_pass
exception: {} charset(如 "utf8mb4") 真正的异常对象 e
(无对应占位符) 真正的异常对象 e(被静默丢弃)

实际影响 / Impact

用户看到的错误日志是:

连接失败:
ip: localhost
port: 3306
db: py_spider
user_name: root
user_pass: root
exception: utf8mb4      ← 实际是 charset 的值,不是异常信息!

真正的异常(如 SSLError: [ASN1: NOT_ENOUGH_DATA] not enough data被完全丢弃,用户被严重误导,无法定位真实原因。

The real exception (e.g. SSL errors, auth failures, connection refused) is silently dropped, making debugging extremely difficult.

附带问题:except 块未重新抛出异常,产生僵尸对象

except 块记录日志后没有 raise,导致即使连接失败,MysqlDB() 仍然返回一个没有 connect_pool 属性的"僵尸"对象。后续任何方法调用(executefindadd 等)都会触发第二个误导性错误:

error:'MysqlDB' object has no attribute 'connect_pool'

两个 Bug 叠加的效果:用户先看到一个错误信息被篡改的日志,紧接着又被 AttributeError 进一步误导,完全找不到北。

受影响的调用点(共 8 处)

# 所有这些无参调用在连接失败时都会产生僵尸对象:
feapder/commands/create/create_item.py:29      self._db = MysqlDB()
feapder/commands/create/create_table.py:23     self._db = MysqlDB()
feapder/core/base_parser.py:128               self._mysqldb = mysqldb or MysqlDB()
feapder/core/base_parser.py:224               batch_info = MysqlDB().find(sql)  # 立即崩
feapder/core/spiders/batch_spider.py:117        self._mysqldb = MysqlDB()
feapder/core/spiders/task_spider.py:114         self._mysqldb = MysqlDB()
feapder/network/user_pool/normal_user_pool.py:67 self._mysqldb = MysqlDB()
feapder/pipelines/mysql_pipeline.py:25          self._to_db = MysqlDB()

其中 base_parser.py:224 最严重——临时创建后立即调用 .find(),连接失败即崩。

修复建议 / Proposed Fix

  1. 修正格式化参数数量
except Exception as e:
    log.error(
        """
    连接失败:
    ip: {}
    port: {}
    db: {}
    user_name: {}
    user_pass: {}
    charset: {}
    exception: {}
    """.format(
            ip, port, db, user_name, user_pass, charset, e
        )
    )
  1. 建议 except 块重新抛出异常,避免产生僵尸对象:
except Exception as e:
    log.error(
        """
    连接失败:
    ip: {}
    port: {}
    db: {}
    user_name: {}
    user_pass: {}
    charset: {}
    exception: {}
    """.format(
            ip, port, db, user_name, user_pass, charset, e
        )
    )
    raise  # ← 重新抛出,避免返回不完整的对象

补充说明 / Additional Context

这是一个存在已久的隐蔽 bug。只有当 MySQL 连接失败时才会触发,而连接失败往往恰恰是最需要准确错误信息来排查问题的场景。这个 bug 导致用户在排查连接问题时被完全误导。

建议一并检查代码库中是否有其他类似的格式化参数不匹配问题。


环境 / Environment

  • feapder version: 1.9.3(最新版)
  • Python: 3.9
  • OS: Windows 11
  • mysql: 5.7.33-log

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions