Files
loggerx/loggerx_combined_test.go
2026-09-13 21:53:37 +08:00

131 lines
3.3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package loggerx_test
import (
"context"
"fmt"
"os"
"path/filepath"
"strings"
"testing"
"time"
"github.com/yuninks/loggerx"
)
// 定时刷盘 + 异步写入 + 按大小切割 + 压缩 全部开启时的综合正确性
func TestAllFeaturesCombined(t *testing.T) {
dir := t.TempDir()
l := loggerx.NewLogger(context.Background(),
loggerx.SetDir(dir),
loggerx.SetWriteAsync(),
loggerx.SetFlushInterval(15*time.Millisecond),
loggerx.SetSizeSplit(6*1024),
loggerx.SetCompress(true),
)
al := l.WriteAsync()
const n = 1500
for i := 0; i < n; i++ {
// 注意:内容里带了固定后缀,条目文本形如 ALL-0-yyy...
// 断言时用 "ALL-<i>-" 前缀而不是 "ALL-<i>\""
al.Infof(context.Background(), "ALL-%d-%s", i, strings.Repeat("y", 40))
// 顺带混入 channel 与 error 事件,确认多句柄并发滚动也正常
if i%50 == 0 {
l.Channel("sub").Errorf(context.Background(), "ERR-%d", i)
}
}
if err := l.Close(); err != nil {
t.Fatalf("Close: %v", err)
}
// 主日志(含压缩归档)一条不能少
gzContent := readAllGz(t, dir)
logContent := readAllLogs(t, dir)
main := logContent + gzContent
t.Logf("未压缩 .log 共 %d 字节;.gz 解压后共 %d 字节", len(logContent), len(gzContent))
if len(gzContent) > 0 {
n := 200
if len(gzContent) < n {
n = len(gzContent)
}
t.Logf("gz 内容片段: %.200q", gzContent[:n])
}
missing := 0
for i := 0; i < n; i++ {
if !strings.Contains(main, fmt.Sprintf("ALL-%d-", i)) {
missing++
}
}
if missing > 0 {
t.Errorf("综合场景丢失 %d / %d 条主日志", missing, n)
}
// sub channel 的 error 日志也要完整
_ = filepath.Walk(dir, func(p string, info os.FileInfo, err error) error {
if err != nil {
return nil
}
rel, _ := filepath.Rel(dir, p)
if info.IsDir() {
t.Logf(" [dir] %s", rel)
} else {
t.Logf(" [file] %s %d 字节", rel, info.Size())
}
return nil
})
sub := readAllIn(t, dir, "sub")
for i := 0; i < n; i += 50 {
if !strings.Contains(sub, fmt.Sprintf("ERR-%d", i)) {
t.Errorf("sub channel 丢失 ERR-%d", i)
}
}
}
// readAllIn 读取某个子目录(channel 目录)下的日志与压缩归档
func readAllIn(t *testing.T, dir, sub string) string {
t.Helper()
target := filepath.Join(dir, sub)
if _, err := os.Stat(target); err != nil {
t.Fatalf("channel 目录不存在: %v", err)
}
var sb strings.Builder
files, _ := filepath.Glob(filepath.Join(target, "*"))
for _, f := range files {
st, err := os.Stat(f)
if err != nil || st.IsDir() {
continue
}
b, err := os.ReadFile(f)
if err != nil {
t.Fatalf("读取 %s: %v", f, err)
}
sb.Write(b)
}
return sb.String()
}
// 综合场景下定时刷盘不能把 Close 卡死(刷盘协程与关闭的互锁)
func TestAllFeaturesCloseNotBlocked(t *testing.T) {
dir := t.TempDir()
l := loggerx.NewLogger(context.Background(),
loggerx.SetDir(dir),
loggerx.SetFlushInterval(1*time.Millisecond), // 刷盘非常频繁,放大竞争
loggerx.SetSizeSplit(2*1024),
)
for i := 0; i < 800; i++ {
l.Infof(context.Background(), "BLK-%d", i)
}
done := make(chan error, 1)
go func() { done <- l.Close() }()
select {
case err := <-done:
if err != nil {
t.Errorf("Close 返回错误: %v", err)
}
case <-time.After(20 * time.Second):
t.Fatal("高频定时刷盘时 Close 卡死")
}
}