Files
loggerx/loggerx_wedge_test.go
T
2026-09-14 00:14:30 +08:00

110 lines
2.6 KiB
Go

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")