fix: add write mutex for log writing to file

This commit is contained in:
ukpratik 2026-03-01 11:31:13 +05:30
parent cadcdc0b41
commit a675c9ba33
2 changed files with 53 additions and 2 deletions

View file

@ -38,6 +38,14 @@ var (
type Logger struct {
file *os.File
// writeMu serializes file writes.
// Although POSIX systems typically guarantee atomicity
// for single write() syscalls on regular files,
// Windows and some filesystems may not.
//
// This prevents log line interleaving across platforms.
writeMu sync.Mutex
}
type LogEntry struct {
@ -116,12 +124,22 @@ func logMessage(level LogLevel, component string, message string, fields map[str
}
}
if logger.file != nil {
mu.RLock()
fileptr := logger.file
if fileptr != nil {
jsonData, err := json.Marshal(entry)
if err == nil {
logger.file.Write(append(jsonData, '\n'))
logger.writeMu.Lock()
_, err = fileptr.WriteString(string(jsonData) + "\n")
logger.writeMu.Unlock()
if err != nil {
log.Println("Failed to write to file:", err.Error())
}
}
}
mu.RUnlock()
var fieldStr string
if len(fields) > 0 {

View file

@ -1,6 +1,11 @@
package logger
import (
"fmt"
"os"
"path/filepath"
"strings"
"sync"
"testing"
)
@ -137,3 +142,31 @@ func TestLoggerHelperFunctions(t *testing.T) {
DebugC("test", "Debug with component")
WarnF("Warning with fields", map[string]any{"key": "value"})
}
// TestConcurrentFileLogging validates concurrent file writes are race-safe and complete.
// Run: go test -race ./pkg/logger -run TestConcurrentFileLogging -count=1
func TestConcurrentFileLogging(t *testing.T) {
dir := t.TempDir()
logFile := filepath.Join(dir, "test.log")
if err := EnableFileLogging(logFile); err != nil {
t.Fatal(err)
}
defer DisableFileLogging()
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func(n int) {
defer wg.Done()
InfoCF("test", fmt.Sprintf("msg-%d", n), map[string]any{"n": n})
}(i)
}
wg.Wait()
data, err := os.ReadFile(logFile)
if err != nil {
t.Fatal(err)
}
lines := strings.Split(strings.TrimSpace(string(data)), "\n")
if len(lines) != 100 {
t.Errorf("expected 100 log lines, got %d", len(lines))
}
}