Source file
src/expvar/expvar.go
Documentation: expvar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package expvar
23
24 import (
25 "encoding/json"
26 "fmt"
27 "log"
28 "math"
29 "net/http"
30 "os"
31 "runtime"
32 "sort"
33 "strconv"
34 "strings"
35 "sync"
36 "sync/atomic"
37 )
38
39
40 type Var interface {
41
42
43
44 String() string
45 }
46
47
48 type Int struct {
49 i int64
50 }
51
52 func (v *Int) Value() int64 {
53 return atomic.LoadInt64(&v.i)
54 }
55
56 func (v *Int) String() string {
57 return strconv.FormatInt(atomic.LoadInt64(&v.i), 10)
58 }
59
60 func (v *Int) Add(delta int64) {
61 atomic.AddInt64(&v.i, delta)
62 }
63
64 func (v *Int) Set(value int64) {
65 atomic.StoreInt64(&v.i, value)
66 }
67
68
69 type Float struct {
70 f uint64
71 }
72
73 func (v *Float) Value() float64 {
74 return math.Float64frombits(atomic.LoadUint64(&v.f))
75 }
76
77 func (v *Float) String() string {
78 return strconv.FormatFloat(
79 math.Float64frombits(atomic.LoadUint64(&v.f)), 'g', -1, 64)
80 }
81
82
83 func (v *Float) Add(delta float64) {
84 for {
85 cur := atomic.LoadUint64(&v.f)
86 curVal := math.Float64frombits(cur)
87 nxtVal := curVal + delta
88 nxt := math.Float64bits(nxtVal)
89 if atomic.CompareAndSwapUint64(&v.f, cur, nxt) {
90 return
91 }
92 }
93 }
94
95
96 func (v *Float) Set(value float64) {
97 atomic.StoreUint64(&v.f, math.Float64bits(value))
98 }
99
100
101 type Map struct {
102 m sync.Map
103 keysMu sync.RWMutex
104 keys []string
105 }
106
107
108 type KeyValue struct {
109 Key string
110 Value Var
111 }
112
113 func (v *Map) String() string {
114 var b strings.Builder
115 fmt.Fprintf(&b, "{")
116 first := true
117 v.Do(func(kv KeyValue) {
118 if !first {
119 fmt.Fprintf(&b, ", ")
120 }
121 fmt.Fprintf(&b, "%q: %v", kv.Key, kv.Value)
122 first = false
123 })
124 fmt.Fprintf(&b, "}")
125 return b.String()
126 }
127
128
129 func (v *Map) Init() *Map {
130 v.keysMu.Lock()
131 defer v.keysMu.Unlock()
132 v.keys = v.keys[:0]
133 v.m.Range(func(k, _ interface{}) bool {
134 v.m.Delete(k)
135 return true
136 })
137 return v
138 }
139
140
141 func (v *Map) addKey(key string) {
142 v.keysMu.Lock()
143 defer v.keysMu.Unlock()
144
145 if i := sort.SearchStrings(v.keys, key); i >= len(v.keys) {
146 v.keys = append(v.keys, key)
147 } else if v.keys[i] != key {
148 v.keys = append(v.keys, "")
149 copy(v.keys[i+1:], v.keys[i:])
150 v.keys[i] = key
151 }
152 }
153
154 func (v *Map) Get(key string) Var {
155 i, _ := v.m.Load(key)
156 av, _ := i.(Var)
157 return av
158 }
159
160 func (v *Map) Set(key string, av Var) {
161
162
163
164 if _, ok := v.m.Load(key); !ok {
165 if _, dup := v.m.LoadOrStore(key, av); !dup {
166 v.addKey(key)
167 return
168 }
169 }
170
171 v.m.Store(key, av)
172 }
173
174
175 func (v *Map) Add(key string, delta int64) {
176 i, ok := v.m.Load(key)
177 if !ok {
178 var dup bool
179 i, dup = v.m.LoadOrStore(key, new(Int))
180 if !dup {
181 v.addKey(key)
182 }
183 }
184
185
186 if iv, ok := i.(*Int); ok {
187 iv.Add(delta)
188 }
189 }
190
191
192 func (v *Map) AddFloat(key string, delta float64) {
193 i, ok := v.m.Load(key)
194 if !ok {
195 var dup bool
196 i, dup = v.m.LoadOrStore(key, new(Float))
197 if !dup {
198 v.addKey(key)
199 }
200 }
201
202
203 if iv, ok := i.(*Float); ok {
204 iv.Add(delta)
205 }
206 }
207
208
209 func (v *Map) Delete(key string) {
210 v.keysMu.Lock()
211 defer v.keysMu.Unlock()
212 i := sort.SearchStrings(v.keys, key)
213 if i < len(v.keys) && key == v.keys[i] {
214 v.keys = append(v.keys[:i], v.keys[i+1:]...)
215 v.m.Delete(key)
216 }
217 }
218
219
220
221
222 func (v *Map) Do(f func(KeyValue)) {
223 v.keysMu.RLock()
224 defer v.keysMu.RUnlock()
225 for _, k := range v.keys {
226 i, _ := v.m.Load(k)
227 f(KeyValue{k, i.(Var)})
228 }
229 }
230
231
232 type String struct {
233 s atomic.Value
234 }
235
236 func (v *String) Value() string {
237 p, _ := v.s.Load().(string)
238 return p
239 }
240
241
242
243 func (v *String) String() string {
244 s := v.Value()
245 b, _ := json.Marshal(s)
246 return string(b)
247 }
248
249 func (v *String) Set(value string) {
250 v.s.Store(value)
251 }
252
253
254
255 type Func func() interface{}
256
257 func (f Func) Value() interface{} {
258 return f()
259 }
260
261 func (f Func) String() string {
262 v, _ := json.Marshal(f())
263 return string(v)
264 }
265
266
267 var (
268 vars sync.Map
269 varKeysMu sync.RWMutex
270 varKeys []string
271 )
272
273
274
275
276 func Publish(name string, v Var) {
277 if _, dup := vars.LoadOrStore(name, v); dup {
278 log.Panicln("Reuse of exported var name:", name)
279 }
280 varKeysMu.Lock()
281 defer varKeysMu.Unlock()
282 varKeys = append(varKeys, name)
283 sort.Strings(varKeys)
284 }
285
286
287
288 func Get(name string) Var {
289 i, _ := vars.Load(name)
290 v, _ := i.(Var)
291 return v
292 }
293
294
295
296 func NewInt(name string) *Int {
297 v := new(Int)
298 Publish(name, v)
299 return v
300 }
301
302 func NewFloat(name string) *Float {
303 v := new(Float)
304 Publish(name, v)
305 return v
306 }
307
308 func NewMap(name string) *Map {
309 v := new(Map).Init()
310 Publish(name, v)
311 return v
312 }
313
314 func NewString(name string) *String {
315 v := new(String)
316 Publish(name, v)
317 return v
318 }
319
320
321
322
323 func Do(f func(KeyValue)) {
324 varKeysMu.RLock()
325 defer varKeysMu.RUnlock()
326 for _, k := range varKeys {
327 val, _ := vars.Load(k)
328 f(KeyValue{k, val.(Var)})
329 }
330 }
331
332 func expvarHandler(w http.ResponseWriter, r *http.Request) {
333 w.Header().Set("Content-Type", "application/json; charset=utf-8")
334 fmt.Fprintf(w, "{\n")
335 first := true
336 Do(func(kv KeyValue) {
337 if !first {
338 fmt.Fprintf(w, ",\n")
339 }
340 first = false
341 fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
342 })
343 fmt.Fprintf(w, "\n}\n")
344 }
345
346
347
348
349 func Handler() http.Handler {
350 return http.HandlerFunc(expvarHandler)
351 }
352
353 func cmdline() interface{} {
354 return os.Args
355 }
356
357 func memstats() interface{} {
358 stats := new(runtime.MemStats)
359 runtime.ReadMemStats(stats)
360 return *stats
361 }
362
363 func init() {
364 http.HandleFunc("/debug/vars", expvarHandler)
365 Publish("cmdline", Func(cmdline))
366 Publish("memstats", Func(memstats))
367 }
368
View as plain text