blob: 24c2d6b29ab4221928104eb052ff693bb223f733 [file] [log] [blame]
David Symonds3cc702b2009-04-19 21:17:27 -07001// 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
Nigel Tao6a186d32011-04-20 09:57:05 +10005// 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.
Russ Coxa7098762010-03-29 13:06:26 -07008//
Sam Thorogood3b9c9d22010-10-11 13:14:07 -04009// Operations to set or modify these public variables are atomic.
10//
Russ Coxa7098762010-03-29 13:06:26 -070011// 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
Russ Coxae7497b2012-02-06 13:34:35 -050019// this way, link this package into your program:
Russ Coxa7098762010-03-29 13:06:26 -070020// import _ "expvar"
21//
Rob Pike0632bb42009-09-30 13:11:33 -070022package expvar
David Symonds3cc702b2009-04-19 21:17:27 -070023
24import (
Robert Griesemer1c729592009-12-15 15:27:16 -080025 "bytes"
Rob Pike30aa7012011-11-08 15:40:58 -080026 "encoding/json"
Robert Griesemer1c729592009-12-15 15:27:16 -080027 "fmt"
Robert Griesemer1c729592009-12-15 15:27:16 -080028 "log"
Matt T. Proud926616d2015-02-02 00:33:44 -080029 "math"
Rob Pike30aa7012011-11-08 15:40:58 -080030 "net/http"
Russ Coxa7098762010-03-29 13:06:26 -070031 "os"
32 "runtime"
Brad Fitzpatrickcfb9cf02014-01-20 09:59:23 -080033 "sort"
Robert Griesemer1c729592009-12-15 15:27:16 -080034 "strconv"
35 "sync"
Evan Phoenixbd043d82015-01-28 09:16:44 -080036 "sync/atomic"
David Symonds3cc702b2009-04-19 21:17:27 -070037)
38
David Symonds2f284942009-05-04 15:14:22 -070039// Var is an abstract type for all exported variables.
40type Var interface {
Robert Griesemer1c729592009-12-15 15:27:16 -080041 String() string
David Symondsde489fb2009-04-20 22:38:14 -070042}
43
Jos Visser25f762c2011-01-18 11:24:43 -050044// Int is a 64-bit integer variable that satisfies the Var interface.
David Symonds2f284942009-05-04 15:14:22 -070045type Int struct {
Evan Phoenixbd043d82015-01-28 09:16:44 -080046 i int64
David Symondsde489fb2009-04-20 22:38:14 -070047}
48
Brad Fitzpatrick1042d7d2012-03-05 11:09:50 -080049func (v *Int) String() string {
Evan Phoenixbd043d82015-01-28 09:16:44 -080050 return strconv.FormatInt(atomic.LoadInt64(&v.i), 10)
Brad Fitzpatrick1042d7d2012-03-05 11:09:50 -080051}
David Symondsde489fb2009-04-20 22:38:14 -070052
David Symonds2f284942009-05-04 15:14:22 -070053func (v *Int) Add(delta int64) {
Evan Phoenixbd043d82015-01-28 09:16:44 -080054 atomic.AddInt64(&v.i, delta)
David Symonds2f284942009-05-04 15:14:22 -070055}
56
Sam Thorogood3b9c9d22010-10-11 13:14:07 -040057func (v *Int) Set(value int64) {
Evan Phoenixbd043d82015-01-28 09:16:44 -080058 atomic.StoreInt64(&v.i, value)
Sam Thorogood3b9c9d22010-10-11 13:14:07 -040059}
60
Jos Visser25f762c2011-01-18 11:24:43 -050061// Float is a 64-bit float variable that satisfies the Var interface.
62type Float struct {
Matt T. Proud926616d2015-02-02 00:33:44 -080063 f uint64
Jos Visser25f762c2011-01-18 11:24:43 -050064}
65
Brad Fitzpatrick1042d7d2012-03-05 11:09:50 -080066func (v *Float) String() string {
Matt T. Proud926616d2015-02-02 00:33:44 -080067 return strconv.FormatFloat(
68 math.Float64frombits(atomic.LoadUint64(&v.f)), 'g', -1, 64)
Brad Fitzpatrick1042d7d2012-03-05 11:09:50 -080069}
Jos Visser25f762c2011-01-18 11:24:43 -050070
71// Add adds delta to v.
72func (v *Float) Add(delta float64) {
Matt T. Proud926616d2015-02-02 00:33:44 -080073 for {
74 cur := atomic.LoadUint64(&v.f)
75 curVal := math.Float64frombits(cur)
76 nxtVal := curVal + delta
77 nxt := math.Float64bits(nxtVal)
78 if atomic.CompareAndSwapUint64(&v.f, cur, nxt) {
79 return
80 }
81 }
Jos Visser25f762c2011-01-18 11:24:43 -050082}
83
84// Set sets v to value.
85func (v *Float) Set(value float64) {
Matt T. Proud926616d2015-02-02 00:33:44 -080086 atomic.StoreUint64(&v.f, math.Float64bits(value))
Jos Visser25f762c2011-01-18 11:24:43 -050087}
88
89// Map is a string-to-Var map variable that satisfies the Var interface.
David Symonds2f284942009-05-04 15:14:22 -070090type Map struct {
Brad Fitzpatrickcfb9cf02014-01-20 09:59:23 -080091 mu sync.RWMutex
92 m map[string]Var
93 keys []string // sorted
David Symonds2f284942009-05-04 15:14:22 -070094}
95
96// KeyValue represents a single entry in a Map.
97type KeyValue struct {
Robert Griesemer1c729592009-12-15 15:27:16 -080098 Key string
99 Value Var
David Symonds2f284942009-05-04 15:14:22 -0700100}
101
102func (v *Map) String() string {
David Symonds715588f2012-02-04 14:32:05 +1100103 v.mu.RLock()
104 defer v.mu.RUnlock()
Brad Fitzpatrick1042d7d2012-03-05 11:09:50 -0800105 var b bytes.Buffer
106 fmt.Fprintf(&b, "{")
Robert Griesemer1c729592009-12-15 15:27:16 -0800107 first := true
Brad Fitzpatrick666f5b42014-03-18 11:38:39 -0700108 v.doLocked(func(kv KeyValue) {
David Symonds2f284942009-05-04 15:14:22 -0700109 if !first {
Brad Fitzpatrick1042d7d2012-03-05 11:09:50 -0800110 fmt.Fprintf(&b, ", ")
David Symonds2f284942009-05-04 15:14:22 -0700111 }
Rui Ueyama74c6b842014-04-10 21:14:04 -0700112 fmt.Fprintf(&b, "%q: %v", kv.Key, kv.Value)
Robert Griesemer1c729592009-12-15 15:27:16 -0800113 first = false
Brad Fitzpatrickcfb9cf02014-01-20 09:59:23 -0800114 })
Brad Fitzpatrick1042d7d2012-03-05 11:09:50 -0800115 fmt.Fprintf(&b, "}")
Robert Griesemer1c729592009-12-15 15:27:16 -0800116 return b.String()
David Symondsde489fb2009-04-20 22:38:14 -0700117}
118
Brendan O'Dea89df0712009-05-18 15:42:09 -0700119func (v *Map) Init() *Map {
Robert Griesemer1c729592009-12-15 15:27:16 -0800120 v.m = make(map[string]Var)
121 return v
Brendan O'Dea89df0712009-05-18 15:42:09 -0700122}
123
Brad Fitzpatrickcfb9cf02014-01-20 09:59:23 -0800124// updateKeys updates the sorted list of keys in v.keys.
125// must be called with v.mu held.
126func (v *Map) updateKeys() {
127 if len(v.m) == len(v.keys) {
128 // No new key.
129 return
130 }
131 v.keys = v.keys[:0]
132 for k := range v.m {
133 v.keys = append(v.keys, k)
134 }
135 sort.Strings(v.keys)
136}
137
David Symonds2f284942009-05-04 15:14:22 -0700138func (v *Map) Get(key string) Var {
David Symonds715588f2012-02-04 14:32:05 +1100139 v.mu.RLock()
140 defer v.mu.RUnlock()
Russ Coxc7122a32010-03-30 10:51:11 -0700141 return v.m[key]
David Symondsde489fb2009-04-20 22:38:14 -0700142}
143
David Symonds2f284942009-05-04 15:14:22 -0700144func (v *Map) Set(key string, av Var) {
Robert Griesemer1c729592009-12-15 15:27:16 -0800145 v.mu.Lock()
146 defer v.mu.Unlock()
147 v.m[key] = av
Brad Fitzpatrickcfb9cf02014-01-20 09:59:23 -0800148 v.updateKeys()
David Symonds2f284942009-05-04 15:14:22 -0700149}
150
151func (v *Map) Add(key string, delta int64) {
David Symonds715588f2012-02-04 14:32:05 +1100152 v.mu.RLock()
Robert Griesemer1c729592009-12-15 15:27:16 -0800153 av, ok := v.m[key]
David Symonds715588f2012-02-04 14:32:05 +1100154 v.mu.RUnlock()
David Symonds2f284942009-05-04 15:14:22 -0700155 if !ok {
David Symonds715588f2012-02-04 14:32:05 +1100156 // check again under the write lock
157 v.mu.Lock()
Brad Fitzpatrickcfb9cf02014-01-20 09:59:23 -0800158 av, ok = v.m[key]
159 if !ok {
David Symonds715588f2012-02-04 14:32:05 +1100160 av = new(Int)
161 v.m[key] = av
Brad Fitzpatrickcfb9cf02014-01-20 09:59:23 -0800162 v.updateKeys()
David Symonds715588f2012-02-04 14:32:05 +1100163 }
164 v.mu.Unlock()
David Symondsde489fb2009-04-20 22:38:14 -0700165 }
David Symondsde489fb2009-04-20 22:38:14 -0700166
David Symonds2f284942009-05-04 15:14:22 -0700167 // Add to Int; ignore otherwise.
168 if iv, ok := av.(*Int); ok {
Robert Griesemer40621d52009-11-09 12:07:39 -0800169 iv.Add(delta)
David Symondsf4b92c82009-04-26 20:57:01 -0700170 }
David Symondsf4b92c82009-04-26 20:57:01 -0700171}
172
Jos Visser25f762c2011-01-18 11:24:43 -0500173// AddFloat adds delta to the *Float value stored under the given map key.
174func (v *Map) AddFloat(key string, delta float64) {
David Symonds715588f2012-02-04 14:32:05 +1100175 v.mu.RLock()
Jos Visser25f762c2011-01-18 11:24:43 -0500176 av, ok := v.m[key]
David Symonds715588f2012-02-04 14:32:05 +1100177 v.mu.RUnlock()
Jos Visser25f762c2011-01-18 11:24:43 -0500178 if !ok {
David Symonds715588f2012-02-04 14:32:05 +1100179 // check again under the write lock
180 v.mu.Lock()
Brad Fitzpatrickcfb9cf02014-01-20 09:59:23 -0800181 av, ok = v.m[key]
182 if !ok {
David Symonds715588f2012-02-04 14:32:05 +1100183 av = new(Float)
184 v.m[key] = av
Brad Fitzpatrickcfb9cf02014-01-20 09:59:23 -0800185 v.updateKeys()
David Symonds715588f2012-02-04 14:32:05 +1100186 }
187 v.mu.Unlock()
Jos Visser25f762c2011-01-18 11:24:43 -0500188 }
189
190 // Add to Float; ignore otherwise.
191 if iv, ok := av.(*Float); ok {
192 iv.Add(delta)
193 }
194}
195
David Symonds715588f2012-02-04 14:32:05 +1100196// Do calls f for each entry in the map.
197// The map is locked during the iteration,
198// but existing entries may be concurrently updated.
199func (v *Map) Do(f func(KeyValue)) {
200 v.mu.RLock()
201 defer v.mu.RUnlock()
Brad Fitzpatrick666f5b42014-03-18 11:38:39 -0700202 v.doLocked(f)
203}
204
Robert Henckef999e142014-04-29 12:44:40 -0400205// doLocked calls f for each entry in the map.
Brad Fitzpatrick666f5b42014-03-18 11:38:39 -0700206// v.mu must be held for reads.
207func (v *Map) doLocked(f func(KeyValue)) {
Brad Fitzpatrickcfb9cf02014-01-20 09:59:23 -0800208 for _, k := range v.keys {
209 f(KeyValue{k, v.m[k]})
David Symonds2f284942009-05-04 15:14:22 -0700210 }
David Symonds2f284942009-05-04 15:14:22 -0700211}
212
213// String is a string variable, and satisfies the Var interface.
214type String struct {
David Symonds63e383c2012-03-06 09:13:26 +1100215 mu sync.RWMutex
Brad Fitzpatrickcfb9cf02014-01-20 09:59:23 -0800216 s string
David Symonds2f284942009-05-04 15:14:22 -0700217}
218
David Symonds63e383c2012-03-06 09:13:26 +1100219func (v *String) String() string {
220 v.mu.RLock()
221 defer v.mu.RUnlock()
222 return strconv.Quote(v.s)
223}
David Symonds2f284942009-05-04 15:14:22 -0700224
David Symonds63e383c2012-03-06 09:13:26 +1100225func (v *String) Set(value string) {
226 v.mu.Lock()
227 defer v.mu.Unlock()
228 v.s = value
229}
David Symonds2f284942009-05-04 15:14:22 -0700230
David Symonds57d0c262011-04-15 01:21:18 -0700231// Func implements Var by calling the function
232// and formatting the returned value using JSON.
233type Func func() interface{}
David Symonds5a12b182009-05-24 15:04:43 -0700234
David Symonds57d0c262011-04-15 01:21:18 -0700235func (f Func) String() string {
236 v, _ := json.Marshal(f())
237 return string(v)
238}
Russ Coxa7098762010-03-29 13:06:26 -0700239
David Symonds2f284942009-05-04 15:14:22 -0700240// All published variables.
David Symonds715588f2012-02-04 14:32:05 +1100241var (
Brad Fitzpatrickcfb9cf02014-01-20 09:59:23 -0800242 mutex sync.RWMutex
243 vars = make(map[string]Var)
244 varKeys []string // sorted
David Symonds715588f2012-02-04 14:32:05 +1100245)
David Symonds2f284942009-05-04 15:14:22 -0700246
Rob Pike0244bae2011-12-09 14:24:51 -0800247// Publish declares a named exported variable. This should be called from a
David Symonds2f284942009-05-04 15:14:22 -0700248// package's init function when it creates its Vars. If the name is already
Rob Pike12da5a92010-10-12 12:59:18 -0700249// registered then this will log.Panic.
David Symonds2f284942009-05-04 15:14:22 -0700250func Publish(name string, v Var) {
Robert Griesemer1c729592009-12-15 15:27:16 -0800251 mutex.Lock()
252 defer mutex.Unlock()
David Symonds2f284942009-05-04 15:14:22 -0700253 if _, existing := vars[name]; existing {
Rob Pike12da5a92010-10-12 12:59:18 -0700254 log.Panicln("Reuse of exported var name:", name)
David Symonds2f284942009-05-04 15:14:22 -0700255 }
Robert Griesemer1c729592009-12-15 15:27:16 -0800256 vars[name] = v
Brad Fitzpatrickcfb9cf02014-01-20 09:59:23 -0800257 varKeys = append(varKeys, name)
258 sort.Strings(varKeys)
David Symonds2f284942009-05-04 15:14:22 -0700259}
260
261// Get retrieves a named exported variable.
262func Get(name string) Var {
David Symonds715588f2012-02-04 14:32:05 +1100263 mutex.RLock()
264 defer mutex.RUnlock()
Russ Coxc7122a32010-03-30 10:51:11 -0700265 return vars[name]
David Symonds2f284942009-05-04 15:14:22 -0700266}
267
268// Convenience functions for creating new exported variables.
269
270func NewInt(name string) *Int {
Robert Griesemer1c729592009-12-15 15:27:16 -0800271 v := new(Int)
272 Publish(name, v)
273 return v
David Symonds2f284942009-05-04 15:14:22 -0700274}
275
Jos Visser25f762c2011-01-18 11:24:43 -0500276func NewFloat(name string) *Float {
277 v := new(Float)
278 Publish(name, v)
279 return v
280}
281
David Symonds2f284942009-05-04 15:14:22 -0700282func NewMap(name string) *Map {
Robert Griesemer1c729592009-12-15 15:27:16 -0800283 v := new(Map).Init()
284 Publish(name, v)
285 return v
David Symonds2f284942009-05-04 15:14:22 -0700286}
287
288func NewString(name string) *String {
Robert Griesemer1c729592009-12-15 15:27:16 -0800289 v := new(String)
290 Publish(name, v)
291 return v
David Symonds2f284942009-05-04 15:14:22 -0700292}
293
David Symonds715588f2012-02-04 14:32:05 +1100294// Do calls f for each exported variable.
295// The global variable map is locked during the iteration,
296// but existing entries may be concurrently updated.
297func Do(f func(KeyValue)) {
298 mutex.RLock()
299 defer mutex.RUnlock()
Brad Fitzpatrickcfb9cf02014-01-20 09:59:23 -0800300 for _, k := range varKeys {
301 f(KeyValue{k, vars[k]})
David Symonds2f284942009-05-04 15:14:22 -0700302 }
David Symonds2f284942009-05-04 15:14:22 -0700303}
304
Stephen Mafd9a5d22010-09-29 14:30:12 +1000305func expvarHandler(w http.ResponseWriter, r *http.Request) {
Brad Fitzpatrick2c420ec2011-03-09 09:41:01 -0800306 w.Header().Set("Content-Type", "application/json; charset=utf-8")
Stephen Mafd9a5d22010-09-29 14:30:12 +1000307 fmt.Fprintf(w, "{\n")
Robert Griesemer1c729592009-12-15 15:27:16 -0800308 first := true
David Symonds715588f2012-02-04 14:32:05 +1100309 Do(func(kv KeyValue) {
David Symonds2f284942009-05-04 15:14:22 -0700310 if !first {
Stephen Mafd9a5d22010-09-29 14:30:12 +1000311 fmt.Fprintf(w, ",\n")
David Symonds5cb68432009-04-21 16:50:09 -0700312 }
Robert Griesemer1c729592009-12-15 15:27:16 -0800313 first = false
David Symonds715588f2012-02-04 14:32:05 +1100314 fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
315 })
Stephen Mafd9a5d22010-09-29 14:30:12 +1000316 fmt.Fprintf(w, "\n}\n")
David Symonds3cc702b2009-04-19 21:17:27 -0700317}
318
David Symonds57d0c262011-04-15 01:21:18 -0700319func cmdline() interface{} {
320 return os.Args
Russ Coxa7098762010-03-29 13:06:26 -0700321}
322
David Symonds57d0c262011-04-15 01:21:18 -0700323func memstats() interface{} {
Rémy Oudompheng842c9062012-02-06 19:16:26 +0100324 stats := new(runtime.MemStats)
325 runtime.ReadMemStats(stats)
326 return *stats
Russ Coxa7098762010-03-29 13:06:26 -0700327}
328
329func init() {
David Symonds715588f2012-02-04 14:32:05 +1100330 http.HandleFunc("/debug/vars", expvarHandler)
David Symonds57d0c262011-04-15 01:21:18 -0700331 Publish("cmdline", Func(cmdline))
332 Publish("memstats", Func(memstats))
Russ Coxa7098762010-03-29 13:06:26 -0700333}