/
val.go
200 lines (179 loc) · 4.52 KB
/
val.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
// 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() (v *IntVal) {
v = &IntVal{}
initIntDist(&v.dist)
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(name 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() (v *FloatVal) {
v = &FloatVal{}
initFloatDist(&v.dist)
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(name 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
}
// NewBoolVal creates a BoolVal
func NewBoolVal() *BoolVal {
return &BoolVal{}
}
// 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(name string, val float64)) {
trues := atomic.LoadInt64(&v.trues)
falses := atomic.LoadInt64(&v.falses)
recent := atomic.LoadInt32(&v.recent)
cb("disposition", float64(trues-falses))
cb("false", float64(falses))
cb("recent", float64(recent))
cb("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{}
}
// NewStructVal creates a StructVal
func NewStructVal() *StructVal {
return &StructVal{}
}
// 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(name string, val float64)) {
v.mtx.Lock()
recent := v.recent
v.mtx.Unlock()
if recent != nil {
StatSourceFromStruct(recent).Stats(cb)
}
}