phuslu / log

Fastest structured logging
MIT License
672 stars 44 forks source link

有内置日志采样功能的计划吗? #46

Closed fufuok closed 3 years ago

fufuok commented 3 years ago
// Will let 5 debug messages per period of 1 second.
// Over 5 debug message, 1 every 100 debug messages are logged.
// Other levels are not sampled.
sampled := log.Sample(zerolog.LevelSampler{
    DebugSampler: &zerolog.BurstSampler{
        Burst: 5,
        Period: 1*time.Second,
        NextSampler: &zerolog.BasicSampler{N: 100},
    },
})
sampled.Debug().Msg("hello world")

// Output: {"time":1494567715,"level":"debug","message":"hello world"}

您好吖.

很喜欢干净整洁的库, 高性能无依赖是天花板. 功能也很全面.

不过, 看了一圈没发现上面的日志采样功能, 在一些高并发场景我们可能更希望1秒有几个日志即可. 或意外产生错误时很可能疯狂记录错误日志, 此时也希望仅采样错误来记录.

如果已有此功能或简单方案, 请贴下范例.

若无, 请问有计划吗?

我感觉这样就完全可以替代我心中理想的日志库了.

谢谢~~

fufuok commented 3 years ago

示例, 1 秒可能有几万个错误. 但记录了 5 个.

21:41:55 WRN client.go:36 > Failed to write Tunnel E="timeout: rpc Client's send queue is full"
21:41:56 WRN client.go:36 > Failed to write Tunnel E="timeout: rpc Client's send queue is full"
21:41:56 WRN client.go:36 > Failed to write Tunnel E="timeout: rpc Client's send queue is full"
21:41:56 WRN client.go:36 > Failed to write Tunnel E="timeout: rpc Client's send queue is full"
21:41:56 WRN client.go:36 > Failed to write Tunnel E="timeout: rpc Client's send queue is full"
21:41:56 WRN client.go:36 > Failed to write Tunnel E="timeout: rpc Client's send queue is full"
21:41:57 WRN client.go:36 > Failed to write Tunnel E="timeout: rpc Client's send queue is full"
phuslu commented 3 years ago

采样功能的确不是特别好做,每秒输出 N 个这个的确没有实现。在高并发时候,我一般是使用概率输出,就是输出 N% 的日志。所以我在这个库里面还暴露了 Fastrand 函数。

// 输出 5% 的日志
if log.Fastrand(100) < 5 {
   log.Info().Msg("a sample log")
}

事实上对于高并发的日志,我会用一个专门的 Logger + FileWriter 去存它. 一个真实的例子如下

trafficLogger := log.Logger{Writer: &log.FileWriter{...}} // 大约如此

if log.Fastrand(100) < 5 {
   trafficLogger .Log().Msg("a sample log")
}

对于支持每秒 N 个的这个需求,其实是每次都要调用一个 timer ,我觉得很难实现的高效,所以就没做。

phuslu commented 3 years ago

这个需求其实之前也有建议,我都准备好了参考对象了,在这里 https://github.com/vitessio/vitess/blob/v2.1.1/go/ratelimiter/ratelimiter.go

但是一直没有下决心去做(因为可能最终是实现出来的结果不够简洁),我再琢磨琢磨。

phuslu commented 3 years ago

youtube 这个版本的 ratelimit 是我所知的最高效的 ratelimiter 实现(因为它本质就是一个计数器)。但是还是对性能造成比较明显的影响,因为设计 time.Now() 和 mutex.Lock(),相比较 Fastrand 的方案,后者性能要好很多。

fufuok commented 3 years ago

好的好的. 了解了. 谢谢. 新项目转到这个日志库. 我觉得挺棒~~