- 添加 lumberjack.v2 依赖实现日志轮转 - 支持配置文件输出(stdout/stderr/file) - 支持文件轮转(100MB/3备份/7天/压缩) - 添加 Config 结构体灵活配置 - 添加完整测试用例 测试验证: - TestInitWithConfig PASS - TestInitWithConfigFileOutput PASS - TestDefaultConfig PASS - 全量日志测试通过
190 lines
3.8 KiB
Go
190 lines
3.8 KiB
Go
package log
|
|
|
|
import (
|
|
"log/slog"
|
|
"os"
|
|
"testing"
|
|
)
|
|
|
|
func TestInit(t *testing.T) {
|
|
// Save original stdout
|
|
oldLogger := logger
|
|
defer func() { logger = oldLogger }()
|
|
|
|
Init()
|
|
|
|
if logger == nil {
|
|
t.Error("logger should not be nil after Init")
|
|
}
|
|
}
|
|
|
|
func TestInitWithLevel(t *testing.T) {
|
|
// Test different levels
|
|
levels := []string{"DEBUG", "INFO", "WARN", "ERROR", "unknown"}
|
|
|
|
for _, level := range levels {
|
|
InitWithLevel(level)
|
|
if logger == nil {
|
|
t.Errorf("logger should not be nil for level %s", level)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestParseLevel(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
expected slog.Level
|
|
}{
|
|
{"DEBUG", slog.LevelDebug},
|
|
{"debug", slog.LevelDebug},
|
|
{"INFO", slog.LevelInfo},
|
|
{"info", slog.LevelInfo},
|
|
{"WARN", slog.LevelWarn},
|
|
{"WARNING", slog.LevelWarn},
|
|
{"ERROR", slog.LevelError},
|
|
{"error", slog.LevelError},
|
|
{"unknown", slog.LevelInfo},
|
|
{"", slog.LevelInfo},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
result := parseLevel(test.input)
|
|
if result != test.expected {
|
|
t.Errorf("parseLevel(%q) = %v, want %v", test.input, result, test.expected)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestIsSensitive(t *testing.T) {
|
|
sensitive := []string{
|
|
"token",
|
|
"password",
|
|
"secret",
|
|
"api_key",
|
|
"access_token",
|
|
"PRIVATE_KEY",
|
|
}
|
|
|
|
for _, field := range sensitive {
|
|
if !IsSensitive(field) {
|
|
t.Errorf("IsSensitive(%q) should be true", field)
|
|
}
|
|
}
|
|
|
|
notSensitive := []string{
|
|
"name",
|
|
"email",
|
|
"user_id",
|
|
}
|
|
|
|
for _, field := range notSensitive {
|
|
if IsSensitive(field) {
|
|
t.Errorf("IsSensitive(%q) should be false", field)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSanitizeAttrs(t *testing.T) {
|
|
// Test that sensitive fields are redacted
|
|
tests := []struct {
|
|
key string
|
|
value string
|
|
expected string
|
|
}{
|
|
{"password", "secret123", "[REDACTED]"},
|
|
{"api_token", "abc123", "[REDACTED]"},
|
|
{"secret_key", "xyz789", "[REDACTED]"},
|
|
{"name", "test", "test"},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
attr := slog.String(test.key, test.value)
|
|
result := sanitizeAttrs(nil, attr)
|
|
if result.Value.String() != test.expected {
|
|
t.Errorf("sanitizeAttrs(%q) = %q, want %q", test.key, result.Value.String(), test.expected)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLoggingMethods(t *testing.T) {
|
|
// Just verify methods don't panic
|
|
Init()
|
|
|
|
Info("test info message", "key", "value")
|
|
Debug("test debug message", "key", "value")
|
|
Warn("test warn message", "key", "value")
|
|
Error("test error message", "key", "value")
|
|
}
|
|
|
|
func TestLogger(t *testing.T) {
|
|
Init()
|
|
l := Logger()
|
|
if l == nil {
|
|
t.Error("Logger() should not return nil")
|
|
}
|
|
}
|
|
|
|
func TestRequestLogger(t *testing.T) {
|
|
Init()
|
|
l := RequestLogger("GET", "/api/hosts", "127.0.0.1")
|
|
if l == nil {
|
|
t.Error("RequestLogger should not return nil")
|
|
}
|
|
}
|
|
|
|
func TestInitWithConfig(t *testing.T) {
|
|
// Test with stdout output
|
|
cfg := DefaultConfig()
|
|
cfg.Output = "stdout"
|
|
cfg.Level = "DEBUG"
|
|
InitWithConfig(cfg)
|
|
|
|
if logger == nil {
|
|
t.Error("logger should not be nil after InitWithConfig")
|
|
}
|
|
}
|
|
|
|
func TestInitWithConfigFileOutput(t *testing.T) {
|
|
// Test with file output (no rotation)
|
|
tmpFile := t.TempDir() + "/test.log"
|
|
cfg := DefaultConfig()
|
|
cfg.Output = tmpFile
|
|
cfg.Rotation = false
|
|
InitWithConfig(cfg)
|
|
|
|
Info("test message for file")
|
|
|
|
// Verify file was created
|
|
if _, err := os.Stat(tmpFile); os.IsNotExist(err) {
|
|
t.Errorf("log file %s should exist", tmpFile)
|
|
}
|
|
}
|
|
|
|
func TestDefaultConfig(t *testing.T) {
|
|
cfg := DefaultConfig()
|
|
|
|
if cfg.Level != "INFO" {
|
|
t.Errorf("default Level = %s, want INFO", cfg.Level)
|
|
}
|
|
|
|
if cfg.Output != "stdout" {
|
|
t.Errorf("default Output = %s, want stdout", cfg.Output)
|
|
}
|
|
|
|
if cfg.MaxSize != 100 {
|
|
t.Errorf("default MaxSize = %d, want 100", cfg.MaxSize)
|
|
}
|
|
|
|
if cfg.MaxBackups != 3 {
|
|
t.Errorf("default MaxBackups = %d, want 3", cfg.MaxBackups)
|
|
}
|
|
|
|
if cfg.MaxAge != 7 {
|
|
t.Errorf("default MaxAge = %d, want 7", cfg.MaxAge)
|
|
}
|
|
|
|
if !cfg.Compress {
|
|
t.Error("default Compress should be true")
|
|
}
|
|
}
|