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