Copyright 2009 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
Package expvar provides a standardized interface to public variables, such as operation counters in servers. It exposes these variables via HTTP at /debug/vars in JSON format. Operations to set or modify these public variables are atomic. In addition to adding the HTTP handler, this package registers the following variables: cmdline os.Args memstats runtime.Memstats The package is sometimes only imported for the side effect of registering its HTTP handler and the above variables. To use it this way, link this package into your program: import _ "expvar"
package expvar

import (
	
	
	
	
	
	
	
	
	
	
	
	
)
Var is an abstract type for all exported variables.
String returns a valid JSON value for the variable. Types with String methods that do not return valid JSON (such as time.Time) must not be used as a Var.
	String() string
}
Int is a 64-bit integer variable that satisfies the Var interface.
type Int struct {
	i int64
}

func ( *Int) () int64 {
	return atomic.LoadInt64(&.i)
}

func ( *Int) () string {
	return strconv.FormatInt(atomic.LoadInt64(&.i), 10)
}

func ( *Int) ( int64) {
	atomic.AddInt64(&.i, )
}

func ( *Int) ( int64) {
	atomic.StoreInt64(&.i, )
}
Float is a 64-bit float variable that satisfies the Var interface.
type Float struct {
	f uint64
}

func ( *Float) () float64 {
	return math.Float64frombits(atomic.LoadUint64(&.f))
}

func ( *Float) () string {
	return strconv.FormatFloat(
		math.Float64frombits(atomic.LoadUint64(&.f)), 'g', -1, 64)
}
Add adds delta to v.
func ( *Float) ( float64) {
	for {
		 := atomic.LoadUint64(&.f)
		 := math.Float64frombits()
		 :=  + 
		 := math.Float64bits()
		if atomic.CompareAndSwapUint64(&.f, , ) {
			return
		}
	}
}
Set sets v to value.
func ( *Float) ( float64) {
	atomic.StoreUint64(&.f, math.Float64bits())
}
Map is a string-to-Var map variable that satisfies the Var interface.
type Map struct {
	m      sync.Map // map[string]Var
	keysMu sync.RWMutex
	keys   []string // sorted
}
KeyValue represents a single entry in a Map.
type KeyValue struct {
	Key   string
	Value Var
}

func ( *Map) () string {
	var  strings.Builder
	fmt.Fprintf(&, "{")
	 := true
	.Do(func( KeyValue) {
		if ! {
			fmt.Fprintf(&, ", ")
		}
		fmt.Fprintf(&, "%q: %v", .Key, .Value)
		 = false
	})
	fmt.Fprintf(&, "}")
	return .String()
}
Init removes all keys from the map.
func ( *Map) () *Map {
	.keysMu.Lock()
	defer .keysMu.Unlock()
	.keys = .keys[:0]
	.m.Range(func(,  interface{}) bool {
		.m.Delete()
		return true
	})
	return 
}
addKey updates the sorted list of keys in v.keys.
func ( *Map) ( string) {
	.keysMu.Lock()
Using insertion sort to place key into the already-sorted v.keys.
	if  := sort.SearchStrings(.keys, );  >= len(.keys) {
		.keys = append(.keys, )
	} else if .keys[] !=  {
		.keys = append(.keys, "")
		copy(.keys[+1:], .keys[:])
		.keys[] = 
	}
}

func ( *Map) ( string) Var {
	,  := .m.Load()
	,  := .(Var)
	return 
}

Before we store the value, check to see whether the key is new. Try a Load before LoadOrStore: LoadOrStore causes the key interface to escape even on the Load path.
	if ,  := .m.Load(); ! {
		if ,  := .m.LoadOrStore(, ); ! {
			.addKey()
			return
		}
	}

	.m.Store(, )
}
Add adds delta to the *Int value stored under the given map key.
func ( *Map) ( string,  int64) {
	,  := .m.Load()
	if ! {
		var  bool
		,  = .m.LoadOrStore(, new(Int))
		if ! {
			.addKey()
		}
	}
Add to Int; ignore otherwise.
	if ,  := .(*Int);  {
		.Add()
	}
}
AddFloat adds delta to the *Float value stored under the given map key.
func ( *Map) ( string,  float64) {
	,  := .m.Load()
	if ! {
		var  bool
		,  = .m.LoadOrStore(, new(Float))
		if ! {
			.addKey()
		}
	}
Add to Float; ignore otherwise.
	if ,  := .(*Float);  {
		.Add()
	}
}
Delete deletes the given key from the map.
func ( *Map) ( string) {
	.keysMu.Lock()
	defer .keysMu.Unlock()
	 := sort.SearchStrings(.keys, )
	if  < len(.keys) &&  == .keys[] {
		.keys = append(.keys[:], .keys[+1:]...)
		.m.Delete()
	}
}
Do calls f for each entry in the map. The map is locked during the iteration, but existing entries may be concurrently updated.
func ( *Map) ( func(KeyValue)) {
	.keysMu.RLock()
	defer .keysMu.RUnlock()
	for ,  := range .keys {
		,  := .m.Load()
		(KeyValue{, .(Var)})
	}
}
String is a string variable, and satisfies the Var interface.
type String struct {
	s atomic.Value // string
}

func ( *String) () string {
	,  := .s.Load().(string)
	return 
}
String implements the Var interface. To get the unquoted string use Value.
func ( *String) () string {
	 := .Value()
	,  := json.Marshal()
	return string()
}

func ( *String) ( string) {
	.s.Store()
}
Func implements Var by calling the function and formatting the returned value using JSON.
type Func func() interface{}

func ( Func) () interface{} {
	return ()
}

func ( Func) () string {
	,  := json.Marshal(())
	return string()
}
All published variables.
var (
	vars      sync.Map // map[string]Var
	varKeysMu sync.RWMutex
	varKeys   []string // sorted
)
Publish declares a named exported variable. This should be called from a package's init function when it creates its Vars. If the name is already registered then this will log.Panic.
func ( string,  Var) {
	if ,  := vars.LoadOrStore(, );  {
		log.Panicln("Reuse of exported var name:", )
	}
	varKeysMu.Lock()
	defer varKeysMu.Unlock()
	varKeys = append(varKeys, )
	sort.Strings(varKeys)
}
Get retrieves a named exported variable. It returns nil if the name has not been registered.
func ( string) Var {
	,  := vars.Load()
	,  := .(Var)
	return 
}
Convenience functions for creating new exported variables.

func ( string) *Int {
	 := new(Int)
	Publish(, )
	return 
}

func ( string) *Float {
	 := new(Float)
	Publish(, )
	return 
}

func ( string) *Map {
	 := new(Map).Init()
	Publish(, )
	return 
}

func ( string) *String {
	 := new(String)
	Publish(, )
	return 
}
Do calls f for each exported variable. The global variable map is locked during the iteration, but existing entries may be concurrently updated.
func ( func(KeyValue)) {
	varKeysMu.RLock()
	defer varKeysMu.RUnlock()
	for ,  := range varKeys {
		,  := vars.Load()
		(KeyValue{, .(Var)})
	}
}

func ( http.ResponseWriter,  *http.Request) {
	.Header().Set("Content-Type", "application/json; charset=utf-8")
	fmt.Fprintf(, "{\n")
	 := true
	Do(func( KeyValue) {
		if ! {
			fmt.Fprintf(, ",\n")
		}
		 = false
		fmt.Fprintf(, "%q: %s", .Key, .Value)
	})
	fmt.Fprintf(, "\n}\n")
}
Handler returns the expvar HTTP Handler. This is only needed to install the handler in a non-standard location.
func () http.Handler {
	return http.HandlerFunc(expvarHandler)
}

func () interface{} {
	return os.Args
}

func () interface{} {
	 := new(runtime.MemStats)
	runtime.ReadMemStats()
	return *
}

func () {
	http.HandleFunc("/debug/vars", expvarHandler)
	Publish("cmdline", Func(cmdline))
	Publish("memstats", Func(memstats))