logger.debug 是启用参数化 sql 日志的硬性前提,parameterizedqueries: true 仅在 loglevel: logger.debug 下生效;info 或 warn 级别下该配置被忽略,且动态调用 logmode(logger.debug) 不触发参数拼接逻辑。

Logger.Debug 是启用参数化 SQL 日志的硬性前提
GORM v2 的 ParameterizedQueries: true 仅在 LogLevel: logger.Debug 下生效,设为 logger.Info 或更低级别时,该开关被完全忽略。日志里看到的永远是 SELECT * FROM users WHERE id = ? 这类带占位符的语句,参数值不会代入。
常见错误现象:配置了 ParameterizedQueries: true 却看不到真实参数,就是卡在了日志级别上。
- 必须用
logger.New(..., logger.Config{LogLevel: logger.Debug, ParameterizedQueries: true})构造新 logger - 不要调用
db.Logger.LogMode(logger.Debug)动态切换——它不触发参数拼接逻辑 -
Colorful: true建议开启,SQL 高亮后一眼能区分语句和参数
Raw() 和 Scan() 是日志过滤的盲区,无法靠 Logger 拦截
db.Raw("UPDATE users SET token = '" + user.Token + "'").Exec() 这类写法,无论 logger 级别多高、ParameterizedQueries 是否开启,都不会出现在 GORM 日志里——因为 Raw() 绕过了整个 ORM 查询构建器,直接交由底层 driver 执行。
这意味着:你指望 logger 自动遮蔽 token 字段,根本没机会介入。
-
Raw()、Exec()、Row()、Rows()全部跳过 GORM 日志管道 - 想审计或过滤这类 SQL,必须在调用前手动检查字符串内容,或用
db.Callback().Create().Before("gorm:create")类似机制拦截 - 敏感字段(如密码、token)绝不能出现在
Raw()的 SQL 字符串中,哪怕只是日志用途
Logger 本身不提供字段级脱敏能力,需配合 slog.LogValuer 或自定义 Formatter
GORM logger 输出的是完整 SQL 字符串,不是结构化字段。它不会识别 password 或 auth_token 这类 key,也没法对其中某一段做替换。所谓“过滤敏感数据”,实际要解决的是:SQL 字符串里含明文参数时,如何不让它们落盘或打印到终端。
真正可控的做法只有两种:
- 用 Go 1.21+ 的
slog+LogValuer:把敏感值包装成类型(如SensitiveToken),在日志构造阶段就返回"[REDACTED]" - 若用
logrus,必须实现自定义Formatter.Format(),在entry.Data还是map[string]interface{}时深拷贝并删除指定 key(如"password") - 切勿依赖日志后端(如 Loki 正则过滤)——敏感信息已在内存/缓冲区明文存在过
生产环境禁用 Debug 日志,且不能靠 if 判断临时开启
logger.Debug 不只打带参 SQL,还会输出事务生命周期、钩子调用栈、反射字段解析等大量调试信息。更关键的是:所有参数(包括 user.Password、auth_code、id_card)都会原样代入 SQL 字符串并打印。
这不是性能问题,而是安全边界问题。
- 禁止在代码里写
if env == "prod" { logger = logger.Default } else { logger = debugLogger }—— 编译期不可控,上线即暴露 - 推荐用构建标签(如
//go:build debug)或启动时通过配置项决定是否创建debugLogger实例 - 高频接口(如
db.First(&u, id))附近调用db.Session(&session).Debug().First()会覆盖全局 logger,且极易误提交到生产分支
GORM 的 logger 本质是 SQL 执行快照,不是日志治理工具;它能帮你看到“什么 SQL 被执行了”,但没法替你决定“哪些字段不该被看见”。参数是否可见、是否脱敏、是否落盘,得在数据进入 logger 之前就做好取舍。











