Add configurable access log sampling via : - 0.0-1.0 range; defaults to 1.0 (record all) for backward compatibility - Uses lock-free atomic counter for deterministic sampling - Non-2xx responses always logged regardless of sample rate Benchmark results (combined format, /dev/null): Full logging: ~2245 ns/op, 1987 B/op, 17 allocs/op 10% sampling: ~1593 ns/op, 1633 B/op, 6 allocs/op Improvement: -29% latency, -65% allocations/op This addresses the top application-layer CPU hotspot identified in the v0.4.0 profile (LogAccess at 16.36% cumulative CPU).
105 lines
2.4 KiB
Go
105 lines
2.4 KiB
Go
// Package accesslog 提供访问日志中间件的基准测试。
|
||
//
|
||
// 该文件测试日志记录的性能开销。
|
||
//
|
||
// 作者:xfy
|
||
package accesslog
|
||
|
||
import (
|
||
"testing"
|
||
|
||
"github.com/valyala/fasthttp"
|
||
"rua.plus/lolly/internal/config"
|
||
)
|
||
|
||
// BenchmarkAccessLogProcess 测试访问日志中间件处理性能。
|
||
func BenchmarkAccessLogProcess(b *testing.B) {
|
||
cfg := &config.LoggingConfig{
|
||
Access: config.AccessLogConfig{
|
||
Path: "/dev/null",
|
||
Format: "combined",
|
||
},
|
||
}
|
||
al := New(cfg)
|
||
defer func() { _ = al.Close() }()
|
||
|
||
mockHandler := func(ctx *fasthttp.RequestCtx) {
|
||
ctx.SetStatusCode(fasthttp.StatusOK)
|
||
ctx.SetBodyString("Hello, World!")
|
||
}
|
||
|
||
handler := al.Process(mockHandler)
|
||
|
||
b.ResetTimer()
|
||
for b.Loop() {
|
||
ctx := &fasthttp.RequestCtx{}
|
||
ctx.Request.Header.SetMethod(fasthttp.MethodGet)
|
||
ctx.Request.SetRequestURI("/api/test")
|
||
ctx.Request.Header.SetHost("example.com")
|
||
handler(ctx)
|
||
}
|
||
}
|
||
|
||
// BenchmarkAccessLogProcessParallel 测试并发场景下的访问日志性能。
|
||
func BenchmarkAccessLogProcessParallel(b *testing.B) {
|
||
cfg := &config.LoggingConfig{
|
||
Access: config.AccessLogConfig{
|
||
Path: "/dev/null",
|
||
Format: "combined",
|
||
},
|
||
}
|
||
al := New(cfg)
|
||
defer func() { _ = al.Close() }()
|
||
|
||
mockHandler := func(ctx *fasthttp.RequestCtx) {
|
||
ctx.SetStatusCode(fasthttp.StatusOK)
|
||
ctx.SetBodyString("OK")
|
||
}
|
||
|
||
handler := al.Process(mockHandler)
|
||
|
||
b.ResetTimer()
|
||
b.RunParallel(func(pb *testing.PB) {
|
||
for pb.Next() {
|
||
ctx := &fasthttp.RequestCtx{}
|
||
ctx.Request.Header.SetMethod(fasthttp.MethodGet)
|
||
ctx.Request.SetRequestURI("/api/test")
|
||
handler(ctx)
|
||
}
|
||
})
|
||
}
|
||
|
||
// BenchmarkAccessLogProcessSampled 测试采样模式下的访问日志性能。
|
||
//
|
||
// 当 sample_rate=0.1 时,90% 的成功请求会跳过日志记录,
|
||
// 预期性能应显著优于全量记录。
|
||
func BenchmarkAccessLogProcessSampled(b *testing.B) {
|
||
cfg := &config.LoggingConfig{
|
||
Access: config.AccessLogConfig{
|
||
Path: "/dev/null",
|
||
Format: "combined",
|
||
SampleRate: 0.1,
|
||
},
|
||
}
|
||
al := New(cfg)
|
||
defer func() { _ = al.Close() }()
|
||
|
||
mockHandler := func(ctx *fasthttp.RequestCtx) {
|
||
ctx.SetStatusCode(fasthttp.StatusOK)
|
||
ctx.SetBodyString("OK")
|
||
}
|
||
|
||
handler := al.Process(mockHandler)
|
||
|
||
b.ResetTimer()
|
||
b.ReportAllocs()
|
||
b.RunParallel(func(pb *testing.PB) {
|
||
for pb.Next() {
|
||
ctx := &fasthttp.RequestCtx{}
|
||
ctx.Request.Header.SetMethod(fasthttp.MethodGet)
|
||
ctx.Request.SetRequestURI("/api/test")
|
||
handler(ctx)
|
||
}
|
||
})
|
||
}
|