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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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