Source File
sampler.go
Belonging Package
go.uber.org/zap/zapcore
// Copyright (c) 2016-2022 Uber Technologies, Inc.//// Permission is hereby granted, free of charge, to any person obtaining a copy// of this software and associated documentation files (the "Software"), to deal// in the Software without restriction, including without limitation the rights// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell// copies of the Software, and to permit persons to whom the Software is// furnished to do so, subject to the following conditions://// The above copyright notice and this permission notice shall be included in// all copies or substantial portions of the Software.//// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN// THE SOFTWARE.package zapcoreimport ()const (_numLevels = _maxLevel - _minLevel + 1_countersPerLevel = 4096)type counter struct {resetAt atomic.Int64counter atomic.Uint64}type counters [_numLevels][_countersPerLevel]counterfunc () *counters {return &counters{}}func ( *counters) ( Level, string) *counter {:= - _minLevel:= fnv32a() % _countersPerLevelreturn &[][]}// fnv32a, adapted from "hash/fnv", but without a []byte(string) allocfunc ( string) uint32 {const (= 2166136261= 16777619):= uint32()for := 0; < len(); ++ {^= uint32([])*=}return}func ( *counter) ( time.Time, time.Duration) uint64 {:= .UnixNano():= .resetAt.Load()if > {return .counter.Add(1)}.counter.Store(1):= + .Nanoseconds()if !.resetAt.CompareAndSwap(, ) {// We raced with another goroutine trying to reset, and it also reset// the counter to 1, so we need to reincrement the counter.return .counter.Add(1)}return 1}// SamplingDecision is a decision represented as a bit field made by sampler.// More decisions may be added in the future.type SamplingDecision uint32const (// LogDropped indicates that the Sampler dropped a log entry.LogDropped SamplingDecision = 1 << iota// LogSampled indicates that the Sampler sampled a log entry.LogSampled)// optionFunc wraps a func so it satisfies the SamplerOption interface.type optionFunc func(*sampler)func ( optionFunc) ( *sampler) {()}// SamplerOption configures a Sampler.type SamplerOption interface {apply(*sampler)}// nopSamplingHook is the default hook used by sampler.func (Entry, SamplingDecision) {}// SamplerHook registers a function which will be called when Sampler makes a// decision.//// This hook may be used to get visibility into the performance of the sampler.// For example, use it to track metrics of dropped versus sampled logs.//// var dropped atomic.Int64// zapcore.SamplerHook(func(ent zapcore.Entry, dec zapcore.SamplingDecision) {// if dec&zapcore.LogDropped > 0 {// dropped.Inc()// }// })func ( func( Entry, SamplingDecision)) SamplerOption {return optionFunc(func( *sampler) {.hook =})}// NewSamplerWithOptions creates a Core that samples incoming entries, which// caps the CPU and I/O load of logging while attempting to preserve a// representative subset of your logs.//// Zap samples by logging the first N entries with a given level and message// 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// absolute precision; under load, each tick may be slightly over- or// under-sampled.func ( Core, time.Duration, , int, ...SamplerOption) Core {:= &sampler{Core: ,tick: ,counts: newCounters(),first: uint64(),thereafter: uint64(),hook: nopSamplingHook,}for , := range {.apply()}return}type sampler struct {Corecounts *counterstick time.Durationfirst, thereafter uint64hook func(Entry, SamplingDecision)}var (_ Core = (*sampler)(nil)_ leveledEnabler = (*sampler)(nil))// NewSampler creates a Core that samples incoming entries, which// caps the CPU and I/O load of logging while attempting to preserve a// representative subset of your logs.//// Zap samples by logging the first N entries with a given level and message// 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.//// 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.//// Deprecated: use NewSamplerWithOptions.func ( Core, time.Duration, , int) Core {return NewSamplerWithOptions(, , , )}func ( *sampler) () Level {return LevelOf(.Core)}func ( *sampler) ( []Field) Core {return &sampler{Core: .Core.With(),tick: .tick,counts: .counts,first: .first,thereafter: .thereafter,hook: .hook,}}func ( *sampler) ( Entry, *CheckedEntry) *CheckedEntry {if !.Enabled(.Level) {return}if .Level >= _minLevel && .Level <= _maxLevel {:= .counts.get(.Level, .Message):= .IncCheckReset(.Time, .tick)if > .first && (.thereafter == 0 || (-.first)%.thereafter != 0) {.hook(, LogDropped)return}.hook(, LogSampled)}return .Core.Check(, )}
![]() |
The pages are generated with Golds v0.6.7. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |