feat(logger): 支持float64类型的日志配置参数并添加测试

- 修改file.go中maxSize和maxCount的类型断言,从int64/int改为
  float64优先,并保留对原类型的兼容
- 添加file_test.go包含完整的文件滚动功能测试用例
- 测试覆盖大小滚动、最大文件数限制和JSON解析场景
```
This commit is contained in:
程广 2026-07-13 10:05:24 +08:00
parent 36b2fe9f34
commit aa69fd4979
2 changed files with 231 additions and 3 deletions

View File

@ -181,8 +181,8 @@ func makeFileAppender(appenderConfig LogAppenderConfig) *LoggerAppender {
}
maxSize := int64(0)
if size, ok := appenderConfig.Options["maxSize"].(int64); ok {
maxSize = size * 1024 * 1024 // 将兆转换为字节
if size, ok := appenderConfig.Options["maxSize"].(float64); ok {
maxSize = int64(size) * 1024 * 1024 // 将兆转换为字节
} else if sizeStr, ok := appenderConfig.Options["maxSize"].(string); ok {
// 解析带单位的大小配置支持KB, MB, GB
var re = regexp.MustCompile(`(?i)^(\d+)([kmg]b)?$`)
@ -233,7 +233,9 @@ func makeFileAppender(appenderConfig LogAppenderConfig) *LoggerAppender {
maxAge = ageInt
}
maxCount := int(1)
if count, ok := appenderConfig.Options["maxCount"].(int); ok {
if count, ok := appenderConfig.Options["maxCount"].(float64); ok {
maxCount = int(count)
} else if count, ok := appenderConfig.Options["maxCount"].(int); ok {
maxCount = count
}

226
file_test.go Normal file
View File

@ -0,0 +1,226 @@
package gologger
import (
"encoding/json"
"os"
"path/filepath"
"strings"
"testing"
"time"
)
func TestFileRollingBySize(t *testing.T) {
// 创建临时目录
tmpDir := t.TempDir()
logFile := filepath.Join(tmpDir, "test.log")
config := LogAppenderConfig{
Options: map[string]interface{}{
"file": logFile,
"enableRolling": true,
"maxSize": float64(1), // 1MB触发滚动
},
}
appender := *makeFileAppender(config)
f := appender.(*FileAppender)
defer f.Close()
// 写入小于 MaxSize 的日志,不应触发滚动
smallMsg := LogEvent{
Ts: time.Now(),
Category: "test",
Level: Info,
Data: []interface{}{"small message"},
}
f.Append(smallMsg)
time.Sleep(100 * time.Millisecond)
// 检查文件存在
if _, err := os.Stat(logFile); os.IsNotExist(err) {
t.Fatalf("log file should exist: %v", err)
}
// 写入大量日志,触发大小滚动
// 每次写入约100字节需要约10000次才能超过1MB
largeData := strings.Repeat("x", 100)
for i := 0; i < 10500; i++ {
msg := LogEvent{
Ts: time.Now(),
Category: "test",
Level: Info,
Data: []interface{}{largeData},
}
f.Append(msg)
}
time.Sleep(200 * time.Millisecond)
// 检查是否有滚动文件产生
files, _ := filepath.Glob(logFile + ".*")
if len(files) == 0 {
t.Fatalf("expected rolled file to exist, but none found")
}
t.Logf("Rolled files found: %v", files)
}
func TestFileRollingByMaxCount(t *testing.T) {
tmpDir := t.TempDir()
logFile := filepath.Join(tmpDir, "test.log")
config := LogAppenderConfig{
Options: map[string]interface{}{
"file": logFile,
"enableRolling": true,
"maxSize": float64(1), // 1MB
"maxCount": float64(3), // 最多保留3个旧文件
},
}
appender := *makeFileAppender(config)
f := appender.(*FileAppender)
defer f.Close()
// 多次触发滚动,产生多个旧文件
largeData := strings.Repeat("x", 1024)
for round := 0; round < 5; round++ {
for i := 0; i < 10500; i++ {
msg := LogEvent{
Ts: time.Now(),
Category: "test",
Level: Info,
Data: []interface{}{largeData},
}
f.Append(msg)
}
time.Sleep(100 * time.Millisecond)
}
// 等待清理完成
time.Sleep(300 * time.Millisecond)
// 检查旧文件数量不应超过 maxCount
files, _ := filepath.Glob(logFile + ".*")
if len(files) > 3 {
t.Errorf("expected at most %d rolled files, but got %d: %v", 3, len(files), files)
}
t.Logf("Rolled files count: %d, files: %v", len(files), files)
}
func TestFileRollingMaxCountFromJSON(t *testing.T) {
// 模拟 JSON 解析场景
jsonStr := `{
"enableRolling": true,
"file": "logs/test.log",
"maxSize": "50M",
"maxCount": 10
}`
var options map[string]interface{}
if err := json.Unmarshal([]byte(jsonStr), &options); err != nil {
t.Fatalf("json unmarshal failed: %v", err)
}
// 验证 JSON 解析后的 maxCount 类型
count := options["maxCount"]
t.Logf("maxCount type: %T, value: %v", count, count)
// 测试类型断言
if c, ok := options["maxCount"].(float64); ok {
t.Logf("maxCount as float64: %v -> int: %d", c, int(c))
if int(c) != 10 {
t.Errorf("expected maxCount=10, got %d", int(c))
}
} else if _, ok := options["maxCount"].(int); ok {
t.Log("maxCount is int type")
} else {
t.Errorf("maxCount has unexpected type: %T", count)
}
}
func TestMakeFileAppenderConfig(t *testing.T) {
tmpDir := t.TempDir()
logFile := filepath.Join(tmpDir, "app.log")
tests := []struct {
name string
config LogAppenderConfig
wantRolling bool
wantMaxSize int64
wantMaxCount int
}{
{
name: "string maxSize and maxCount",
config: LogAppenderConfig{
Options: map[string]interface{}{
"file": logFile,
"enableRolling": true,
"maxSize": "10MB",
"maxCount": float64(5),
},
},
wantRolling: true,
wantMaxSize: 10 * 1024 * 1024,
wantMaxCount: 5,
},
{
name: "int maxSize and int maxCount",
config: LogAppenderConfig{
Options: map[string]interface{}{
"file": logFile,
"enableRolling": true,
"maxSize": float64(20),
"maxCount": float64(3),
},
},
wantRolling: true,
wantMaxSize: 20 * 1024 * 1024,
wantMaxCount: 3,
},
{
name: "KB unit",
config: LogAppenderConfig{
Options: map[string]interface{}{
"file": logFile,
"enableRolling": true,
"maxSize": "100KB",
"maxCount": float64(2),
},
},
wantRolling: true,
wantMaxSize: 100 * 1024,
wantMaxCount: 2,
},
{
name: "GB unit",
config: LogAppenderConfig{
Options: map[string]interface{}{
"file": logFile,
"enableRolling": true,
"maxSize": "1GB",
"maxCount": float64(1),
},
},
wantRolling: true,
wantMaxSize: 1 * 1024 * 1024 * 1024,
wantMaxCount: 1,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
appender := *makeFileAppender(tt.config)
f := appender.(*FileAppender)
defer f.Close()
if f.EnableRolling != tt.wantRolling {
t.Errorf("EnableRolling = %v, want %v", f.EnableRolling, tt.wantRolling)
}
if f.MaxSize != tt.wantMaxSize {
t.Errorf("MaxSize = %v, want %v", f.MaxSize, tt.wantMaxSize)
}
if f.MaxCount != tt.wantMaxCount {
t.Errorf("MaxCount = %v, want %v", f.MaxCount, tt.wantMaxCount)
}
})
}
}