Tortoise ORM 日志配置实战:捕获 Debug SQL 与 Pygments 语法高亮

📅 发布时间:2026/10/12 2:22:01
Tortoise ORM 日志配置实战:捕获 Debug SQL 与 Pygments 语法高亮
数据库后端【免费下载链接】tortoise-ormFamiliar asyncio ORM for python, built with relations in mind项目地址https://gitcode.com/gh_mirrors/to/tortoise-orm点击查看免费下载导读本文围绕 Tortoise ORM 内置的两条日志通道tortoise.db_client查询执行日志与tortoise运行时日志展开讲解如何自行接管日志配置以打印可读的 Debug SQL并通过基于 Pygments 的自定义 Formatter 为 SQL 增加终端语法高亮。读完本文你将掌握 Tortoise ORM 日志体系的底层分发机制、各后端驱动在 DEBUG 级别的真实日志输出形态以及一套可直接复制到项目的日志美化方案。Tortoise ORM 的两条日志通道Tortoise ORM 当前维护两个命名 logger定义在 tortoise/log.pyimport logging logger logging.getLogger(tortoise) db_client_logger logging.getLogger(tortoise.db_client)二者的职责划分非常清晰Logger 名称记录内容典型级别tortoise.db_client查询执行信息SQL 语句与绑定参数、连接池/连接创建与关闭DEBUGtortoise运行时信息框架启动、建表、关闭等生命周期事件INFO / DEBUGtortoise.db_client面向数据库客户端这一层每一个后端驱动的连接客户端都会持有该 logger。从源码结构看BaseDBAsyncClient.__init__中通过self.log db_client_logger见 tortoise/backends/base/client.py将其挂载到所有后端客户端实例上因此 asyncpg、psycopg、mysql、sqlite、mssql、odbc、oracle 各后端共用同一条查询日志通道。tortoise则负责框架级别的运行时信息例如 tortoise/init.py 在Tortoise.init时会在 DEBUG 级别打印脱敏后的连接配置密码会被star_password掩码处理以及 tortoise/init.py 中Tortoise-ORM shutdown之类的关闭提示。为什么默认看不到 Debug SQLTortoise ORM 遵循 Python 标准库logging的设计logger 本身不做任何输出是否打印完全取决于你在应用侧是否为其配置了 handler 与级别。由于框架默认不对这两个 logger 做任何 handler 配置所以即使底层在 DEBUG 级别记录了大量查询信息默认情况下也不会输出到终端。若想让查询 SQL 可视化只需像配置普通 Python logger 一样为tortoise.db_client挂上 handler 并设置logging.DEBUG级别即可。配置示例让 Debug SQL 打印到终端以下是官方文档给出的最小配置需先import logging与sysimport logging fmt logging.Formatter( fmt%(asctime)s - %(name)s:%(lineno)d - %(levelname)s - %(message)s, datefmt%Y-%m-%d %H:%M:%S, ) sh logging.StreamHandler(sys.stdout) sh.setLevel(logging.DEBUG) sh.setFormatter(fmt) # will print debug sql logger_db_client logging.getLogger(tortoise.db_client) logger_db_client.setLevel(logging.DEBUG) logger_db_client.addHandler(sh) logger_tortoise logging.getLogger(tortoise) logger_tortoise.setLevel(logging.DEBUG) logger_tortoise.addHandler(sh)几点实操说明StreamHandler(sys.stdout)将日志输出定向到标准输出也可改用sys.stderr或logging.FileHandler落到文件setLevel(logging.DEBUG)是关键因为各后端的查询 SQL 均以 DEBUG 级别记录见下文源码证据fmt中的%(lineno)d会打印产生日志记录的源码行号便于回溯日志出处两个 logger 可共用同一个 handler避免重复创建 StreamHandler。将这段配置放在调用Tortoise.init(...)之前执行之后每次执行查询终端即可看到形如2026-10-11 22:19:34 - tortoise.db_client:190 - DEBUG - SELECT ...: [...]的输出。源码证据查询日志在各后端 DEBUG 级别产生以 MySQL 后端为例在 tortoise/backends/mysql/client.py 中execute_insert、execute_many、execute_query均在真正执行前调用self.log.debug(%s: %s, query, values)同样的模式出现在 asyncpgtortoise/backends/asyncpg/client.py、sqlitetortoise/backends/sqlite/client.py、psycopgtortoise/backends/psycopg/client.py、mssql、odbc、oracle 等客户端的execute_query/execute_insert/execute_many方法中。这意味着一旦打开tortoise.db_client的 DEBUG 开关所有后端都会输出「SQL 绑定参数列表」的完整记录。此外连接池的生命周期事件也走同一条通道例如 asyncpg 客户端在 tortoise/backends/asyncpg/client.py 与 tortoise/backends/asyncpg/client.py 分别输出Created connection pool ...与Closed connection pool ...sqlite 客户端在 tortoise/backends/sqlite/client.py 输出Created connection .../Closed connection ...含 filename 与 pragma 参数。运行时日志的实际内容打开tortoiselogger 的 DEBUG 后可以看到框架生命周期信息Tortoise.init时在 DEBUG 级别输出脱敏后的connections与apps配置tortoise/init.py连接 URL 中的密码会被star_password掩码避免密钥泄露到日志FastAPI、Aiohttp、Sanic、Starlette、Quart、Blacksheep 等集成层在init_orm/close_orm中输出Tortoise-ORM started, ...、Tortoise-ORM generating schema、Tortoise-ORM shutdown等 INFO 日志例如 tortoise/contrib/aiohttp/init.py。补充说明迁移执行器使用独立的子 logger值得注意的是迁移执行器 tortoise/migrations/executor.py 内部通过logging.getLogger(__name__)创建了tortoise.migrations.executorlogger用于输出Building migration graph、Loading applied migrations等 DEBUG 信息。由于它是tortoise的子 logger当你为tortoise设置了 DEBUG 级别与 handler 时这部分迁移调试信息同样会生效——这也是官方文档建议同时配置tortoise与tortoise.db_client两个 logger 的实用理由之一。进阶用 Pygments 为 SQL 增加终端语法高亮纯文本 SQL 在大日志量时难以快速扫读。官方文档给出的进阶方案是自定义一个继承logging.Formatter的PygmentsFormatter利用pygments库对 SQL 消息做终端高亮渲染。前置依赖需单独安装不在 Tortoise ORM 核心依赖内pip install pygments完整实现如下import logging from pygments import highlight from pygments.formatters.terminal import TerminalFormatter from pygments.lexers.sql import PostgresLexer postgres PostgresLexer() terminal_formatter TerminalFormatter() class PygmentsFormatter(logging.Formatter): def __init__( self, fmt{asctime} - {name}:{lineno} - {levelname} - {message}, datefmt%H:%M:%S, ): self.datefmt datefmt self.fmt fmt logging.Formatter.__init__(self, None, datefmt) def format(self, record: logging.LogRecord): Format the logging record with slqs syntax coloration. own_records { attr: val for attr, val in record.__dict__.items() if not attr.startswith(_) } message record.getMessage() name record.name asctime self.formatTime(record, self.datefmt) if name tortoise.db_client: if ( record.levelname DEBUG and not message.startswith(Created connection pool) and not message.startswith(Closed connection pool) ): message highlight(message, postgres, terminal_formatter).rstrip() own_records.update( { message: message, name: name, asctime: asctime, } ) return self.fmt.format(**own_records)使用方式把前面基础示例中的logging.Formatter替换为该自定义 Formatter 即可fmt PygmentsFormatter( fmt{asctime} - {name}:{lineno} - {levelname} - {message}, datefmt%Y-%m-%d %H:%M:%S, )实现细节拆解该 Formatter 的代码虽短但包含了几个值得注意的设计决策仅对tortoise.db_client做高亮通过record.name精确限定tortoise运行时日志不参与 SQL 着色避免无谓的渲染开销排除连接池消息Created connection pool .../Closed connection pool ...这类消息是连接池对象的 repr并非合法 SQL 语句直接对其做词法高亮会产生杂乱输出因此显式跳过使用{message}风格格式化logging.Formatter.__init__(self, None, datefmt)传入None作为 fmt再手工构造own_records字典绕开了标准%(...)s风格的属性插值从而可以在渲染前替换message字段为高亮后的文本highlight(...).rstrip()Pygments 的终端输出以 ANSI 转义序列结尾rstrip()去除尾部空白保证换行整洁。从实现上可以推断该方案直接复用了record的完整属性集lineno、levelname、name、asctime等只是对message做了就地替换因此日志的时间戳、文件名、行号等信息依然完整保留。进一步定制颜色方案与多后端适配示例中选用的是PostgresLexer与TerminalFormatter。如果你实际使用 MySQL、SQLite 或 MSSQL从 Pygments 源码结构看其 lexer 家族还提供SqlLexer、MySQLLexer、SqliteConsoleLexer、MssqlLexer等可按下述方式按后端替换from pygments.lexers.sql import MySQLLexer # 使用 MySQL 词法分析器 mysql MySQLLexer() message highlight(message, mysql, terminal_formatter).rstrip()TerminalFormatter支持若干可选参数例如bgdark/bglight适配深色或浅色终端背景style...传入 pygments 内置风格如monokai、native、friendly以获得不同的配色linenosTrue为多行 SQL 显示行号。例如深色终端下的 Monokai 风格from pygments.styles import get_style_by_name terminal_formatter TerminalFormatter(bgdark, styleget_style_by_name(monokai))需要注意的是Pygments 的 ANSI 高亮只在支持 ANSI 转义序列的真终端中可见若日志写入文件或进入 CI 日志采集系统转义码可能会污染原始文本此时建议关闭高亮或仅在本地开发环境启用。生产环境的日志实践建议综合官方文档与仓库实现给出如下落地建议分环境控制级别开发环境把tortoise.db_client设为 DEBUG 以观察 SQL生产环境建议保持 WARNING 或以上避免高吞吐下日志洪峰拖垮 I/O日志脱敏Tortoise.init的 DEBUG 输出已通过star_password对连接配置脱敏tortoise/init.py但 DEBUG 级 SQL 日志会包含绑定参数值若参数中夹带敏感数据请谨慎评估是否在正式环境开启统一接入既有日志体系由于 Tortoise ORM 完全基于标准库logging无需任何适配即可与loguru、structlog的 stdlib 桥接或企业级日志框架集成——只需像操作普通 logger 一样为tortoise/tortoise.db_client设置 handler 与级别不要重复添加 handler多次执行addHandler会导致日志重复打印可在应用入口统一配置一次。小结Tortoise ORM 的日志体系围绕tortoise.db_client查询/连接事件与tortoise运行时生命周期两条通道展开底层全部基于标准库logging因此你可以用任意熟悉的方式接管其输出无论是简单的 StreamHandler 打印 Debug SQL还是基于 Pygments 的自定义 Formatter 实现终端语法高亮都无需修改框架代码。本文涉及的源码位置汇总如下供深入研读tortoise/log.py两条 logger 的定义源头tortoise/backends/base/client.pydb_client_logger挂载到各后端客户端tortoise/backends/mysql/client.py查询语句 DEBUG 日志的典型产生点tortoise/backends/asyncpg/client.py连接池创建/关闭日志tortoise/init.py运行时配置的脱敏 DEBUG 输出tortoise/migrations/executor.py迁移执行器的独立子 loggerdocs/reference.rst本文档在 Tortoise ORM 参考手册中的位置。赞分享数据库后端【免费下载链接】tortoise-ormFamiliar asyncio ORM for python, built with relations in mind项目地址https://gitcode.com/gh_mirrors/to/tortoise-orm点击查看免费下载相关推荐超全Pygments教程500语言语法高亮实战指南超全Pygments教程500语言语法高亮实战指南 你还在为代码展示不够专业而烦恼吗作为开发者我们经常需要在文档、博客或应用中展示代码但默认的纯文本格开发工具500语言通用语法高亮Pygments全功能实战指南500语言通用语法高亮Pygments全功能实战指南 你还在为代码展示缺乏专业美感而烦恼还在忍受不同平台语法高亮风格不一的困扰作为开发者我们每天都在与开发工具Django 日志配置与 Django-Debug-Toolbar 实战从调试到 ORM 性能优化Python-100-DaysDjango 日志配置与 Django Debug Toolbar 实战从调试到 ORM 性能优化Python 100 Days 本篇技术指南围绕 Dja文档教程上一篇ClawPanel多Agent管理创建多个AI身份、独立工作区与模型分配的完整指南下一篇策略梯度算法与 REINFORCE基于策略的强化学习入门Awesome-ML-SYS-Tutorial 系列笔记创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考