Rebase.
[official-gcc.git] / libgo / go / expvar / expvar.go
blob9b6dab487cb6209e9b3e407dce9f90ce23bca372
1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Package expvar provides a standardized interface to public variables, such
6 // as operation counters in servers. It exposes these variables via HTTP at
7 // /debug/vars in JSON format.
8 //
9 // Operations to set or modify these public variables are atomic.
11 // In addition to adding the HTTP handler, this package registers the
12 // following variables:
14 // cmdline os.Args
15 // memstats runtime.Memstats
17 // The package is sometimes only imported for the side effect of
18 // registering its HTTP handler and the above variables. To use it
19 // this way, link this package into your program:
20 // import _ "expvar"
22 package expvar
24 import (
25 "bytes"
26 "encoding/json"
27 "fmt"
28 "log"
29 "net/http"
30 "os"
31 "runtime"
32 "sort"
33 "strconv"
34 "sync"
37 // Var is an abstract type for all exported variables.
38 type Var interface {
39 String() string
42 // Int is a 64-bit integer variable that satisfies the Var interface.
43 type Int struct {
44 mu sync.RWMutex
45 i int64
48 func (v *Int) String() string {
49 v.mu.RLock()
50 defer v.mu.RUnlock()
51 return strconv.FormatInt(v.i, 10)
54 func (v *Int) Add(delta int64) {
55 v.mu.Lock()
56 defer v.mu.Unlock()
57 v.i += delta
60 func (v *Int) Set(value int64) {
61 v.mu.Lock()
62 defer v.mu.Unlock()
63 v.i = value
66 // Float is a 64-bit float variable that satisfies the Var interface.
67 type Float struct {
68 mu sync.RWMutex
69 f float64
72 func (v *Float) String() string {
73 v.mu.RLock()
74 defer v.mu.RUnlock()
75 return strconv.FormatFloat(v.f, 'g', -1, 64)
78 // Add adds delta to v.
79 func (v *Float) Add(delta float64) {
80 v.mu.Lock()
81 defer v.mu.Unlock()
82 v.f += delta
85 // Set sets v to value.
86 func (v *Float) Set(value float64) {
87 v.mu.Lock()
88 defer v.mu.Unlock()
89 v.f = value
92 // Map is a string-to-Var map variable that satisfies the Var interface.
93 type Map struct {
94 mu sync.RWMutex
95 m map[string]Var
96 keys []string // sorted
99 // KeyValue represents a single entry in a Map.
100 type KeyValue struct {
101 Key string
102 Value Var
105 func (v *Map) String() string {
106 v.mu.RLock()
107 defer v.mu.RUnlock()
108 var b bytes.Buffer
109 fmt.Fprintf(&b, "{")
110 first := true
111 v.doLocked(func(kv KeyValue) {
112 if !first {
113 fmt.Fprintf(&b, ", ")
115 fmt.Fprintf(&b, "%q: %v", kv.Key, kv.Value)
116 first = false
118 fmt.Fprintf(&b, "}")
119 return b.String()
122 func (v *Map) Init() *Map {
123 v.m = make(map[string]Var)
124 return v
127 // updateKeys updates the sorted list of keys in v.keys.
128 // must be called with v.mu held.
129 func (v *Map) updateKeys() {
130 if len(v.m) == len(v.keys) {
131 // No new key.
132 return
134 v.keys = v.keys[:0]
135 for k := range v.m {
136 v.keys = append(v.keys, k)
138 sort.Strings(v.keys)
141 func (v *Map) Get(key string) Var {
142 v.mu.RLock()
143 defer v.mu.RUnlock()
144 return v.m[key]
147 func (v *Map) Set(key string, av Var) {
148 v.mu.Lock()
149 defer v.mu.Unlock()
150 v.m[key] = av
151 v.updateKeys()
154 func (v *Map) Add(key string, delta int64) {
155 v.mu.RLock()
156 av, ok := v.m[key]
157 v.mu.RUnlock()
158 if !ok {
159 // check again under the write lock
160 v.mu.Lock()
161 av, ok = v.m[key]
162 if !ok {
163 av = new(Int)
164 v.m[key] = av
165 v.updateKeys()
167 v.mu.Unlock()
170 // Add to Int; ignore otherwise.
171 if iv, ok := av.(*Int); ok {
172 iv.Add(delta)
176 // AddFloat adds delta to the *Float value stored under the given map key.
177 func (v *Map) AddFloat(key string, delta float64) {
178 v.mu.RLock()
179 av, ok := v.m[key]
180 v.mu.RUnlock()
181 if !ok {
182 // check again under the write lock
183 v.mu.Lock()
184 av, ok = v.m[key]
185 if !ok {
186 av = new(Float)
187 v.m[key] = av
188 v.updateKeys()
190 v.mu.Unlock()
193 // Add to Float; ignore otherwise.
194 if iv, ok := av.(*Float); ok {
195 iv.Add(delta)
199 // Do calls f for each entry in the map.
200 // The map is locked during the iteration,
201 // but existing entries may be concurrently updated.
202 func (v *Map) Do(f func(KeyValue)) {
203 v.mu.RLock()
204 defer v.mu.RUnlock()
205 v.doLocked(f)
208 // doLocked calls f for each entry in the map.
209 // v.mu must be held for reads.
210 func (v *Map) doLocked(f func(KeyValue)) {
211 for _, k := range v.keys {
212 f(KeyValue{k, v.m[k]})
216 // String is a string variable, and satisfies the Var interface.
217 type String struct {
218 mu sync.RWMutex
219 s string
222 func (v *String) String() string {
223 v.mu.RLock()
224 defer v.mu.RUnlock()
225 return strconv.Quote(v.s)
228 func (v *String) Set(value string) {
229 v.mu.Lock()
230 defer v.mu.Unlock()
231 v.s = value
234 // Func implements Var by calling the function
235 // and formatting the returned value using JSON.
236 type Func func() interface{}
238 func (f Func) String() string {
239 v, _ := json.Marshal(f())
240 return string(v)
243 // All published variables.
244 var (
245 mutex sync.RWMutex
246 vars = make(map[string]Var)
247 varKeys []string // sorted
250 // Publish declares a named exported variable. This should be called from a
251 // package's init function when it creates its Vars. If the name is already
252 // registered then this will log.Panic.
253 func Publish(name string, v Var) {
254 mutex.Lock()
255 defer mutex.Unlock()
256 if _, existing := vars[name]; existing {
257 log.Panicln("Reuse of exported var name:", name)
259 vars[name] = v
260 varKeys = append(varKeys, name)
261 sort.Strings(varKeys)
264 // Get retrieves a named exported variable.
265 func Get(name string) Var {
266 mutex.RLock()
267 defer mutex.RUnlock()
268 return vars[name]
271 // Convenience functions for creating new exported variables.
273 func NewInt(name string) *Int {
274 v := new(Int)
275 Publish(name, v)
276 return v
279 func NewFloat(name string) *Float {
280 v := new(Float)
281 Publish(name, v)
282 return v
285 func NewMap(name string) *Map {
286 v := new(Map).Init()
287 Publish(name, v)
288 return v
291 func NewString(name string) *String {
292 v := new(String)
293 Publish(name, v)
294 return v
297 // Do calls f for each exported variable.
298 // The global variable map is locked during the iteration,
299 // but existing entries may be concurrently updated.
300 func Do(f func(KeyValue)) {
301 mutex.RLock()
302 defer mutex.RUnlock()
303 for _, k := range varKeys {
304 f(KeyValue{k, vars[k]})
308 func expvarHandler(w http.ResponseWriter, r *http.Request) {
309 w.Header().Set("Content-Type", "application/json; charset=utf-8")
310 fmt.Fprintf(w, "{\n")
311 first := true
312 Do(func(kv KeyValue) {
313 if !first {
314 fmt.Fprintf(w, ",\n")
316 first = false
317 fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
319 fmt.Fprintf(w, "\n}\n")
322 func cmdline() interface{} {
323 return os.Args
326 func memstats() interface{} {
327 stats := new(runtime.MemStats)
328 runtime.ReadMemStats(stats)
329 return *stats
332 func init() {
333 http.HandleFunc("/debug/vars", expvarHandler)
334 Publish("cmdline", Func(cmdline))
335 Publish("memstats", Func(memstats))