1
0
Fork 0

Resync oxy with original repository

This commit is contained in:
SALLEYRON Julien 2017-11-22 18:20:03 +01:00 committed by Traefiker
parent da5e4a13bf
commit bee8ebb00b
31 changed files with 650 additions and 808 deletions

View file

@ -40,7 +40,7 @@ func SplitRatios(values []float64) (good map[float64]bool, bad map[float64]bool)
}
// SplitFloat64 provides simple anomaly detection for skewed data sets with no particular distribution.
// In essense it applies the formula if(v > median(values) + threshold * medianAbsoluteDeviation) -> anomaly
// In essence it applies the formula if(v > median(values) + threshold * medianAbsoluteDeviation) -> anomaly
// There's a corner case where there are just 2 values, so by definition there's no value that exceeds the threshold.
// This case is solved by introducing additional value that we know is good, e.g. 0. That helps to improve the detection results
// on such data sets.

View file

@ -71,9 +71,7 @@ func (c *RollingCounter) Clone() *RollingCounter {
lastBucket: c.lastBucket,
lastUpdated: c.lastUpdated,
}
for i, v := range c.values {
other.values[i] = v
}
copy(other.values, c.values)
return other
}

View file

@ -34,6 +34,15 @@ func NewHDRHistogram(low, high int64, sigfigs int) (h *HDRHistogram, err error)
}, nil
}
func (r *HDRHistogram) Export() *HDRHistogram {
var hist *hdrhistogram.Histogram = nil
if r.h != nil {
snapshot := r.h.Export()
hist = hdrhistogram.Import(snapshot)
}
return &HDRHistogram{low: r.low, high: r.high, sigfigs: r.sigfigs, h: hist}
}
// Returns latency at quantile with microsecond precision
func (h *HDRHistogram) LatencyAtQuantile(q float64) time.Duration {
return time.Duration(h.ValueAtQuantile(q)) * time.Microsecond
@ -118,6 +127,26 @@ func NewRollingHDRHistogram(low, high int64, sigfigs int, period time.Duration,
return rh, nil
}
func (r *RollingHDRHistogram) Export() *RollingHDRHistogram {
export := &RollingHDRHistogram{}
export.idx = r.idx
export.lastRoll = r.lastRoll
export.period = r.period
export.bucketCount = r.bucketCount
export.low = r.low
export.high = r.high
export.sigfigs = r.sigfigs
export.clock = r.clock
exportBuckets := make([]*HDRHistogram, len(r.buckets))
for i, hist := range r.buckets {
exportBuckets[i] = hist.Export()
}
export.buckets = exportBuckets
return export
}
func (r *RollingHDRHistogram) Append(o *RollingHDRHistogram) error {
if r.bucketCount != o.bucketCount || r.period != o.period || r.low != o.low || r.high != o.high || r.sigfigs != o.sigfigs {
return fmt.Errorf("can't merge")
@ -150,8 +179,8 @@ func (r *RollingHDRHistogram) Merged() (*HDRHistogram, error) {
return m, err
}
for _, h := range r.buckets {
if m.Merge(h); err != nil {
return nil, err
if errMerge := m.Merge(h); errMerge != nil {
return nil, errMerge
}
}
return m, nil

View file

@ -20,6 +20,7 @@ type RTMetrics struct {
statusCodes map[int]*RollingCounter
statusCodesLock sync.RWMutex
histogram *RollingHDRHistogram
histogramLock sync.RWMutex
newCounter NewCounterFn
newHist NewRollingHistogramFn
@ -102,12 +103,39 @@ func NewRTMetrics(settings ...rrOptSetter) (*RTMetrics, error) {
return m, nil
}
// Returns a new RTMetrics which is a copy of the current one
func (m *RTMetrics) Export() *RTMetrics {
m.statusCodesLock.RLock()
defer m.statusCodesLock.RUnlock()
m.histogramLock.RLock()
defer m.histogramLock.RUnlock()
export := &RTMetrics{}
export.statusCodesLock = sync.RWMutex{}
export.histogramLock = sync.RWMutex{}
export.total = m.total.Clone()
export.netErrors = m.netErrors.Clone()
exportStatusCodes := map[int]*RollingCounter{}
for code, rollingCounter := range m.statusCodes {
exportStatusCodes[code] = rollingCounter.Clone()
}
export.statusCodes = exportStatusCodes
if m.histogram != nil {
export.histogram = m.histogram.Export()
}
export.newCounter = m.newCounter
export.newHist = m.newHist
export.clock = m.clock
return export
}
func (m *RTMetrics) CounterWindowSize() time.Duration {
return m.total.WindowSize()
}
// GetNetworkErrorRatio calculates the amont of network errors such as time outs and dropped connection
// that occured in the given time window compared to the total requests count.
// that occurred in the given time window compared to the total requests count.
func (m *RTMetrics) NetworkErrorRatio() float64 {
if m.total.Count() == 0 {
return 0
@ -148,11 +176,13 @@ func (m *RTMetrics) Append(other *RTMetrics) error {
return err
}
copied := other.Export()
m.statusCodesLock.Lock()
defer m.statusCodesLock.Unlock()
other.statusCodesLock.RLock()
defer other.statusCodesLock.RUnlock()
for code, c := range other.statusCodes {
m.histogramLock.Lock()
defer m.histogramLock.Unlock()
for code, c := range copied.statusCodes {
o, ok := m.statusCodes[code]
if ok {
if err := o.Append(c); err != nil {
@ -163,7 +193,7 @@ func (m *RTMetrics) Append(other *RTMetrics) error {
}
}
return m.histogram.Append(other.histogram)
return m.histogram.Append(copied.histogram)
}
func (m *RTMetrics) Record(code int, duration time.Duration) {
@ -200,35 +230,36 @@ func (m *RTMetrics) StatusCodesCounts() map[int]int64 {
// GetLatencyHistogram computes and returns resulting histogram with latencies observed.
func (m *RTMetrics) LatencyHistogram() (*HDRHistogram, error) {
m.histogramLock.Lock()
defer m.histogramLock.Unlock()
return m.histogram.Merged()
}
func (m *RTMetrics) Reset() {
m.statusCodesLock.Lock()
defer m.statusCodesLock.Unlock()
m.histogramLock.Lock()
defer m.histogramLock.Unlock()
m.histogram.Reset()
m.total.Reset()
m.netErrors.Reset()
m.statusCodesLock.Lock()
defer m.statusCodesLock.Unlock()
m.statusCodes = make(map[int]*RollingCounter)
}
func (m *RTMetrics) recordNetError() error {
m.netErrors.Inc(1)
return nil
}
func (m *RTMetrics) recordLatency(d time.Duration) error {
m.histogramLock.Lock()
defer m.histogramLock.Unlock()
return m.histogram.RecordLatencies(d, 1)
}
func (m *RTMetrics) recordStatusCode(statusCode int) error {
m.statusCodesLock.RLock()
m.statusCodesLock.Lock()
if c, ok := m.statusCodes[statusCode]; ok {
c.Inc(1)
m.statusCodesLock.RUnlock()
m.statusCodesLock.Unlock()
return nil
}
m.statusCodesLock.RUnlock()
m.statusCodesLock.Unlock()
m.statusCodesLock.Lock()
defer m.statusCodesLock.Unlock()