Source file src/pkg/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 "bytes"
26 "encoding/json"
27 "fmt"
28 "log"
29 "net/http"
30 "os"
31 "runtime"
32 "strconv"
33 "sync"
34 )
35
36
37 type Var interface {
38 String() string
39 }
40
41
42 type Int struct {
43 i int64
44 mu sync.RWMutex
45 }
46
47 func (v *Int) String() string {
48 v.mu.RLock()
49 defer v.mu.RUnlock()
50 return strconv.FormatInt(v.i, 10)
51 }
52
53 func (v *Int) Add(delta int64) {
54 v.mu.Lock()
55 defer v.mu.Unlock()
56 v.i += delta
57 }
58
59 func (v *Int) Set(value int64) {
60 v.mu.Lock()
61 defer v.mu.Unlock()
62 v.i = value
63 }
64
65
66 type Float struct {
67 f float64
68 mu sync.RWMutex
69 }
70
71 func (v *Float) String() string {
72 v.mu.RLock()
73 defer v.mu.RUnlock()
74 return strconv.FormatFloat(v.f, 'g', -1, 64)
75 }
76
77
78 func (v *Float) Add(delta float64) {
79 v.mu.Lock()
80 defer v.mu.Unlock()
81 v.f += delta
82 }
83
84
85 func (v *Float) Set(value float64) {
86 v.mu.Lock()
87 defer v.mu.Unlock()
88 v.f = value
89 }
90
91
92 type Map struct {
93 m map[string]Var
94 mu sync.RWMutex
95 }
96
97
98 type KeyValue struct {
99 Key string
100 Value Var
101 }
102
103 func (v *Map) String() string {
104 v.mu.RLock()
105 defer v.mu.RUnlock()
106 var b bytes.Buffer
107 fmt.Fprintf(&b, "{")
108 first := true
109 for key, val := range v.m {
110 if !first {
111 fmt.Fprintf(&b, ", ")
112 }
113 fmt.Fprintf(&b, "\"%s\": %v", key, val)
114 first = false
115 }
116 fmt.Fprintf(&b, "}")
117 return b.String()
118 }
119
120 func (v *Map) Init() *Map {
121 v.m = make(map[string]Var)
122 return v
123 }
124
125 func (v *Map) Get(key string) Var {
126 v.mu.RLock()
127 defer v.mu.RUnlock()
128 return v.m[key]
129 }
130
131 func (v *Map) Set(key string, av Var) {
132 v.mu.Lock()
133 defer v.mu.Unlock()
134 v.m[key] = av
135 }
136
137 func (v *Map) Add(key string, delta int64) {
138 v.mu.RLock()
139 av, ok := v.m[key]
140 v.mu.RUnlock()
141 if !ok {
142
143 v.mu.Lock()
144 if _, ok = v.m[key]; !ok {
145 av = new(Int)
146 v.m[key] = av
147 }
148 v.mu.Unlock()
149 }
150
151
152 if iv, ok := av.(*Int); ok {
153 iv.Add(delta)
154 }
155 }
156
157
158 func (v *Map) AddFloat(key string, delta float64) {
159 v.mu.RLock()
160 av, ok := v.m[key]
161 v.mu.RUnlock()
162 if !ok {
163
164 v.mu.Lock()
165 if _, ok = v.m[key]; !ok {
166 av = new(Float)
167 v.m[key] = av
168 }
169 v.mu.Unlock()
170 }
171
172
173 if iv, ok := av.(*Float); ok {
174 iv.Add(delta)
175 }
176 }
177
178
179
180
181 func (v *Map) Do(f func(KeyValue)) {
182 v.mu.RLock()
183 defer v.mu.RUnlock()
184 for k, v := range v.m {
185 f(KeyValue{k, v})
186 }
187 }
188
189
190 type String struct {
191 s string
192 mu sync.RWMutex
193 }
194
195 func (v *String) String() string {
196 v.mu.RLock()
197 defer v.mu.RUnlock()
198 return strconv.Quote(v.s)
199 }
200
201 func (v *String) Set(value string) {
202 v.mu.Lock()
203 defer v.mu.Unlock()
204 v.s = value
205 }
206
207
208
209 type Func func() interface{}
210
211 func (f Func) String() string {
212 v, _ := json.Marshal(f())
213 return string(v)
214 }
215
216
217 var (
218 mutex sync.RWMutex
219 vars map[string]Var = make(map[string]Var)
220 )
221
222
223
224
225 func Publish(name string, v Var) {
226 mutex.Lock()
227 defer mutex.Unlock()
228 if _, existing := vars[name]; existing {
229 log.Panicln("Reuse of exported var name:", name)
230 }
231 vars[name] = v
232 }
233
234
235 func Get(name string) Var {
236 mutex.RLock()
237 defer mutex.RUnlock()
238 return vars[name]
239 }
240
241
242
243 func NewInt(name string) *Int {
244 v := new(Int)
245 Publish(name, v)
246 return v
247 }
248
249 func NewFloat(name string) *Float {
250 v := new(Float)
251 Publish(name, v)
252 return v
253 }
254
255 func NewMap(name string) *Map {
256 v := new(Map).Init()
257 Publish(name, v)
258 return v
259 }
260
261 func NewString(name string) *String {
262 v := new(String)
263 Publish(name, v)
264 return v
265 }
266
267
268
269
270 func Do(f func(KeyValue)) {
271 mutex.RLock()
272 defer mutex.RUnlock()
273 for k, v := range vars {
274 f(KeyValue{k, v})
275 }
276 }
277
278 func expvarHandler(w http.ResponseWriter, r *http.Request) {
279 w.Header().Set("Content-Type", "application/json; charset=utf-8")
280 fmt.Fprintf(w, "{\n")
281 first := true
282 Do(func(kv KeyValue) {
283 if !first {
284 fmt.Fprintf(w, ",\n")
285 }
286 first = false
287 fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
288 })
289 fmt.Fprintf(w, "\n}\n")
290 }
291
292 func cmdline() interface{} {
293 return os.Args
294 }
295
296 func memstats() interface{} {
297 stats := new(runtime.MemStats)
298 runtime.ReadMemStats(stats)
299 return *stats
300 }
301
302 func init() {
303 http.HandleFunc("/debug/vars", expvarHandler)
304 Publish("cmdline", Func(cmdline))
305 Publish("memstats", Func(memstats))
306 }
View as plain text