package loggerx_test import ( "context" "errors" "log" "strings" "sync" "testing" "time" "github.com/yuninks/loggerx" ) // F1 验证:异步消费路径里 panic 之后,整个日志系统是否彻底卡死 func TestPanicInAsyncConsumerWedgesLogger(t *testing.T) { dir := t.TempDir() // 一个会 panic 的 driver(模拟用户 writer / gin writer 里出问题) var once sync.Once boom := writerFunc(func(p []byte) (int, error) { once.Do(func() { panic("driver exploded") }) return len(p), nil }) l := loggerx.NewLogger(context.Background(), loggerx.SetDir(dir), loggerx.SetPrintFile(false), loggerx.SetExtraDriver(boom), loggerx.SetWriteAsync(), ) // 第一条触发 panic(消费协程挂掉) l.Info(context.Background(), "trigger") // 之后继续写,看是否会在队列满之前就卡死 done := make(chan struct{}) go func() { defer close(done) for i := 0; i < 3000; i++ { l.Info(context.Background(), "after-panic") } }() select { case <-done: t.Log("panic 之后仍能继续写入(未卡死)") case <-time.After(5 * time.Second): t.Fatal("F1 复现:异步消费协程 panic 后,写入方永久阻塞(队列满后死锁)") } // Close 是否会卡死 closed := make(chan error, 1) go func() { closed <- l.Close() }() select { case err := <-closed: t.Logf("Close 返回: %v", err) case <-time.After(10 * time.Second): t.Fatal("F1 复现:Close 永久阻塞在 wg.Wait()") } } // F7 验证:经 stdlib log 写入时,异步队列是否保留了 log 包会复用的缓冲 func TestStdLogBufferReuseInAsync(t *testing.T) { dir := t.TempDir() l := loggerx.NewLogger(context.Background(), loggerx.SetDir(dir), loggerx.SetWriteAsync()) defer l.Close() log.SetOutput(l) // stdlib log 用 sync.Pool 的缓冲,Write 返回后立即归还并复用 for i := 0; i < 2000; i++ { log.Printf("POOL-%05d-%s", i, string(make([]byte, 200))) } if err := l.Close(); err != nil { t.Fatalf("Close: %v", err) } // 逐条检查:每个 POOL-nnnnn 是否都完整(不再被复用的池缓冲破坏) content := readAllLogs(t, dir) bad := 0 for i := 0; i < 2000; i++ { if !strings.Contains(content, "POOL-"+pad(i)) { bad++ } } if bad > 0 { t.Errorf("F7 复现:%d / 2000 条日志内容缺失或被复用缓冲破坏", bad) } } func pad(i int) string { s := "00000" d := "" for i > 0 { d = string(rune('0'+i%10)) + d i /= 10 } if len(d) >= len(s) { return d } return s[:len(s)-len(d)] + d } type writerFunc func([]byte) (int, error) func (f writerFunc) Write(p []byte) (int, error) { return f(p) } var errBoom = errors.New("boom")