diff --git a/config.example.yaml b/config.example.yaml index 2da01191..7f0b9fe5 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -31,7 +31,7 @@ database: max_open_conn: 128 conn_max_lifetime: 1800 conn_max_idle_time: 600 - log_level: "info" # error | warn | info | debug | silent + log_level: "info" # error | warn | info | debug | silent;SQL 语句仅在 log.level=debug 时输出 ssl_mode: "disable" time_zone: "UTC" application_name: "openflare-server" diff --git a/docs/changelog/index.md b/docs/changelog/index.md index 866bc940..9d20987f 100644 --- a/docs/changelog/index.md +++ b/docs/changelog/index.md @@ -35,6 +35,7 @@ sidebar: false ### 修复 +- GORM SQL 语句改为仅在全局 `debug` 日志级别输出;生产默认日志级别不再记录查询文本,慢查询与执行错误也不包含 SQL 参数,避免节点访问令牌等敏感信息写入应用日志。 - WAF 规则编辑器支持通过按钮或键盘删除普通节点和连线,节点属性栏改为选中节点后按需显示,并修复拖动节点时因 React Flow 初始化状态丢失导致的画面闪烁与 error 015。 - WAF 规则编辑器新增启用/停用控制,并移除已废弃的规则组侧站点绑定入口;站点规则顺序统一在反代路由详情中管理。 - 修复 Agent 心跳无法从活动 WAF 运行图发现 IP 组引用的问题,并对发布与同步的完整 IP 组快照增加 20 MiB 聚合容量保护。 diff --git a/internal/db/postgres_logger.go b/internal/db/postgres_logger.go index eb7964d9..0bfd0f7a 100644 --- a/internal/db/postgres_logger.go +++ b/internal/db/postgres_logger.go @@ -53,30 +53,25 @@ func (l *gormZapLogger) Trace(ctx context.Context, begin time.Time, fc func() (s elapsed := time.Since(begin) switch { case err != nil && l.logLevel >= gormLogger.Error && (!errors.Is(err, gorm.ErrRecordNotFound) || !l.ignoreRecordNotFoundError): - sql, rows := fc() - if rows == -1 { - logger.ErrorF(ctx, "%s\n[%.3fms] [rows:%v] %s", err, float64(elapsed.Nanoseconds())/nanoToMilli, "-", sql) - } else { - logger.ErrorF(ctx, "%s\n[%.3fms] [rows:%v] %s", err, float64(elapsed.Nanoseconds())/nanoToMilli, rows, sql) - } + _, rows := fc() + logger.ErrorF(ctx, "database query failed: %s [%.3fms] [rows:%v]", err, float64(elapsed.Nanoseconds())/nanoToMilli, formatRows(rows)) case elapsed > l.slowThreshold && l.slowThreshold != 0 && l.logLevel >= gormLogger.Warn: - sql, rows := fc() + _, rows := fc() slowLog := fmt.Sprintf("SLOW SQL >= %v", l.slowThreshold) - if rows == -1 { - logger.WarnF(ctx, "%s\n[%.3fms] [rows:%v] %s", slowLog, float64(elapsed.Nanoseconds())/nanoToMilli, "-", sql) - } else { - logger.WarnF(ctx, "%s\n[%.3fms] [rows:%v] %s", slowLog, float64(elapsed.Nanoseconds())/nanoToMilli, rows, sql) - } + logger.WarnF(ctx, "%s [%.3fms] [rows:%v]", slowLog, float64(elapsed.Nanoseconds())/nanoToMilli, formatRows(rows)) case l.logLevel == gormLogger.Info: sql, rows := fc() - if rows == -1 { - logger.InfoF(ctx, "[%.3fms] [rows:%v] %s", float64(elapsed.Nanoseconds())/nanoToMilli, "-", sql) - } else { - logger.InfoF(ctx, "[%.3fms] [rows:%v] %s", float64(elapsed.Nanoseconds())/nanoToMilli, rows, sql) - } + logger.DebugF(ctx, "[%.3fms] [rows:%v] %s", float64(elapsed.Nanoseconds())/nanoToMilli, formatRows(rows), sql) } } +func formatRows(rows int64) interface{} { + if rows == -1 { + return "-" + } + return rows +} + func parseLogLevel(level string) gormLogger.LogLevel { level = strings.ToLower(level) switch level { @@ -88,6 +83,8 @@ func parseLogLevel(level string) gormLogger.LogLevel { return gormLogger.Warn case "info": return gormLogger.Info + case "debug": + return gormLogger.Info default: return gormLogger.Info } diff --git a/internal/db/postgres_logger_test.go b/internal/db/postgres_logger_test.go new file mode 100644 index 00000000..20539a5b --- /dev/null +++ b/internal/db/postgres_logger_test.go @@ -0,0 +1,39 @@ +// Copyright 2026 Arctel.net +// SPDX-License-Identifier: Apache-2.0 + +package db + +import ( + "testing" + + gormLogger "gorm.io/gorm/logger" +) + +func TestParseLogLevel(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + configuredLevel string + want gormLogger.LogLevel + }{ + { + name: "debug enables SQL trace processing", + configuredLevel: "debug", + want: gormLogger.Info, + }, + { + name: "development preserves configured level", + configuredLevel: "warn", + want: gormLogger.Warn, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := parseLogLevel(tt.configuredLevel); got != tt.want { + t.Fatalf("parseLogLevel() = %v, want %v", got, tt.want) + } + }) + } +}