expvar.go 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  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. "encoding/json"
  24. "fmt"
  25. "log"
  26. "math"
  27. "net/http"
  28. "os"
  29. "runtime"
  30. "sort"
  31. "strconv"
  32. "strings"
  33. "sync"
  34. "sync/atomic"
  35. )
  36. // Var is an abstract type for all exported variables.
  37. type Var interface {
  38. // String returns a valid JSON value for the variable.
  39. // Types with String methods that do not return valid JSON
  40. // (such as time.Time) must not be used as a Var.
  41. String() string
  42. }
  43. // Int is a 64-bit integer variable that satisfies the Var interface.
  44. type Int struct {
  45. i int64
  46. }
  47. func (v *Int) Value() int64 {
  48. return atomic.LoadInt64(&v.i)
  49. }
  50. func (v *Int) String() string {
  51. return strconv.FormatInt(atomic.LoadInt64(&v.i), 10)
  52. }
  53. func (v *Int) Add(delta int64) {
  54. atomic.AddInt64(&v.i, delta)
  55. }
  56. func (v *Int) Set(value int64) {
  57. atomic.StoreInt64(&v.i, value)
  58. }
  59. // Float is a 64-bit float variable that satisfies the Var interface.
  60. type Float struct {
  61. f uint64
  62. }
  63. func (v *Float) Value() float64 {
  64. return math.Float64frombits(atomic.LoadUint64(&v.f))
  65. }
  66. func (v *Float) String() string {
  67. return strconv.FormatFloat(
  68. math.Float64frombits(atomic.LoadUint64(&v.f)), 'g', -1, 64)
  69. }
  70. // Add adds delta to v.
  71. func (v *Float) Add(delta float64) {
  72. for {
  73. cur := atomic.LoadUint64(&v.f)
  74. curVal := math.Float64frombits(cur)
  75. nxtVal := curVal + delta
  76. nxt := math.Float64bits(nxtVal)
  77. if atomic.CompareAndSwapUint64(&v.f, cur, nxt) {
  78. return
  79. }
  80. }
  81. }
  82. // Set sets v to value.
  83. func (v *Float) Set(value float64) {
  84. atomic.StoreUint64(&v.f, math.Float64bits(value))
  85. }
  86. // Map is a string-to-Var map variable that satisfies the Var interface.
  87. type Map struct {
  88. m sync.Map // map[string]Var
  89. keysMu sync.RWMutex
  90. keys []string // sorted
  91. }
  92. // KeyValue represents a single entry in a Map.
  93. type KeyValue struct {
  94. Key string
  95. Value Var
  96. }
  97. func (v *Map) String() string {
  98. var b strings.Builder
  99. fmt.Fprintf(&b, "{")
  100. first := true
  101. v.Do(func(kv KeyValue) {
  102. if !first {
  103. fmt.Fprintf(&b, ", ")
  104. }
  105. fmt.Fprintf(&b, "%q: %v", kv.Key, kv.Value)
  106. first = false
  107. })
  108. fmt.Fprintf(&b, "}")
  109. return b.String()
  110. }
  111. // Init removes all keys from the map.
  112. func (v *Map) Init() *Map {
  113. v.keysMu.Lock()
  114. defer v.keysMu.Unlock()
  115. v.keys = v.keys[:0]
  116. v.m.Range(func(k, _ any) bool {
  117. v.m.Delete(k)
  118. return true
  119. })
  120. return v
  121. }
  122. // addKey updates the sorted list of keys in v.keys.
  123. func (v *Map) addKey(key string) {
  124. v.keysMu.Lock()
  125. defer v.keysMu.Unlock()
  126. // Using insertion sort to place key into the already-sorted v.keys.
  127. if i := sort.SearchStrings(v.keys, key); i >= len(v.keys) {
  128. v.keys = append(v.keys, key)
  129. } else if v.keys[i] != key {
  130. v.keys = append(v.keys, "")
  131. copy(v.keys[i+1:], v.keys[i:])
  132. v.keys[i] = key
  133. }
  134. }
  135. func (v *Map) Get(key string) Var {
  136. i, _ := v.m.Load(key)
  137. av, _ := i.(Var)
  138. return av
  139. }
  140. func (v *Map) Set(key string, av Var) {
  141. // Before we store the value, check to see whether the key is new. Try a Load
  142. // before LoadOrStore: LoadOrStore causes the key interface to escape even on
  143. // the Load path.
  144. if _, ok := v.m.Load(key); !ok {
  145. if _, dup := v.m.LoadOrStore(key, av); !dup {
  146. v.addKey(key)
  147. return
  148. }
  149. }
  150. v.m.Store(key, av)
  151. }
  152. // Add adds delta to the *Int value stored under the given map key.
  153. func (v *Map) Add(key string, delta int64) {
  154. i, ok := v.m.Load(key)
  155. if !ok {
  156. var dup bool
  157. i, dup = v.m.LoadOrStore(key, new(Int))
  158. if !dup {
  159. v.addKey(key)
  160. }
  161. }
  162. // Add to Int; ignore otherwise.
  163. if iv, ok := i.(*Int); ok {
  164. iv.Add(delta)
  165. }
  166. }
  167. // AddFloat adds delta to the *Float value stored under the given map key.
  168. func (v *Map) AddFloat(key string, delta float64) {
  169. i, ok := v.m.Load(key)
  170. if !ok {
  171. var dup bool
  172. i, dup = v.m.LoadOrStore(key, new(Float))
  173. if !dup {
  174. v.addKey(key)
  175. }
  176. }
  177. // Add to Float; ignore otherwise.
  178. if iv, ok := i.(*Float); ok {
  179. iv.Add(delta)
  180. }
  181. }
  182. // Delete deletes the given key from the map.
  183. func (v *Map) Delete(key string) {
  184. v.keysMu.Lock()
  185. defer v.keysMu.Unlock()
  186. i := sort.SearchStrings(v.keys, key)
  187. if i < len(v.keys) && key == v.keys[i] {
  188. v.keys = append(v.keys[:i], v.keys[i+1:]...)
  189. v.m.Delete(key)
  190. }
  191. }
  192. // Do calls f for each entry in the map.
  193. // The map is locked during the iteration,
  194. // but existing entries may be concurrently updated.
  195. func (v *Map) Do(f func(KeyValue)) {
  196. v.keysMu.RLock()
  197. defer v.keysMu.RUnlock()
  198. for _, k := range v.keys {
  199. i, _ := v.m.Load(k)
  200. f(KeyValue{k, i.(Var)})
  201. }
  202. }
  203. // String is a string variable, and satisfies the Var interface.
  204. type String struct {
  205. s atomic.Value // string
  206. }
  207. func (v *String) Value() string {
  208. p, _ := v.s.Load().(string)
  209. return p
  210. }
  211. // String implements the Var interface. To get the unquoted string
  212. // use Value.
  213. func (v *String) String() string {
  214. s := v.Value()
  215. b, _ := json.Marshal(s)
  216. return string(b)
  217. }
  218. func (v *String) Set(value string) {
  219. v.s.Store(value)
  220. }
  221. // Func implements Var by calling the function
  222. // and formatting the returned value using JSON.
  223. type Func func() any
  224. func (f Func) Value() any {
  225. return f()
  226. }
  227. func (f Func) String() string {
  228. v, _ := json.Marshal(f())
  229. return string(v)
  230. }
  231. // All published variables.
  232. var (
  233. vars sync.Map // map[string]Var
  234. varKeysMu sync.RWMutex
  235. varKeys []string // sorted
  236. )
  237. // Publish declares a named exported variable. This should be called from a
  238. // package's init function when it creates its Vars. If the name is already
  239. // registered then this will log.Panic.
  240. func Publish(name string, v Var) {
  241. if _, dup := vars.LoadOrStore(name, v); dup {
  242. log.Panicln("Reuse of exported var name:", name)
  243. }
  244. varKeysMu.Lock()
  245. defer varKeysMu.Unlock()
  246. varKeys = append(varKeys, name)
  247. sort.Strings(varKeys)
  248. }
  249. // Get retrieves a named exported variable. It returns nil if the name has
  250. // not been registered.
  251. func Get(name string) Var {
  252. i, _ := vars.Load(name)
  253. v, _ := i.(Var)
  254. return v
  255. }
  256. // Convenience functions for creating new exported variables.
  257. func NewInt(name string) *Int {
  258. v := new(Int)
  259. Publish(name, v)
  260. return v
  261. }
  262. func NewFloat(name string) *Float {
  263. v := new(Float)
  264. Publish(name, v)
  265. return v
  266. }
  267. func NewMap(name string) *Map {
  268. v := new(Map).Init()
  269. Publish(name, v)
  270. return v
  271. }
  272. func NewString(name string) *String {
  273. v := new(String)
  274. Publish(name, v)
  275. return v
  276. }
  277. // Do calls f for each exported variable.
  278. // The global variable map is locked during the iteration,
  279. // but existing entries may be concurrently updated.
  280. func Do(f func(KeyValue)) {
  281. varKeysMu.RLock()
  282. defer varKeysMu.RUnlock()
  283. for _, k := range varKeys {
  284. val, _ := vars.Load(k)
  285. f(KeyValue{k, val.(Var)})
  286. }
  287. }
  288. func expvarHandler(w http.ResponseWriter, r *http.Request) {
  289. w.Header().Set("Content-Type", "application/json; charset=utf-8")
  290. fmt.Fprintf(w, "{\n")
  291. first := true
  292. Do(func(kv KeyValue) {
  293. if !first {
  294. fmt.Fprintf(w, ",\n")
  295. }
  296. first = false
  297. fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
  298. })
  299. fmt.Fprintf(w, "\n}\n")
  300. }
  301. // Handler returns the expvar HTTP Handler.
  302. //
  303. // This is only needed to install the handler in a non-standard location.
  304. func Handler() http.Handler {
  305. return http.HandlerFunc(expvarHandler)
  306. }
  307. func cmdline() any {
  308. return os.Args
  309. }
  310. func memstats() any {
  311. stats := new(runtime.MemStats)
  312. runtime.ReadMemStats(stats)
  313. return *stats
  314. }
  315. func init() {
  316. http.HandleFunc("/debug/vars", expvarHandler)
  317. Publish("cmdline", Func(cmdline))
  318. Publish("memstats", Func(memstats))
  319. }