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