131 lines
3.3 KiB
Go
131 lines
3.3 KiB
Go
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 卡死")
|
|||
|
|
}
|
|||
|
|
}
|