OSDN Git Service

libgo: Update to weekly.2012-02-07.
[pf3gnuchains/gcc-fork.git] / libgo / go / expvar / expvar.go
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.
4
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.
10 //
11 // In addition to adding the HTTP handler, this package registers the
12 // following variables:
13 //
14 //      cmdline   os.Args
15 //      memstats  runtime.Memstats
16 //
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"
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 // Var is an abstract type for all exported variables.
37 type Var interface {
38         String() string
39 }
40
41 // Int is a 64-bit integer variable that satisfies the Var interface.
42 type Int struct {
43         i  int64
44         mu sync.Mutex
45 }
46
47 func (v *Int) String() string { return strconv.FormatInt(v.i, 10) }
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 // Float is a 64-bit float variable that satisfies the Var interface.
62 type Float struct {
63         f  float64
64         mu sync.Mutex
65 }
66
67 func (v *Float) String() string { return strconv.FormatFloat(v.f, 'g', -1, 64) }
68
69 // Add adds delta to v.
70 func (v *Float) Add(delta float64) {
71         v.mu.Lock()
72         defer v.mu.Unlock()
73         v.f += delta
74 }
75
76 // Set sets v to value.
77 func (v *Float) Set(value float64) {
78         v.mu.Lock()
79         defer v.mu.Unlock()
80         v.f = value
81 }
82
83 // Map is a string-to-Var map variable that satisfies the Var interface.
84 type Map struct {
85         m  map[string]Var
86         mu sync.RWMutex
87 }
88
89 // KeyValue represents a single entry in a Map.
90 type KeyValue struct {
91         Key   string
92         Value Var
93 }
94
95 func (v *Map) String() string {
96         v.mu.RLock()
97         defer v.mu.RUnlock()
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)
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.RLock()
119         defer v.mu.RUnlock()
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.RLock()
131         av, ok := v.m[key]
132         v.mu.RUnlock()
133         if !ok {
134                 // check again under the write lock
135                 v.mu.Lock()
136                 if _, ok = v.m[key]; !ok {
137                         av = new(Int)
138                         v.m[key] = av
139                 }
140                 v.mu.Unlock()
141         }
142
143         // Add to Int; ignore otherwise.
144         if iv, ok := av.(*Int); ok {
145                 iv.Add(delta)
146         }
147 }
148
149 // AddFloat adds delta to the *Float value stored under the given map key.
150 func (v *Map) AddFloat(key string, delta float64) {
151         v.mu.RLock()
152         av, ok := v.m[key]
153         v.mu.RUnlock()
154         if !ok {
155                 // check again under the write lock
156                 v.mu.Lock()
157                 if _, ok = v.m[key]; !ok {
158                         av = new(Float)
159                         v.m[key] = av
160                 }
161                 v.mu.Unlock()
162         }
163
164         // Add to Float; ignore otherwise.
165         if iv, ok := av.(*Float); ok {
166                 iv.Add(delta)
167         }
168 }
169
170 // Do calls f for each entry in the map.
171 // The map is locked during the iteration,
172 // but existing entries may be concurrently updated.
173 func (v *Map) Do(f func(KeyValue)) {
174         v.mu.RLock()
175         defer v.mu.RUnlock()
176         for k, v := range v.m {
177                 f(KeyValue{k, v})
178         }
179 }
180
181 // String is a string variable, and satisfies the Var interface.
182 type String struct {
183         s string
184 }
185
186 func (v *String) String() string { return strconv.Quote(v.s) }
187
188 func (v *String) Set(value string) { v.s = value }
189
190 // Func implements Var by calling the function
191 // and formatting the returned value using JSON.
192 type Func func() interface{}
193
194 func (f Func) String() string {
195         v, _ := json.Marshal(f())
196         return string(v)
197 }
198
199 // All published variables.
200 var (
201         mutex sync.RWMutex
202         vars  map[string]Var = make(map[string]Var)
203 )
204
205 // Publish declares a named exported variable. This should be called from a
206 // package's init function when it creates its Vars. If the name is already
207 // registered then this will log.Panic.
208 func Publish(name string, v Var) {
209         mutex.Lock()
210         defer mutex.Unlock()
211         if _, existing := vars[name]; existing {
212                 log.Panicln("Reuse of exported var name:", name)
213         }
214         vars[name] = v
215 }
216
217 // Get retrieves a named exported variable.
218 func Get(name string) Var {
219         mutex.RLock()
220         defer mutex.RUnlock()
221         return vars[name]
222 }
223
224 // Convenience functions for creating new exported variables.
225
226 func NewInt(name string) *Int {
227         v := new(Int)
228         Publish(name, v)
229         return v
230 }
231
232 func NewFloat(name string) *Float {
233         v := new(Float)
234         Publish(name, v)
235         return v
236 }
237
238 func NewMap(name string) *Map {
239         v := new(Map).Init()
240         Publish(name, v)
241         return v
242 }
243
244 func NewString(name string) *String {
245         v := new(String)
246         Publish(name, v)
247         return v
248 }
249
250 // Do calls f for each exported variable.
251 // The global variable map is locked during the iteration,
252 // but existing entries may be concurrently updated.
253 func Do(f func(KeyValue)) {
254         mutex.RLock()
255         defer mutex.RUnlock()
256         for k, v := range vars {
257                 f(KeyValue{k, v})
258         }
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         Do(func(kv KeyValue) {
266                 if !first {
267                         fmt.Fprintf(w, ",\n")
268                 }
269                 first = false
270                 fmt.Fprintf(w, "%q: %s", kv.Key, kv.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         stats := new(runtime.MemStats)
281         runtime.ReadMemStats(stats)
282         return *stats
283 }
284
285 func init() {
286         http.HandleFunc("/debug/vars", expvarHandler)
287         Publish("cmdline", Func(cmdline))
288         Publish("memstats", Func(memstats))
289 }