mirror of
https://github.com/yusing/godoxy.git
synced 2026-02-22 18:37:46 +01:00
Major refactoring of the access logging infrastructure to improve code organization and add proper console/stdout logging support. - Renamed `Writer` interface to `File` and consolidated with `SupportRotate` - Renamed `Log(req, res)` to `LogRequest(req, res)` for clarity - Added new `ConsoleLogger` with zerolog console writer for formatted stdout output - Moved type definitions to new `types.go` file - Changed buffer handling from `[]byte` returns to `*bytes.Buffer` parameters - Renamed internal files for clarity (`access_logger.go` → `file_access_logger.go`) - Fixed fileserver access logging timing: moved logging after handler execution with defer - Correct response handling in Fileserver - Remove deprecated field `buffer_size` - Simplify and removed unnecessary code All callers have been updated to use the new APIs.
103 lines
2.1 KiB
Go
103 lines
2.1 KiB
Go
package accesslog
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand/v2"
|
|
"net/http"
|
|
"os"
|
|
"runtime"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/yusing/goutils/task"
|
|
"golang.org/x/sync/errgroup"
|
|
)
|
|
|
|
func TestConcurrentFileLoggersShareSameAccessLogIO(t *testing.T) {
|
|
cfg := DefaultRequestLoggerConfig()
|
|
cfg.Path = "test.log"
|
|
|
|
loggerCount := runtime.GOMAXPROCS(0)
|
|
accessLogIOs := make([]File, loggerCount)
|
|
|
|
// make test log file
|
|
file, err := os.Create(cfg.Path)
|
|
assert.NoError(t, err)
|
|
file.Close()
|
|
t.Cleanup(func() {
|
|
assert.NoError(t, os.Remove(cfg.Path))
|
|
})
|
|
|
|
var errs errgroup.Group
|
|
for i := range loggerCount {
|
|
errs.Go(func() error {
|
|
file, err := OpenFile(cfg.Path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
accessLogIOs[i] = file
|
|
return nil
|
|
})
|
|
}
|
|
|
|
err = errs.Wait()
|
|
assert.NoError(t, err)
|
|
|
|
firstIO := accessLogIOs[0]
|
|
for _, io := range accessLogIOs {
|
|
assert.Equal(t, firstIO, io)
|
|
}
|
|
}
|
|
|
|
func TestConcurrentAccessLoggerLogAndFlush(t *testing.T) {
|
|
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)
|
|
|
|
loggerCount := runtime.GOMAXPROCS(0)
|
|
logCountPerLogger := 10
|
|
loggers := make([]AccessLogger, loggerCount)
|
|
|
|
for i := range loggerCount {
|
|
loggers[i] = NewFileAccessLogger(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)
|
|
})
|
|
}
|
|
}
|
|
|
|
func concurrentLog(logger AccessLogger, req *http.Request, resp *http.Response, n int) {
|
|
var wg sync.WaitGroup
|
|
for range n {
|
|
wg.Go(func() {
|
|
logger.LogRequest(req, resp)
|
|
if rand.IntN(2) == 0 {
|
|
logger.Flush()
|
|
}
|
|
})
|
|
}
|
|
wg.Wait()
|
|
}
|