The Go Programming Language

Source file src/pkg/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, simply link this package into your program:
    20	//	import _ "expvar"
    21	//
    22	package expvar
    23	
    24	import (
    25		"bytes"
    26		"fmt"
    27		"http"
    28		"json"
    29		"log"
    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.Mutex
    45	}
    46	
    47	func (v *Int) String() string { return strconv.Itoa64(v.i) }
    48	
    49	func (v *Int) Add(delta int64) {
    50		v.mu.Lock()
    51		defer v.mu.Unlock()
    52		v.i += delta
    53	}
    54	
    55	func (v *Int) Set(value int64) {
    56		v.mu.Lock()
    57		defer v.mu.Unlock()
    58		v.i = value
    59	}
    60	
    61	// Float is a 64-bit float variable that satisfies the Var interface.
    62	type Float struct {
    63		f  float64
    64		mu sync.Mutex
    65	}
    66	
    67	func (v *Float) String() string { return strconv.Ftoa64(v.f, 'g', -1) }
    68	
    69	// Add adds delta to v.
    70	func (v *Float) Add(delta float64) {
    71		v.mu.Lock()
    72		defer v.mu.Unlock()
    73		v.f += delta
    74	}
    75	
    76	// Set sets v to value.
    77	func (v *Float) Set(value float64) {
    78		v.mu.Lock()
    79		defer v.mu.Unlock()
    80		v.f = value
    81	}
    82	
    83	// Map is a string-to-Var map variable that satisfies the Var interface.
    84	type Map struct {
    85		m  map[string]Var
    86		mu sync.Mutex
    87	}
    88	
    89	// KeyValue represents a single entry in a Map.
    90	type KeyValue struct {
    91		Key   string
    92		Value Var
    93	}
    94	
    95	func (v *Map) String() string {
    96		v.mu.Lock()
    97		defer v.mu.Unlock()
    98		b := new(bytes.Buffer)
    99		fmt.Fprintf(b, "{")
   100		first := true
   101		for key, val := range v.m {
   102			if !first {
   103				fmt.Fprintf(b, ", ")
   104			}
   105			fmt.Fprintf(b, "\"%s\": %v", key, val.String())
   106			first = false
   107		}
   108		fmt.Fprintf(b, "}")
   109		return b.String()
   110	}
   111	
   112	func (v *Map) Init() *Map {
   113		v.m = make(map[string]Var)
   114		return v
   115	}
   116	
   117	func (v *Map) Get(key string) Var {
   118		v.mu.Lock()
   119		defer v.mu.Unlock()
   120		return v.m[key]
   121	}
   122	
   123	func (v *Map) Set(key string, av Var) {
   124		v.mu.Lock()
   125		defer v.mu.Unlock()
   126		v.m[key] = av
   127	}
   128	
   129	func (v *Map) Add(key string, delta int64) {
   130		v.mu.Lock()
   131		defer v.mu.Unlock()
   132		av, ok := v.m[key]
   133		if !ok {
   134			av = new(Int)
   135			v.m[key] = av
   136		}
   137	
   138		// Add to Int; ignore otherwise.
   139		if iv, ok := av.(*Int); ok {
   140			iv.Add(delta)
   141		}
   142	}
   143	
   144	// AddFloat adds delta to the *Float value stored under the given map key.
   145	func (v *Map) AddFloat(key string, delta float64) {
   146		v.mu.Lock()
   147		defer v.mu.Unlock()
   148		av, ok := v.m[key]
   149		if !ok {
   150			av = new(Float)
   151			v.m[key] = av
   152		}
   153	
   154		// Add to Float; ignore otherwise.
   155		if iv, ok := av.(*Float); ok {
   156			iv.Add(delta)
   157		}
   158	}
   159	
   160	// TODO(rsc): Make sure map access in separate thread is safe.
   161	func (v *Map) iterate(c chan<- KeyValue) {
   162		for k, v := range v.m {
   163			c <- KeyValue{k, v}
   164		}
   165		close(c)
   166	}
   167	
   168	func (v *Map) Iter() <-chan KeyValue {
   169		c := make(chan KeyValue)
   170		go v.iterate(c)
   171		return c
   172	}
   173	
   174	// String is a string variable, and satisfies the Var interface.
   175	type String struct {
   176		s string
   177	}
   178	
   179	func (v *String) String() string { return strconv.Quote(v.s) }
   180	
   181	func (v *String) Set(value string) { v.s = value }
   182	
   183	// Func implements Var by calling the function
   184	// and formatting the returned value using JSON.
   185	type Func func() interface{}
   186	
   187	func (f Func) String() string {
   188		v, _ := json.Marshal(f())
   189		return string(v)
   190	}
   191	
   192	// All published variables.
   193	var vars map[string]Var = make(map[string]Var)
   194	var mutex sync.Mutex
   195	
   196	// Publish declares an named exported variable. This should be called from a
   197	// package's init function when it creates its Vars. If the name is already
   198	// registered then this will log.Panic.
   199	func Publish(name string, v Var) {
   200		mutex.Lock()
   201		defer mutex.Unlock()
   202		if _, existing := vars[name]; existing {
   203			log.Panicln("Reuse of exported var name:", name)
   204		}
   205		vars[name] = v
   206	}
   207	
   208	// Get retrieves a named exported variable.
   209	func Get(name string) Var {
   210		return vars[name]
   211	}
   212	
   213	// RemoveAll removes all exported variables.
   214	// This is for tests; don't call this on a real server.
   215	func RemoveAll() {
   216		mutex.Lock()
   217		defer mutex.Unlock()
   218		vars = make(map[string]Var)
   219	}
   220	
   221	// Convenience functions for creating new exported variables.
   222	
   223	func NewInt(name string) *Int {
   224		v := new(Int)
   225		Publish(name, v)
   226		return v
   227	}
   228	
   229	func NewFloat(name string) *Float {
   230		v := new(Float)
   231		Publish(name, v)
   232		return v
   233	}
   234	
   235	func NewMap(name string) *Map {
   236		v := new(Map).Init()
   237		Publish(name, v)
   238		return v
   239	}
   240	
   241	func NewString(name string) *String {
   242		v := new(String)
   243		Publish(name, v)
   244		return v
   245	}
   246	
   247	// TODO(rsc): Make sure map access in separate thread is safe.
   248	func iterate(c chan<- KeyValue) {
   249		for k, v := range vars {
   250			c <- KeyValue{k, v}
   251		}
   252		close(c)
   253	}
   254	
   255	func Iter() <-chan KeyValue {
   256		c := make(chan KeyValue)
   257		go iterate(c)
   258		return c
   259	}
   260	
   261	func expvarHandler(w http.ResponseWriter, r *http.Request) {
   262		w.Header().Set("Content-Type", "application/json; charset=utf-8")
   263		fmt.Fprintf(w, "{\n")
   264		first := true
   265		for name, value := range vars {
   266			if !first {
   267				fmt.Fprintf(w, ",\n")
   268			}
   269			first = false
   270			fmt.Fprintf(w, "%q: %s", name, value)
   271		}
   272		fmt.Fprintf(w, "\n}\n")
   273	}
   274	
   275	func cmdline() interface{} {
   276		return os.Args
   277	}
   278	
   279	func memstats() interface{} {
   280		return runtime.MemStats
   281	}
   282	
   283	func init() {
   284		http.Handle("/debug/vars", http.HandlerFunc(expvarHandler))
   285		Publish("cmdline", Func(cmdline))
   286		Publish("memstats", Func(memstats))
   287	}

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.