mirror of
https://github.com/yusing/godoxy.git
synced 2026-04-23 17:28:53 +02:00
fix(access_logger): nil panic when stdout only, improve concurrency safety
This commit is contained in:
@@ -1,89 +1,96 @@
|
||||
package accesslog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand/v2"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/yusing/goutils/task"
|
||||
expect "github.com/yusing/goutils/testing"
|
||||
)
|
||||
|
||||
func TestConcurrentFileLoggersShareSameAccessLogIO(t *testing.T) {
|
||||
var wg sync.WaitGroup
|
||||
|
||||
cfg := DefaultRequestLoggerConfig()
|
||||
cfg.Path = "test.log"
|
||||
|
||||
loggerCount := 10
|
||||
accessLogIOs := make([]WriterWithName, loggerCount)
|
||||
loggerCount := runtime.GOMAXPROCS(0)
|
||||
accessLogIOs := make([]Writer, loggerCount)
|
||||
|
||||
// make test log file
|
||||
file, err := os.Create(cfg.Path)
|
||||
expect.NoError(t, err)
|
||||
assert.NoError(t, err)
|
||||
file.Close()
|
||||
t.Cleanup(func() {
|
||||
expect.NoError(t, os.Remove(cfg.Path))
|
||||
assert.NoError(t, os.Remove(cfg.Path))
|
||||
})
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for i := range loggerCount {
|
||||
wg.Add(1)
|
||||
go func(index int) {
|
||||
defer wg.Done()
|
||||
wg.Go(func() {
|
||||
file, err := NewFileIO(cfg.Path)
|
||||
expect.NoError(t, err)
|
||||
accessLogIOs[index] = file
|
||||
}(i)
|
||||
assert.NoError(t, err)
|
||||
accessLogIOs[i] = file
|
||||
})
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
firstIO := accessLogIOs[0]
|
||||
for _, io := range accessLogIOs {
|
||||
expect.Equal(t, io, firstIO)
|
||||
assert.Equal(t, firstIO, io)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConcurrentAccessLoggerLogAndFlush(t *testing.T) {
|
||||
file := NewMockFile()
|
||||
for _, buffered := range []bool{false, true} {
|
||||
t.Run(fmt.Sprintf("buffered=%t", buffered), func(t *testing.T) {
|
||||
file := NewMockFile(buffered)
|
||||
|
||||
cfg := DefaultRequestLoggerConfig()
|
||||
parent := task.RootTask("test", false)
|
||||
cfg := DefaultRequestLoggerConfig()
|
||||
parent := task.RootTask("test", false)
|
||||
|
||||
loggerCount := 5
|
||||
logCountPerLogger := 10
|
||||
loggers := make([]*AccessLogger, loggerCount)
|
||||
loggerCount := runtime.GOMAXPROCS(0)
|
||||
logCountPerLogger := 10
|
||||
loggers := make([]*AccessLogger, loggerCount)
|
||||
|
||||
for i := range loggerCount {
|
||||
loggers[i] = NewAccessLoggerWithIO(parent, file, cfg)
|
||||
for i := range loggerCount {
|
||||
loggers[i] = NewAccessLoggerWithIO(parent, file, cfg)
|
||||
}
|
||||
|
||||
req, _ := http.NewRequest(http.MethodGet, "http://example.com", nil)
|
||||
resp := &http.Response{StatusCode: http.StatusOK}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for _, logger := range loggers {
|
||||
wg.Go(func() {
|
||||
concurrentLog(logger, req, resp, logCountPerLogger)
|
||||
})
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
for _, logger := range loggers {
|
||||
logger.Close()
|
||||
}
|
||||
|
||||
expected := loggerCount * logCountPerLogger
|
||||
actual := file.NumLines()
|
||||
assert.Equal(t, expected, actual)
|
||||
})
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
req, _ := http.NewRequest(http.MethodGet, "http://example.com", nil)
|
||||
resp := &http.Response{StatusCode: http.StatusOK}
|
||||
|
||||
wg.Add(len(loggers))
|
||||
for _, logger := range loggers {
|
||||
go func(l *AccessLogger) {
|
||||
defer wg.Done()
|
||||
parallelLog(l, req, resp, logCountPerLogger)
|
||||
l.Flush()
|
||||
}(logger)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
expected := loggerCount * logCountPerLogger
|
||||
actual := file.NumLines()
|
||||
expect.Equal(t, actual, expected)
|
||||
}
|
||||
|
||||
func parallelLog(logger *AccessLogger, req *http.Request, resp *http.Response, n int) {
|
||||
func concurrentLog(logger *AccessLogger, req *http.Request, resp *http.Response, n int) {
|
||||
var wg sync.WaitGroup
|
||||
for range n {
|
||||
wg.Go(func() {
|
||||
logger.Log(req, resp)
|
||||
if rand.IntN(2) == 0 {
|
||||
logger.Flush()
|
||||
}
|
||||
})
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
Reference in New Issue
Block a user