Source file
src/expvar/expvar.go
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 atomic.Uint64
71 }
72
73 func (v *Float) Value() float64 {
74 return math.Float64frombits(v.f.Load())
75 }
76
77 func (v *Float) String() string {
78 return strconv.FormatFloat(
79 math.Float64frombits(v.f.Load()), 'g', -1, 64)
80 }
81
82
83 func (v *Float) Add(delta float64) {
84 for {
85 cur := v.f.Load()
86 curVal := math.Float64frombits(cur)
87 nxtVal := curVal + delta
88 nxt := math.Float64bits(nxtVal)
89 if v.f.CompareAndSwap(cur, nxt) {
90 return
91 }
92 }
93 }
94
95
96 func (v *Float) Set(value float64) {
97 v.f.Store(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: ", kv.Key)
122 if kv.Value != nil {
123 fmt.Fprintf(&b, "%v", kv.Value)
124 } else {
125 fmt.Fprint(&b, "null")
126 }
127 first = false
128 })
129 fmt.Fprintf(&b, "}")
130 return b.String()
131 }
132
133
134 func (v *Map) Init() *Map {
135 v.keysMu.Lock()
136 defer v.keysMu.Unlock()
137 v.keys = v.keys[:0]
138 v.m.Range(func(k, _ any) bool {
139 v.m.Delete(k)
140 return true
141 })
142 return v
143 }
144
145
146 func (v *Map) addKey(key string) {
147 v.keysMu.Lock()
148 defer v.keysMu.Unlock()
149
150 if i := sort.SearchStrings(v.keys, key); i >= len(v.keys) {
151 v.keys = append(v.keys, key)
152 } else if v.keys[i] != key {
153 v.keys = append(v.keys, "")
154 copy(v.keys[i+1:], v.keys[i:])
155 v.keys[i] = key
156 }
157 }
158
159 func (v *Map) Get(key string) Var {
160 i, _ := v.m.Load(key)
161 av, _ := i.(Var)
162 return av
163 }
164
165 func (v *Map) Set(key string, av Var) {
166
167
168
169 if _, ok := v.m.Load(key); !ok {
170 if _, dup := v.m.LoadOrStore(key, av); !dup {
171 v.addKey(key)
172 return
173 }
174 }
175
176 v.m.Store(key, av)
177 }
178
179
180 func (v *Map) Add(key string, delta int64) {
181 i, ok := v.m.Load(key)
182 if !ok {
183 var dup bool
184 i, dup = v.m.LoadOrStore(key, new(Int))
185 if !dup {
186 v.addKey(key)
187 }
188 }
189
190
191 if iv, ok := i.(*Int); ok {
192 iv.Add(delta)
193 }
194 }
195
196
197 func (v *Map) AddFloat(key string, delta float64) {
198 i, ok := v.m.Load(key)
199 if !ok {
200 var dup bool
201 i, dup = v.m.LoadOrStore(key, new(Float))
202 if !dup {
203 v.addKey(key)
204 }
205 }
206
207
208 if iv, ok := i.(*Float); ok {
209 iv.Add(delta)
210 }
211 }
212
213
214 func (v *Map) Delete(key string) {
215 v.keysMu.Lock()
216 defer v.keysMu.Unlock()
217 i := sort.SearchStrings(v.keys, key)
218 if i < len(v.keys) && key == v.keys[i] {
219 v.keys = append(v.keys[:i], v.keys[i+1:]...)
220 v.m.Delete(key)
221 }
222 }
223
224
225
226
227 func (v *Map) Do(f func(KeyValue)) {
228 v.keysMu.RLock()
229 defer v.keysMu.RUnlock()
230 for _, k := range v.keys {
231 i, _ := v.m.Load(k)
232 val, _ := i.(Var)
233 f(KeyValue{k, val})
234 }
235 }
236
237
238 type String struct {
239 s atomic.Value
240 }
241
242 func (v *String) Value() string {
243 p, _ := v.s.Load().(string)
244 return p
245 }
246
247
248
249 func (v *String) String() string {
250 s := v.Value()
251 b, _ := json.Marshal(s)
252 return string(b)
253 }
254
255 func (v *String) Set(value string) {
256 v.s.Store(value)
257 }
258
259
260
261 type Func func() any
262
263 func (f Func) Value() any {
264 return f()
265 }
266
267 func (f Func) String() string {
268 v, _ := json.Marshal(f())
269 return string(v)
270 }
271
272
273 var (
274 vars sync.Map
275 varKeysMu sync.RWMutex
276 varKeys []string
277 )
278
279
280
281
282 func Publish(name string, v Var) {
283 if _, dup := vars.LoadOrStore(name, v); dup {
284 log.Panicln("Reuse of exported var name:", name)
285 }
286 varKeysMu.Lock()
287 defer varKeysMu.Unlock()
288 varKeys = append(varKeys, name)
289 sort.Strings(varKeys)
290 }
291
292
293
294 func Get(name string) Var {
295 i, _ := vars.Load(name)
296 v, _ := i.(Var)
297 return v
298 }
299
300
301
302 func NewInt(name string) *Int {
303 v := new(Int)
304 Publish(name, v)
305 return v
306 }
307
308 func NewFloat(name string) *Float {
309 v := new(Float)
310 Publish(name, v)
311 return v
312 }
313
314 func NewMap(name string) *Map {
315 v := new(Map).Init()
316 Publish(name, v)
317 return v
318 }
319
320 func NewString(name string) *String {
321 v := new(String)
322 Publish(name, v)
323 return v
324 }
325
326
327
328
329 func Do(f func(KeyValue)) {
330 varKeysMu.RLock()
331 defer varKeysMu.RUnlock()
332 for _, k := range varKeys {
333 val, _ := vars.Load(k)
334 f(KeyValue{k, val.(Var)})
335 }
336 }
337
338 func expvarHandler(w http.ResponseWriter, r *http.Request) {
339 w.Header().Set("Content-Type", "application/json; charset=utf-8")
340 fmt.Fprintf(w, "{\n")
341 first := true
342 Do(func(kv KeyValue) {
343 if !first {
344 fmt.Fprintf(w, ",\n")
345 }
346 first = false
347 fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
348 })
349 fmt.Fprintf(w, "\n}\n")
350 }
351
352
353
354
355 func Handler() http.Handler {
356 return http.HandlerFunc(expvarHandler)
357 }
358
359 func cmdline() any {
360 return os.Args
361 }
362
363 func memstats() any {
364 stats := new(runtime.MemStats)
365 runtime.ReadMemStats(stats)
366 return *stats
367 }
368
369 func init() {
370 http.HandleFunc("/debug/vars", expvarHandler)
371 Publish("cmdline", Func(cmdline))
372 Publish("memstats", Func(memstats))
373 }
374
View as plain text