github.com/yanyiwu/go@v0.0.0-20150106053140-03d6637dbb7f/src/expvar/expvar.go (about)

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