205 lines
4.7 KiB
Go
205 lines
4.7 KiB
Go
|
// Copyright (C) 2015 Space Monkey, Inc.
|
||
|
//
|
||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
// you may not use this file except in compliance with the License.
|
||
|
// You may obtain a copy of the License at
|
||
|
//
|
||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||
|
//
|
||
|
// Unless required by applicable law or agreed to in writing, software
|
||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
// See the License for the specific language governing permissions and
|
||
|
// limitations under the License.
|
||
|
|
||
|
package monkit
|
||
|
|
||
|
import (
|
||
|
"sync"
|
||
|
"sync/atomic"
|
||
|
)
|
||
|
|
||
|
// IntVal is a convenience wrapper around an IntDist. Constructed using
|
||
|
// NewIntVal, though its expected usage is like:
|
||
|
//
|
||
|
// var mon = monkit.Package()
|
||
|
//
|
||
|
// func MyFunc() {
|
||
|
// ...
|
||
|
// mon.IntVal("size").Observe(val)
|
||
|
// ...
|
||
|
// }
|
||
|
//
|
||
|
type IntVal struct {
|
||
|
mtx sync.Mutex
|
||
|
dist IntDist
|
||
|
}
|
||
|
|
||
|
// NewIntVal creates an IntVal
|
||
|
func NewIntVal(key SeriesKey) (v *IntVal) {
|
||
|
v = &IntVal{}
|
||
|
initIntDist(&v.dist, key)
|
||
|
return v
|
||
|
}
|
||
|
|
||
|
// Observe observes an integer value
|
||
|
func (v *IntVal) Observe(val int64) {
|
||
|
v.mtx.Lock()
|
||
|
v.dist.Insert(val)
|
||
|
v.mtx.Unlock()
|
||
|
}
|
||
|
|
||
|
// Stats implements the StatSource interface.
|
||
|
func (v *IntVal) Stats(cb func(key SeriesKey, field string, val float64)) {
|
||
|
v.mtx.Lock()
|
||
|
vd := v.dist.Copy()
|
||
|
v.mtx.Unlock()
|
||
|
|
||
|
vd.Stats(cb)
|
||
|
}
|
||
|
|
||
|
// Quantile returns an estimate of the requested quantile of observed values.
|
||
|
// 0 <= quantile <= 1
|
||
|
func (v *IntVal) Quantile(quantile float64) (rv int64) {
|
||
|
v.mtx.Lock()
|
||
|
rv = v.dist.Query(quantile)
|
||
|
v.mtx.Unlock()
|
||
|
return rv
|
||
|
}
|
||
|
|
||
|
// FloatVal is a convenience wrapper around an FloatDist. Constructed using
|
||
|
// NewFloatVal, though its expected usage is like:
|
||
|
//
|
||
|
// var mon = monkit.Package()
|
||
|
//
|
||
|
// func MyFunc() {
|
||
|
// ...
|
||
|
// mon.FloatVal("size").Observe(val)
|
||
|
// ...
|
||
|
// }
|
||
|
//
|
||
|
type FloatVal struct {
|
||
|
mtx sync.Mutex
|
||
|
dist FloatDist
|
||
|
}
|
||
|
|
||
|
// NewFloatVal creates a FloatVal
|
||
|
func NewFloatVal(key SeriesKey) (v *FloatVal) {
|
||
|
v = &FloatVal{}
|
||
|
initFloatDist(&v.dist, key)
|
||
|
return v
|
||
|
}
|
||
|
|
||
|
// Observe observes an floating point value
|
||
|
func (v *FloatVal) Observe(val float64) {
|
||
|
v.mtx.Lock()
|
||
|
v.dist.Insert(val)
|
||
|
v.mtx.Unlock()
|
||
|
}
|
||
|
|
||
|
// Stats implements the StatSource interface.
|
||
|
func (v *FloatVal) Stats(cb func(key SeriesKey, field string, val float64)) {
|
||
|
v.mtx.Lock()
|
||
|
vd := v.dist.Copy()
|
||
|
v.mtx.Unlock()
|
||
|
|
||
|
vd.Stats(cb)
|
||
|
}
|
||
|
|
||
|
// Quantile returns an estimate of the requested quantile of observed values.
|
||
|
// 0 <= quantile <= 1
|
||
|
func (v *FloatVal) Quantile(quantile float64) (rv float64) {
|
||
|
v.mtx.Lock()
|
||
|
rv = v.dist.Query(quantile)
|
||
|
v.mtx.Unlock()
|
||
|
return rv
|
||
|
}
|
||
|
|
||
|
// BoolVal keeps statistics about boolean values. It keeps the number of trues,
|
||
|
// number of falses, and the disposition (number of trues minus number of
|
||
|
// falses). Constructed using NewBoolVal, though its expected usage is like:
|
||
|
//
|
||
|
// var mon = monkit.Package()
|
||
|
//
|
||
|
// func MyFunc() {
|
||
|
// ...
|
||
|
// mon.BoolVal("flipped").Observe(bool)
|
||
|
// ...
|
||
|
// }
|
||
|
//
|
||
|
type BoolVal struct {
|
||
|
trues int64
|
||
|
falses int64
|
||
|
recent int32
|
||
|
key SeriesKey
|
||
|
}
|
||
|
|
||
|
// NewBoolVal creates a BoolVal
|
||
|
func NewBoolVal(key SeriesKey) *BoolVal {
|
||
|
return &BoolVal{key: key}
|
||
|
}
|
||
|
|
||
|
// Observe observes a boolean value
|
||
|
func (v *BoolVal) Observe(val bool) {
|
||
|
if val {
|
||
|
atomic.AddInt64(&v.trues, 1)
|
||
|
atomic.StoreInt32(&v.recent, 1)
|
||
|
} else {
|
||
|
atomic.AddInt64(&v.falses, 1)
|
||
|
atomic.StoreInt32(&v.recent, 0)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Stats implements the StatSource interface.
|
||
|
func (v *BoolVal) Stats(cb func(key SeriesKey, field string, val float64)) {
|
||
|
trues := atomic.LoadInt64(&v.trues)
|
||
|
falses := atomic.LoadInt64(&v.falses)
|
||
|
recent := atomic.LoadInt32(&v.recent)
|
||
|
cb(v.key, "disposition", float64(trues-falses))
|
||
|
cb(v.key, "false", float64(falses))
|
||
|
cb(v.key, "recent", float64(recent))
|
||
|
cb(v.key, "true", float64(trues))
|
||
|
}
|
||
|
|
||
|
// StructVal keeps track of a structure of data. Constructed using
|
||
|
// NewStructVal, though its expected usage is like:
|
||
|
//
|
||
|
// var mon = monkit.Package()
|
||
|
//
|
||
|
// func MyFunc() {
|
||
|
// ...
|
||
|
// mon.StructVal("stats").Observe(stats)
|
||
|
// ...
|
||
|
// }
|
||
|
//
|
||
|
type StructVal struct {
|
||
|
mtx sync.Mutex
|
||
|
recent interface{}
|
||
|
key SeriesKey
|
||
|
}
|
||
|
|
||
|
// NewStructVal creates a StructVal
|
||
|
func NewStructVal(key SeriesKey) *StructVal {
|
||
|
return &StructVal{key: key}
|
||
|
}
|
||
|
|
||
|
// Observe observes a struct value. Only the fields convertable to float64 will
|
||
|
// be monitored. A reference to the most recently called Observe value is kept
|
||
|
// for reading when Stats is called.
|
||
|
func (v *StructVal) Observe(val interface{}) {
|
||
|
v.mtx.Lock()
|
||
|
v.recent = val
|
||
|
v.mtx.Unlock()
|
||
|
}
|
||
|
|
||
|
// Stats implements the StatSource interface.
|
||
|
func (v *StructVal) Stats(cb func(key SeriesKey, field string, val float64)) {
|
||
|
v.mtx.Lock()
|
||
|
recent := v.recent
|
||
|
v.mtx.Unlock()
|
||
|
|
||
|
if recent != nil {
|
||
|
StatSourceFromStruct(v.key, recent).Stats(cb)
|
||
|
}
|
||
|
}
|