...
Run Format

Source file src/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		"math"
    30		"net/http"
    31		"os"
    32		"runtime"
    33		"sort"
    34		"strconv"
    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		mu   sync.RWMutex
   103		m    map[string]Var
   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		v.mu.RLock()
   115		defer v.mu.RUnlock()
   116		var b bytes.Buffer
   117		fmt.Fprintf(&b, "{")
   118		first := true
   119		v.doLocked(func(kv KeyValue) {
   120			if !first {
   121				fmt.Fprintf(&b, ", ")
   122			}
   123			fmt.Fprintf(&b, "%q: %v", kv.Key, kv.Value)
   124			first = false
   125		})
   126		fmt.Fprintf(&b, "}")
   127		return b.String()
   128	}
   129	
   130	func (v *Map) Init() *Map {
   131		v.m = make(map[string]Var)
   132		return v
   133	}
   134	
   135	// updateKeys updates the sorted list of keys in v.keys.
   136	// must be called with v.mu held.
   137	func (v *Map) updateKeys() {
   138		if len(v.m) == len(v.keys) {
   139			// No new key.
   140			return
   141		}
   142		v.keys = v.keys[:0]
   143		for k := range v.m {
   144			v.keys = append(v.keys, k)
   145		}
   146		sort.Strings(v.keys)
   147	}
   148	
   149	func (v *Map) Get(key string) Var {
   150		v.mu.RLock()
   151		defer v.mu.RUnlock()
   152		return v.m[key]
   153	}
   154	
   155	func (v *Map) Set(key string, av Var) {
   156		v.mu.Lock()
   157		defer v.mu.Unlock()
   158		v.m[key] = av
   159		v.updateKeys()
   160	}
   161	
   162	func (v *Map) Add(key string, delta int64) {
   163		v.mu.RLock()
   164		av, ok := v.m[key]
   165		v.mu.RUnlock()
   166		if !ok {
   167			// check again under the write lock
   168			v.mu.Lock()
   169			av, ok = v.m[key]
   170			if !ok {
   171				av = new(Int)
   172				v.m[key] = av
   173				v.updateKeys()
   174			}
   175			v.mu.Unlock()
   176		}
   177	
   178		// Add to Int; ignore otherwise.
   179		if iv, ok := av.(*Int); ok {
   180			iv.Add(delta)
   181		}
   182	}
   183	
   184	// AddFloat adds delta to the *Float value stored under the given map key.
   185	func (v *Map) AddFloat(key string, delta float64) {
   186		v.mu.RLock()
   187		av, ok := v.m[key]
   188		v.mu.RUnlock()
   189		if !ok {
   190			// check again under the write lock
   191			v.mu.Lock()
   192			av, ok = v.m[key]
   193			if !ok {
   194				av = new(Float)
   195				v.m[key] = av
   196				v.updateKeys()
   197			}
   198			v.mu.Unlock()
   199		}
   200	
   201		// Add to Float; ignore otherwise.
   202		if iv, ok := av.(*Float); ok {
   203			iv.Add(delta)
   204		}
   205	}
   206	
   207	// Do calls f for each entry in the map.
   208	// The map is locked during the iteration,
   209	// but existing entries may be concurrently updated.
   210	func (v *Map) Do(f func(KeyValue)) {
   211		v.mu.RLock()
   212		defer v.mu.RUnlock()
   213		v.doLocked(f)
   214	}
   215	
   216	// doLocked calls f for each entry in the map.
   217	// v.mu must be held for reads.
   218	func (v *Map) doLocked(f func(KeyValue)) {
   219		for _, k := range v.keys {
   220			f(KeyValue{k, v.m[k]})
   221		}
   222	}
   223	
   224	// String is a string variable, and satisfies the Var interface.
   225	type String struct {
   226		mu sync.RWMutex
   227		s  string
   228	}
   229	
   230	func (v *String) Value() string {
   231		v.mu.RLock()
   232		defer v.mu.RUnlock()
   233		return v.s
   234	}
   235	
   236	// String implements the Val interface. To get the unquoted string
   237	// use Value.
   238	func (v *String) String() string {
   239		v.mu.RLock()
   240		s := v.s
   241		v.mu.RUnlock()
   242		b, _ := json.Marshal(s)
   243		return string(b)
   244	}
   245	
   246	func (v *String) Set(value string) {
   247		v.mu.Lock()
   248		defer v.mu.Unlock()
   249		v.s = value
   250	}
   251	
   252	// Func implements Var by calling the function
   253	// and formatting the returned value using JSON.
   254	type Func func() interface{}
   255	
   256	func (f Func) Value() interface{} {
   257		return f()
   258	}
   259	
   260	func (f Func) String() string {
   261		v, _ := json.Marshal(f())
   262		return string(v)
   263	}
   264	
   265	// All published variables.
   266	var (
   267		mutex   sync.RWMutex
   268		vars    = make(map[string]Var)
   269		varKeys []string // sorted
   270	)
   271	
   272	// Publish declares a named exported variable. This should be called from a
   273	// package's init function when it creates its Vars. If the name is already
   274	// registered then this will log.Panic.
   275	func Publish(name string, v Var) {
   276		mutex.Lock()
   277		defer mutex.Unlock()
   278		if _, existing := vars[name]; existing {
   279			log.Panicln("Reuse of exported var name:", name)
   280		}
   281		vars[name] = v
   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		mutex.RLock()
   290		defer mutex.RUnlock()
   291		return vars[name]
   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		mutex.RLock()
   325		defer mutex.RUnlock()
   326		for _, k := range varKeys {
   327			f(KeyValue{k, vars[k]})
   328		}
   329	}
   330	
   331	func expvarHandler(w http.ResponseWriter, r *http.Request) {
   332		w.Header().Set("Content-Type", "application/json; charset=utf-8")
   333		fmt.Fprintf(w, "{\n")
   334		first := true
   335		Do(func(kv KeyValue) {
   336			if !first {
   337				fmt.Fprintf(w, ",\n")
   338			}
   339			first = false
   340			fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
   341		})
   342		fmt.Fprintf(w, "\n}\n")
   343	}
   344	
   345	// Handler returns the expvar HTTP Handler.
   346	//
   347	// This is only needed to install the handler in a non-standard location.
   348	func Handler() http.Handler {
   349		return http.HandlerFunc(expvarHandler)
   350	}
   351	
   352	func cmdline() interface{} {
   353		return os.Args
   354	}
   355	
   356	func memstats() interface{} {
   357		stats := new(runtime.MemStats)
   358		runtime.ReadMemStats(stats)
   359		return *stats
   360	}
   361	
   362	func init() {
   363		http.HandleFunc("/debug/vars", expvarHandler)
   364		Publish("cmdline", Func(cmdline))
   365		Publish("memstats", Func(memstats))
   366	}
   367	

View as plain text