diff --git a/zapcore/sampler.go b/zapcore/sampler.go index 31ed96e12..8c116049d 100644 --- a/zapcore/sampler.go +++ b/zapcore/sampler.go @@ -133,10 +133,21 @@ func SamplerHook(hook func(entry Entry, dec SamplingDecision)) SamplerOption { // each tick. If more Entries with the same level and message are seen during // the same interval, every Mth message is logged and the rest are dropped. // +// For example, +// +// core = NewSamplerWithOptions(core, time.Second, 10, 5) +// +// This will log the first 10 log entries with the same level and message +// in a one second interval as-is. Following that, it will allow through +// every 5th log entry with the same level and message in that interval. +// +// If thereafter is zero, the Core will drop all log entries after the first N +// in that interval. +// // Sampler can be configured to report sampling decisions with the SamplerHook // option. // -// Keep in mind that zap's sampling implementation is optimized for speed over +// Keep in mind that Zap's sampling implementation is optimized for speed over // absolute precision; under load, each tick may be slightly over- or // under-sampled. func NewSamplerWithOptions(core Core, tick time.Duration, first, thereafter int, opts ...SamplerOption) Core { @@ -200,7 +211,7 @@ func (s *sampler) Check(ent Entry, ce *CheckedEntry) *CheckedEntry { if ent.Level >= _minLevel && ent.Level <= _maxLevel { counter := s.counts.get(ent.Level, ent.Message) n := counter.IncCheckReset(ent.Time, s.tick) - if n > s.first && (n-s.first)%s.thereafter != 0 { + if n > s.first && (s.thereafter == 0 || (n-s.first)%s.thereafter != 0) { s.hook(ent, LogDropped) return ce } diff --git a/zapcore/sampler_test.go b/zapcore/sampler_test.go index fbcdd46cc..f19a6fc9e 100644 --- a/zapcore/sampler_test.go +++ b/zapcore/sampler_test.go @@ -275,3 +275,42 @@ func TestSamplerUnknownLevels(t *testing.T) { }) } } + +func TestSamplerWithZeroThereafter(t *testing.T) { + var counter countingCore + + // Logs two messages per second. + sampler := NewSamplerWithOptions(&counter, time.Second, 2, 0) + + now := time.Now() + + for i := 0; i < 1000; i++ { + ent := Entry{ + Level: InfoLevel, + Message: "msg", + Time: now, + } + if ce := sampler.Check(ent, nil); ce != nil { + ce.Write() + } + } + + assert.Equal(t, 2, int(counter.logs.Load()), + "Unexpected number of logs") + + now = now.Add(time.Second) + + for i := 0; i < 1000; i++ { + ent := Entry{ + Level: InfoLevel, + Message: "msg", + Time: now, + } + if ce := sampler.Check(ent, nil); ce != nil { + ce.Write() + } + } + + assert.Equal(t, 4, int(counter.logs.Load()), + "Unexpected number of logs") +}