package logger import ( "bytes" "context" "strings" "testing" ) func TestTextFormat(t *testing.T) { buf := &bytes.Buffer{} l := New( WithOutputFile(""), WithFormat(TEXT), WithTimeFormat("2006-01-02"), ) l.mu.Lock() l.writer = buf l.mu.Unlock() l.Info("hello %s", "world") output := buf.String() if !strings.Contains(output, "hello world") { t.Errorf("expected 'hello world' in output, got: %s", output) } } func TestJSONFormat(t *testing.T) { buf := &bytes.Buffer{} l := New( WithOutputFile(""), WithFormat(JSON), ) l.mu.Lock() l.writer = buf l.mu.Unlock() l.Info("test message") output := buf.String() if !strings.Contains(output, `"message":"test message"`) { t.Errorf("expected JSON message in output, got: %s", output) } if !strings.Contains(output, `"level":"INFO"`) { t.Errorf("expected level INFO in output, got: %s", output) } } func TestWithFields(t *testing.T) { buf := &bytes.Buffer{} l := New( WithOutputFile(""), WithFormat(TEXT), ) l.mu.Lock() l.writer = buf l.mu.Unlock() l.InfoField("user logged in", "user_id", 123, "action", "login", ) output := buf.String() if !strings.Contains(output, "user_id=123") { t.Errorf("expected user_id=123 in output, got: %s", output) } if !strings.Contains(output, "action=login") { t.Errorf("expected action=login in output, got: %s", output) } } func TestContextTraceID(t *testing.T) { buf := &bytes.Buffer{} l := New( WithOutputFile(""), WithFormat(JSON), ) l.mu.Lock() l.writer = buf l.mu.Unlock() ctx := context.WithValue(context.Background(), "trace_id", "req-123") l.InfoCtx(ctx, "request processed") output := buf.String() if !strings.Contains(output, `"trace_id":"req-123"`) { t.Errorf("expected trace_id in output, got: %s", output) } } func TestCustomFieldKey(t *testing.T) { buf := &bytes.Buffer{} l := New( WithOutputFile(""), WithFormat(JSON), WithFieldKey("request_id"), ) l.mu.Lock() l.writer = buf l.mu.Unlock() ctx := context.WithValue(context.Background(), "request_id", "req-456") l.InfoCtx(ctx, "request processed") output := buf.String() if !strings.Contains(output, `"request_id":"req-456"`) { t.Errorf("expected request_id in output, got: %s", output) } } func TestCaller(t *testing.T) { buf := &bytes.Buffer{} l := New( WithOutputFile(""), WithFormat(TEXT), WithCaller(true), ) l.mu.Lock() l.writer = buf l.mu.Unlock() l.Info("test caller") output := buf.String() if !strings.Contains(output, "logger_test.go:") { t.Errorf("expected caller info in output, got: %s", output) } } func TestLevelFiltering(t *testing.T) { buf := &bytes.Buffer{} l := New( WithOutputFile(""), WithLevel(ERROR), ) l.mu.Lock() l.writer = buf l.mu.Unlock() l.Debug("debug message") l.Info("info message") l.Error("error message") output := buf.String() if strings.Contains(output, "debug message") { t.Errorf("debug message should be filtered out, got: %s", output) } if strings.Contains(output, "info message") { t.Errorf("info message should be filtered out, got: %s", output) } if !strings.Contains(output, "error message") { t.Errorf("error message should be present, got: %s", output) } } func TestGlobalLogger(t *testing.T) { buf := &bytes.Buffer{} original := defaultLogger defer func() { defaultLogger = original }() defaultLogger = New( WithOutputFile(""), WithFormat(TEXT), ) defaultLogger.mu.Lock() defaultLogger.writer = buf defaultLogger.mu.Unlock() Info("global logger test") output := buf.String() if !strings.Contains(output, "global logger test") { t.Errorf("expected global logger output, got: %s", output) } } // Benchmarks func benchmarkLogger(format Format, caller bool) *Logger { buf := &bytes.Buffer{} l := New( WithOutputFile(""), WithFormat(format), WithCaller(caller), ) l.mu.Lock() l.writer = buf l.mu.Unlock() return l } func BenchmarkInfoText(b *testing.B) { l := benchmarkLogger(TEXT, false) msg := "hello world" b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { l.Info("hello world") _ = msg } } func BenchmarkInfoTextWithArgs(b *testing.B) { l := benchmarkLogger(TEXT, false) b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { l.Info("user %s logged in from %s", "john", "192.168.1.1") } } func BenchmarkInfoJSON(b *testing.B) { l := benchmarkLogger(JSON, false) b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { l.Info("hello world") } } func BenchmarkInfoField(b *testing.B) { l := benchmarkLogger(TEXT, false) b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { l.InfoField("user logged in", "user_id", 123, "action", "login", "ip", "192.168.1.1", ) } } func BenchmarkInfoFieldJSON(b *testing.B) { l := benchmarkLogger(JSON, false) b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { l.InfoField("user logged in", "user_id", 123, "action", "login", "ip", "192.168.1.1", ) } } func BenchmarkInfoWithCaller(b *testing.B) { l := benchmarkLogger(TEXT, true) b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { l.Info("hello world") } } func BenchmarkInfoCtx(b *testing.B) { l := benchmarkLogger(JSON, false) ctx := context.WithValue(context.Background(), "trace_id", "req-123456789") b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { l.InfoCtx(ctx, "request processed") } } func BenchmarkInfoFiltered(b *testing.B) { l := New( WithOutputFile(""), WithLevel(ERROR), ) l.mu.Lock() l.writer = &bytes.Buffer{} l.mu.Unlock() b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { l.Info("this should be filtered") } } func BenchmarkManyFields(b *testing.B) { l := benchmarkLogger(JSON, false) b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { l.InfoField("event", "field1", "value1", "field2", "value2", "field3", "value3", "field4", "value4", "field5", "value5", "field6", "value6", "field7", "value7", "field8", "value8", ) } } func BenchmarkGlobalInfo(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { Info("hello world") } } func BenchmarkGlobalInfoField(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { InfoField("event", "key1", "value1", "key2", "value2", ) } }