...

Source file src/expvar/expvar.go

Documentation: expvar

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

View as plain text