package gormx import ( "bytes" "context" "encoding/json" "errors" "fmt" "strings" "sync" "testing" "time" "git.yuntuo.hk/k2safe/go-omni/logx" "gorm.io/gorm" gormlog "gorm.io/gorm/logger" ) func TestSQLLoggerLevelsPrivacyAndCorrelation(t *testing.T) { var out bytes.Buffer base, _ := logx.New(logx.Config{Writer: &out}) l, _ := NewLogger(base, DefaultLogConfig()) ctx := logx.WithRequestID(logx.WithTraceID(context.Background(), "trace-1"), "request-1") count := 0 fc := func() (string, int64) { count++; return "SELECT * FROM records WHERE token = ?", 1 } l.Trace(ctx, time.Now(), fc, nil) l.Trace(ctx, time.Now(), fc, fmt.Errorf("wrapped: %w", gorm.ErrRecordNotFound)) l.LogMode(gormlog.Silent).Trace(ctx, time.Now(), fc, errors.New("password-value")) if count != 0 { t.Fatal("ignored event evaluated SQL") } l.Trace(ctx, time.Now().Add(-time.Second), fc, nil) l.Trace(ctx, time.Now(), fc, errors.New("password-value")) l.Error(ctx, "failed: %v", errors.New("password-value")) l.LogMode(gormlog.Info).Trace(ctx, time.Now(), fc, nil) if count != 3 { t.Fatal(count) } if strings.Contains(out.String(), "password-value") { t.Fatal("driver detail leaked", out.String()) } for _, text := range []string{"gorm.slowQuery", "gorm.queryFailed", "gorm.query", `"requestId":"request-1"`, `"traceId":"trace-1"`} { if !strings.Contains(out.String(), text) { t.Fatal(text, out.String()) } } q, args := l.(gorm.ParamsFilter).ParamsFilter(ctx, "SELECT ?", "private") if q != "SELECT ?" || len(args) != 0 { t.Fatal("default SQL arguments exposed") } // LogMode clones rather than mutating the shared instance. l.Trace(ctx, time.Now(), fc, nil) if count != 3 { t.Fatal("session mode changed root logger") } } func TestSQLLoggerExplicitDetailsAndConcurrentModes(t *testing.T) { var out bytes.Buffer base, _ := logx.New(logx.Config{Writer: &out}) cfg := DefaultLogConfig() cfg.IncludeParameters = true cfg.IncludeErrorDetails = true cfg.Level = "info" cfg.MaxSQLBytes = 8 l, err := NewLogger(base, cfg) if err != nil { t.Fatal(err) } _, args := l.(gorm.ParamsFilter).ParamsFilter(context.Background(), "SELECT ?", "value") if len(args) != 1 { t.Fatal("explicit arguments dropped") } var wg sync.WaitGroup for i := 0; i < 20; i++ { wg.Add(1) go func() { defer wg.Done() l.LogMode(gormlog.Error).Trace(context.Background(), time.Now(), func() (string, int64) { return "SELECT 中文标识符", -1 }, errors.New("failure")) }() } wg.Wait() for _, line := range strings.Split(strings.TrimSpace(out.String()), "\n") { var event map[string]any if err = json.Unmarshal([]byte(line), &event); err != nil { t.Fatal(err) } if event["error"] != "failure" || strings.Contains(event["sql"].(string), "�") { t.Fatal(event) } } }