expvar.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  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. // Package expvar provides a standardized interface to public variables, such
  5. // as operation counters in servers. It exposes these variables via HTTP at
  6. // /debug/vars in JSON format.
  7. //
  8. // Operations to set or modify these public variables are atomic.
  9. //
  10. // In addition to adding the HTTP handler, this package registers the
  11. // following variables:
  12. //
  13. // cmdline os.Args
  14. // memstats runtime.Memstats
  15. //
  16. // The package is sometimes only imported for the side effect of
  17. // registering its HTTP handler and the above variables. To use it
  18. // this way, link this package into your program:
  19. // import _ "expvar"
  20. //
  21. package expvar
  22. import (
  23. "bytes"
  24. "encoding/json"
  25. "fmt"
  26. "log"
  27. "net/http"
  28. "os"
  29. "runtime"
  30. "sort"
  31. "strconv"
  32. "sync"
  33. )
  34. // Var is an abstract type for all exported variables.
  35. type Var interface {
  36. String() string
  37. }
  38. // Int is a 64-bit integer variable that satisfies the Var interface.
  39. type Int struct {
  40. mu sync.RWMutex
  41. i int64
  42. }
  43. func (v *Int) String() string {
  44. v.mu.RLock()
  45. defer v.mu.RUnlock()
  46. return strconv.FormatInt(v.i, 10)
  47. }
  48. func (v *Int) Add(delta int64) {
  49. v.mu.Lock()
  50. defer v.mu.Unlock()
  51. v.i += delta
  52. }
  53. func (v *Int) Set(value int64) {
  54. v.mu.Lock()
  55. defer v.mu.Unlock()
  56. v.i = value
  57. }
  58. // Float is a 64-bit float variable that satisfies the Var interface.
  59. type Float struct {
  60. mu sync.RWMutex
  61. f float64
  62. }
  63. func (v *Float) String() string {
  64. v.mu.RLock()
  65. defer v.mu.RUnlock()
  66. return strconv.FormatFloat(v.f, 'g', -1, 64)
  67. }
  68. // Add adds delta to v.
  69. func (v *Float) Add(delta float64) {
  70. v.mu.Lock()
  71. defer v.mu.Unlock()
  72. v.f += delta
  73. }
  74. // Set sets v to value.
  75. func (v *Float) Set(value float64) {
  76. v.mu.Lock()
  77. defer v.mu.Unlock()
  78. v.f = value
  79. }
  80. // Map is a string-to-Var map variable that satisfies the Var interface.
  81. type Map struct {
  82. mu sync.RWMutex
  83. m map[string]Var
  84. keys []string // sorted
  85. }
  86. // KeyValue represents a single entry in a Map.
  87. type KeyValue struct {
  88. Key string
  89. Value Var
  90. }
  91. func (v *Map) String() string {
  92. v.mu.RLock()
  93. defer v.mu.RUnlock()
  94. var b bytes.Buffer
  95. fmt.Fprintf(&b, "{")
  96. first := true
  97. v.doLocked(func(kv KeyValue) {
  98. if !first {
  99. fmt.Fprintf(&b, ", ")
  100. }
  101. fmt.Fprintf(&b, "%q: %v", kv.Key, kv.Value)
  102. first = false
  103. })
  104. fmt.Fprintf(&b, "}")
  105. return b.String()
  106. }
  107. func (v *Map) Init() *Map {
  108. v.m = make(map[string]Var)
  109. return v
  110. }
  111. // updateKeys updates the sorted list of keys in v.keys.
  112. // must be called with v.mu held.
  113. func (v *Map) updateKeys() {
  114. if len(v.m) == len(v.keys) {
  115. // No new key.
  116. return
  117. }
  118. v.keys = v.keys[:0]
  119. for k := range v.m {
  120. v.keys = append(v.keys, k)
  121. }
  122. sort.Strings(v.keys)
  123. }
  124. func (v *Map) Get(key string) Var {
  125. v.mu.RLock()
  126. defer v.mu.RUnlock()
  127. return v.m[key]
  128. }
  129. func (v *Map) Set(key string, av Var) {
  130. v.mu.Lock()
  131. defer v.mu.Unlock()
  132. v.m[key] = av
  133. v.updateKeys()
  134. }
  135. func (v *Map) Add(key string, delta int64) {
  136. v.mu.RLock()
  137. av, ok := v.m[key]
  138. v.mu.RUnlock()
  139. if !ok {
  140. // check again under the write lock
  141. v.mu.Lock()
  142. av, ok = v.m[key]
  143. if !ok {
  144. av = new(Int)
  145. v.m[key] = av
  146. v.updateKeys()
  147. }
  148. v.mu.Unlock()
  149. }
  150. // Add to Int; ignore otherwise.
  151. if iv, ok := av.(*Int); ok {
  152. iv.Add(delta)
  153. }
  154. }
  155. // AddFloat adds delta to the *Float value stored under the given map key.
  156. func (v *Map) AddFloat(key string, delta float64) {
  157. v.mu.RLock()
  158. av, ok := v.m[key]
  159. v.mu.RUnlock()
  160. if !ok {
  161. // check again under the write lock
  162. v.mu.Lock()
  163. av, ok = v.m[key]
  164. if !ok {
  165. av = new(Float)
  166. v.m[key] = av
  167. v.updateKeys()
  168. }
  169. v.mu.Unlock()
  170. }
  171. // Add to Float; ignore otherwise.
  172. if iv, ok := av.(*Float); ok {
  173. iv.Add(delta)
  174. }
  175. }
  176. // Do calls f for each entry in the map.
  177. // The map is locked during the iteration,
  178. // but existing entries may be concurrently updated.
  179. func (v *Map) Do(f func(KeyValue)) {
  180. v.mu.RLock()
  181. defer v.mu.RUnlock()
  182. v.doLocked(f)
  183. }
  184. // doLocked calls f for each entry in the map.
  185. // v.mu must be held for reads.
  186. func (v *Map) doLocked(f func(KeyValue)) {
  187. for _, k := range v.keys {
  188. f(KeyValue{k, v.m[k]})
  189. }
  190. }
  191. // String is a string variable, and satisfies the Var interface.
  192. type String struct {
  193. mu sync.RWMutex
  194. s string
  195. }
  196. func (v *String) String() string {
  197. v.mu.RLock()
  198. defer v.mu.RUnlock()
  199. return strconv.Quote(v.s)
  200. }
  201. func (v *String) Set(value string) {
  202. v.mu.Lock()
  203. defer v.mu.Unlock()
  204. v.s = value
  205. }
  206. // Func implements Var by calling the function
  207. // and formatting the returned value using JSON.
  208. type Func func() interface{}
  209. func (f Func) String() string {
  210. v, _ := json.Marshal(f())
  211. return string(v)
  212. }
  213. // All published variables.
  214. var (
  215. mutex sync.RWMutex
  216. vars = make(map[string]Var)
  217. varKeys []string // sorted
  218. )
  219. // Publish declares a named exported variable. This should be called from a
  220. // package's init function when it creates its Vars. If the name is already
  221. // registered then this will log.Panic.
  222. func Publish(name string, v Var) {
  223. mutex.Lock()
  224. defer mutex.Unlock()
  225. if _, existing := vars[name]; existing {
  226. log.Panicln("Reuse of exported var name:", name)
  227. }
  228. vars[name] = v
  229. varKeys = append(varKeys, name)
  230. sort.Strings(varKeys)
  231. }
  232. // Get retrieves a named exported variable.
  233. func Get(name string) Var {
  234. mutex.RLock()
  235. defer mutex.RUnlock()
  236. return vars[name]
  237. }
  238. // Convenience functions for creating new exported variables.
  239. func NewInt(name string) *Int {
  240. v := new(Int)
  241. Publish(name, v)
  242. return v
  243. }
  244. func NewFloat(name string) *Float {
  245. v := new(Float)
  246. Publish(name, v)
  247. return v
  248. }
  249. func NewMap(name string) *Map {
  250. v := new(Map).Init()
  251. Publish(name, v)
  252. return v
  253. }
  254. func NewString(name string) *String {
  255. v := new(String)
  256. Publish(name, v)
  257. return v
  258. }
  259. // Do calls f for each exported variable.
  260. // The global variable map is locked during the iteration,
  261. // but existing entries may be concurrently updated.
  262. func Do(f func(KeyValue)) {
  263. mutex.RLock()
  264. defer mutex.RUnlock()
  265. for _, k := range varKeys {
  266. f(KeyValue{k, vars[k]})
  267. }
  268. }
  269. func expvarHandler(w http.ResponseWriter, r *http.Request) {
  270. w.Header().Set("Content-Type", "application/json; charset=utf-8")
  271. fmt.Fprintf(w, "{\n")
  272. first := true
  273. Do(func(kv KeyValue) {
  274. if !first {
  275. fmt.Fprintf(w, ",\n")
  276. }
  277. first = false
  278. fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
  279. })
  280. fmt.Fprintf(w, "\n}\n")
  281. }
  282. func cmdline() interface{} {
  283. return os.Args
  284. }
  285. func memstats() interface{} {
  286. stats := new(runtime.MemStats)
  287. runtime.ReadMemStats(stats)
  288. return *stats
  289. }
  290. func init() {
  291. http.HandleFunc("/debug/vars", expvarHandler)
  292. Publish("cmdline", Func(cmdline))
  293. Publish("memstats", Func(memstats))
  294. }