diff --git a/file.go b/file.go index 0f74c64..6dbd29b 100644 --- a/file.go +++ b/file.go @@ -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 } diff --git a/file_test.go b/file_test.go new file mode 100644 index 0000000..f017075 --- /dev/null +++ b/file_test.go @@ -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) + } + }) + } +}