1
0
mirror of https://github.com/taigrr/log-socket synced 2026-03-20 16:02:28 -07:00
Files
log-socket/log/benchmark_test.go
Tai Groot 085aadaaef test(log): add comprehensive benchmarks
Adds a new benchmark_test.go file with comprehensive benchmarks for the logging library:

Serial benchmarks:
- Trace, Debug, Info, Notice, Warn, Error levels

Formatted logging:
- Debugf, Infof, Errorf variants

Parallel benchmarks:
- DebugParallel, InfoParallel, InfofParallel

Logger instance (namespaced):
- LoggerInfo, LoggerInfof, LoggerDebugParallel

Multiple clients/namespaces:
- MultipleClients, MultipleNamespaces

Message size comparison:
- Short, Medium, Long messages

Level filtering overhead:
- DebugFilteredByLevel

Also removes the duplicate BenchmarkDebugSerial from log_test.go and applies minor whitespace formatting fixes.

Fixes #6
2026-02-10 08:04:08 +00:00

390 lines
8.8 KiB
Go

package log
import (
"testing"
)
// drainClient continuously reads from a client to prevent blocking.
// Returns a function to stop draining and wait for completion.
func drainClient(c *Client) func() {
done := make(chan struct{})
go func() {
for {
select {
case <-done:
return
case <-c.writer:
// Drain entries
}
}
}()
return func() { close(done) }
}
// -----------------------------------------------------------------------------
// Serial Benchmarks - Single Log Levels
// -----------------------------------------------------------------------------
func BenchmarkTrace(b *testing.B) {
c := CreateClient(DefaultNamespace)
c.SetLogLevel(LTrace)
stop := drainClient(c)
defer stop()
defer c.Destroy()
b.ResetTimer()
for i := 0; i < b.N; i++ {
Trace("benchmark message")
}
}
func BenchmarkDebug(b *testing.B) {
c := CreateClient(DefaultNamespace)
c.SetLogLevel(LDebug)
stop := drainClient(c)
defer stop()
defer c.Destroy()
b.ResetTimer()
for i := 0; i < b.N; i++ {
Debug("benchmark message")
}
}
func BenchmarkInfo(b *testing.B) {
c := CreateClient(DefaultNamespace)
c.SetLogLevel(LInfo)
stop := drainClient(c)
defer stop()
defer c.Destroy()
b.ResetTimer()
for i := 0; i < b.N; i++ {
Info("benchmark message")
}
}
func BenchmarkNotice(b *testing.B) {
c := CreateClient(DefaultNamespace)
c.SetLogLevel(LNotice)
stop := drainClient(c)
defer stop()
defer c.Destroy()
b.ResetTimer()
for i := 0; i < b.N; i++ {
Notice("benchmark message")
}
}
func BenchmarkWarn(b *testing.B) {
c := CreateClient(DefaultNamespace)
c.SetLogLevel(LWarn)
stop := drainClient(c)
defer stop()
defer c.Destroy()
b.ResetTimer()
for i := 0; i < b.N; i++ {
Warn("benchmark message")
}
}
func BenchmarkError(b *testing.B) {
c := CreateClient(DefaultNamespace)
c.SetLogLevel(LError)
stop := drainClient(c)
defer stop()
defer c.Destroy()
b.ResetTimer()
for i := 0; i < b.N; i++ {
Error("benchmark message")
}
}
// -----------------------------------------------------------------------------
// Formatted Logging Benchmarks
// -----------------------------------------------------------------------------
func BenchmarkDebugf(b *testing.B) {
c := CreateClient(DefaultNamespace)
c.SetLogLevel(LDebug)
stop := drainClient(c)
defer stop()
defer c.Destroy()
b.ResetTimer()
for i := 0; i < b.N; i++ {
Debugf("benchmark message %d with %s", i, "formatting")
}
}
func BenchmarkInfof(b *testing.B) {
c := CreateClient(DefaultNamespace)
c.SetLogLevel(LInfo)
stop := drainClient(c)
defer stop()
defer c.Destroy()
b.ResetTimer()
for i := 0; i < b.N; i++ {
Infof("benchmark message %d with %s", i, "formatting")
}
}
func BenchmarkErrorf(b *testing.B) {
c := CreateClient(DefaultNamespace)
c.SetLogLevel(LError)
stop := drainClient(c)
defer stop()
defer c.Destroy()
b.ResetTimer()
for i := 0; i < b.N; i++ {
Errorf("benchmark message %d with %s", i, "formatting")
}
}
// -----------------------------------------------------------------------------
// Parallel Benchmarks
// -----------------------------------------------------------------------------
func BenchmarkDebugParallel(b *testing.B) {
c := CreateClient(DefaultNamespace)
c.SetLogLevel(LDebug)
stop := drainClient(c)
defer stop()
defer c.Destroy()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
Debug("parallel benchmark message")
}
})
}
func BenchmarkInfoParallel(b *testing.B) {
c := CreateClient(DefaultNamespace)
c.SetLogLevel(LInfo)
stop := drainClient(c)
defer stop()
defer c.Destroy()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
Info("parallel benchmark message")
}
})
}
func BenchmarkInfofParallel(b *testing.B) {
c := CreateClient(DefaultNamespace)
c.SetLogLevel(LInfo)
stop := drainClient(c)
defer stop()
defer c.Destroy()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
counter := 0
for pb.Next() {
Infof("parallel benchmark message %d", counter)
counter++
}
})
}
// -----------------------------------------------------------------------------
// Logger Instance Benchmarks (Namespaced Logging)
// -----------------------------------------------------------------------------
func BenchmarkLoggerInfo(b *testing.B) {
logger := NewLogger("benchmark")
c := CreateClient("benchmark")
c.SetLogLevel(LInfo)
stop := drainClient(c)
defer stop()
defer c.Destroy()
b.ResetTimer()
for i := 0; i < b.N; i++ {
logger.Info("benchmark message")
}
}
func BenchmarkLoggerInfof(b *testing.B) {
logger := NewLogger("benchmark")
c := CreateClient("benchmark")
c.SetLogLevel(LInfo)
stop := drainClient(c)
defer stop()
defer c.Destroy()
b.ResetTimer()
for i := 0; i < b.N; i++ {
logger.Infof("benchmark message %d", i)
}
}
func BenchmarkLoggerDebugParallel(b *testing.B) {
logger := NewLogger("benchmark")
c := CreateClient("benchmark")
c.SetLogLevel(LDebug)
stop := drainClient(c)
defer stop()
defer c.Destroy()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Debug("parallel benchmark message")
}
})
}
// -----------------------------------------------------------------------------
// Multiple Client Benchmarks
// -----------------------------------------------------------------------------
func BenchmarkMultipleClients(b *testing.B) {
const numClients = 5
var clients []*Client
var stopFuncs []func()
for i := 0; i < numClients; i++ {
c := CreateClient(DefaultNamespace)
c.SetLogLevel(LInfo)
stop := drainClient(c)
clients = append(clients, c)
stopFuncs = append(stopFuncs, stop)
}
defer func() {
for i, c := range clients {
stopFuncs[i]()
c.Destroy()
}
}()
b.ResetTimer()
for i := 0; i < b.N; i++ {
Info("benchmark message to multiple clients")
}
}
func BenchmarkMultipleNamespaces(b *testing.B) {
namespaces := []string{"auth", "db", "api", "cache", "queue"}
var loggers []*Logger
var clients []*Client
var stopFuncs []func()
for _, ns := range namespaces {
loggers = append(loggers, NewLogger(ns))
c := CreateClient(ns)
c.SetLogLevel(LInfo)
stop := drainClient(c)
clients = append(clients, c)
stopFuncs = append(stopFuncs, stop)
}
defer func() {
for i, c := range clients {
stopFuncs[i]()
c.Destroy()
}
}()
b.ResetTimer()
for i := 0; i < b.N; i++ {
loggers[i%len(loggers)].Info("benchmark message")
}
}
// -----------------------------------------------------------------------------
// With Synchronous Client Consumption (Legacy Pattern)
// -----------------------------------------------------------------------------
// BenchmarkDebugWithSyncConsumer measures the overhead of synchronous consumption
// using the Get() method, processing one message at a time.
func BenchmarkDebugWithSyncConsumer(b *testing.B) {
c := CreateClient(DefaultNamespace)
c.SetLogLevel(LDebug)
stop := drainClient(c)
defer stop()
defer c.Destroy()
// This benchmark measures just the logging side with async draining.
// For sync consumption patterns, see the TestOrder test.
b.ResetTimer()
for i := 0; i < b.N; i++ {
Debug("benchmark message")
}
}
// -----------------------------------------------------------------------------
// Comparison Benchmarks (Different Message Sizes)
// -----------------------------------------------------------------------------
func BenchmarkInfoShortMessage(b *testing.B) {
c := CreateClient(DefaultNamespace)
c.SetLogLevel(LInfo)
stop := drainClient(c)
defer stop()
defer c.Destroy()
b.ResetTimer()
for i := 0; i < b.N; i++ {
Info("ok")
}
}
func BenchmarkInfoMediumMessage(b *testing.B) {
c := CreateClient(DefaultNamespace)
c.SetLogLevel(LInfo)
stop := drainClient(c)
defer stop()
defer c.Destroy()
msg := "This is a medium-length log message for benchmarking purposes"
b.ResetTimer()
for i := 0; i < b.N; i++ {
Info(msg)
}
}
func BenchmarkInfoLongMessage(b *testing.B) {
c := CreateClient(DefaultNamespace)
c.SetLogLevel(LInfo)
stop := drainClient(c)
defer stop()
defer c.Destroy()
msg := "This is a much longer log message that simulates real-world logging scenarios where developers tend to include more context about what the application is doing, including variable values, request IDs, and other debugging information that can be quite verbose"
b.ResetTimer()
for i := 0; i < b.N; i++ {
Info(msg)
}
}
// -----------------------------------------------------------------------------
// Overhead Benchmarks (Level Filtering)
// -----------------------------------------------------------------------------
func BenchmarkDebugFilteredByLevel(b *testing.B) {
// No client with Debug level, so Debug logs won't be consumed
// This measures the overhead of creating log entries that get filtered
c := CreateClient(DefaultNamespace)
c.SetLogLevel(LError) // Only Error and above
stop := drainClient(c)
defer stop()
defer c.Destroy()
b.ResetTimer()
for i := 0; i < b.N; i++ {
Debug("this message will be filtered")
}
}