Files
log/benchmark_test.go
T
Claude f9b8770303
Test / test (push) Canceled after 0s
Test / fuzz (./compat, FuzzParseFormat) (push) Canceled after 0s
Test / fuzz (./formatter, FuzzFormatJSON) (push) Canceled after 0s
Test / fuzz (./formatter, FuzzFormatTextPolicy) (push) Canceled after 0s
Test / fuzz (./sanitizer, FuzzSanitize) (push) Canceled after 0s
Test / fuzz (./sanitizer, FuzzSerializerJSON) (push) Canceled after 0s
v0.1.13 follow a replaced, removed, moved log file properly
2026-10-15 16:54:39 -04:00

133 lines
3.5 KiB
Go

package log
import (
"testing"
"time"
)
// The benchmarks up to BenchmarkProcessLogRecord measure the producer path:
// format selection, channel send, and drop accounting. File writes complete
// asynchronously in the processor and are not attributed to their iterations.
// BenchmarkLoggerInfo measures the default raw-format path.
func BenchmarkLoggerInfo(b *testing.B) {
logger, _ := newTestLogger(b)
b.ReportAllocs()
for i := 0; b.Loop(); i++ {
logger.Info("benchmark message", i)
}
}
// BenchmarkLoggerTxt measures enqueueing with txt output selected.
func BenchmarkLoggerTxt(b *testing.B) {
logger, _ := newTestLogger(b)
cfg := logger.GetConfig()
cfg.Format = "txt"
mustNoErr(b, logger.ApplyConfig(cfg), "ApplyConfig")
b.ReportAllocs()
for i := 0; b.Loop(); i++ {
logger.Info("benchmark message", i)
}
}
// BenchmarkLoggerJSON measures the json path with key/value arguments.
func BenchmarkLoggerJSON(b *testing.B) {
logger, _ := newTestLogger(b)
cfg := logger.GetConfig()
cfg.Format = "json"
mustNoErr(b, logger.ApplyConfig(cfg), "ApplyConfig")
b.ReportAllocs()
for i := 0; b.Loop(); i++ {
logger.Info("benchmark message", i, "key", "value")
}
}
// BenchmarkLoggerStructured measures enqueueing and snapshotting structured maps.
func BenchmarkLoggerStructured(b *testing.B) {
logger, _ := newTestLogger(b)
cfg := logger.GetConfig()
cfg.Format = "json"
mustNoErr(b, logger.ApplyConfig(cfg), "ApplyConfig")
fields := map[string]any{
"user_id": 123,
"action": "benchmark",
"value": 42.5,
}
b.ReportAllocs()
for b.Loop() {
logger.LogStructured(LevelInfo, "benchmark", fields)
}
}
// BenchmarkLoggerSanitized measures enqueueing with PolicyTxt selected;
// sanitizer CPU work runs asynchronously and is benchmarked in its own package.
func BenchmarkLoggerSanitized(b *testing.B) {
logger, _ := newTestLogger(b)
cfg := logger.GetConfig()
cfg.Format = "txt"
cfg.Sanitization = PolicyTxt
mustNoErr(b, logger.ApplyConfig(cfg), "ApplyConfig")
b.ReportAllocs()
for i := 0; b.Loop(); i++ {
logger.Info("benchmark message", i)
}
}
// BenchmarkConcurrentLogging measures contention on the shared channel.
func BenchmarkConcurrentLogging(b *testing.B) {
logger, _ := newTestLogger(b)
b.ReportAllocs()
b.RunParallel(func(pb *testing.PB) {
i := 0
for pb.Next() {
logger.Info("concurrent", i)
i++
}
})
}
// BenchmarkProcessLogRecord measures the processor's write path, which the
// producer benchmarks above do not see. Record stamps advance by step to stand
// for a logging rate: at 100/s every record is due a log path check.
func BenchmarkProcessLogRecord(b *testing.B) {
for _, bc := range []struct {
name string
step time.Duration // 0: time.Now per record, as emit stamps it
}{{"ts=now", 0}, {"rate=1k/s", time.Millisecond}, {"rate=100/s", 10 * time.Millisecond}} {
b.Run(bc.name, func(b *testing.B) {
l := NewLogger()
c := DefaultConfig()
c.EnableConsole = false
c.EnableFile = true
c.Directory = b.TempDir()
c.Format = "txt"
c.MaxSizeKB = 0
mustNoErr(b, l.ApplyConfig(c), "ApplyConfig") // not started: the benchmark is the processor
b.Cleanup(func() { _ = l.Shutdown() })
rec := logRecord{Flags: l.getFlags(), Level: LevelInfo, Args: []any{"benchmark message", 42}}
ts := time.Now()
b.ReportAllocs()
for b.Loop() {
if ts = ts.Add(bc.step); bc.step == 0 {
ts = time.Now()
}
rec.TimeStamp = ts
if l.processLogRecord(rec) == 0 {
b.Fatal("record not written")
}
}
})
}
}