From cea1e9d746c5013b6566fac3a06f817626fbcae1 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Wed, 30 Sep 2009 13:11:33 -0700 Subject: rename the public exvar package to be expvar. R=rsc DELTA=684 (324 added, 324 deleted, 36 changed) OCL=35161 CL=35163 --- src/pkg/Make.deps | 2 +- src/pkg/Makefile | 2 +- src/pkg/expvar/Makefile | 11 +++ src/pkg/expvar/expvar.go | 222 ++++++++++++++++++++++++++++++++++++++++++ src/pkg/expvar/expvar_test.go | 91 +++++++++++++++++ src/pkg/exvar/Makefile | 11 --- src/pkg/exvar/exvar.go | 222 ------------------------------------------ src/pkg/exvar/exvar_test.go | 91 ----------------- src/pkg/http/triv.go | 10 +- 9 files changed, 331 insertions(+), 331 deletions(-) create mode 100644 src/pkg/expvar/Makefile create mode 100644 src/pkg/expvar/expvar.go create mode 100644 src/pkg/expvar/expvar_test.go delete mode 100644 src/pkg/exvar/Makefile delete mode 100644 src/pkg/exvar/exvar.go delete mode 100644 src/pkg/exvar/exvar_test.go (limited to 'src') diff --git a/src/pkg/Make.deps b/src/pkg/Make.deps index 33631e668..1f85b2c39 100644 --- a/src/pkg/Make.deps +++ b/src/pkg/Make.deps @@ -26,7 +26,7 @@ debug/gosym.install: debug/binary.install fmt.install os.install strconv.install debug/proc.install: container/vector.install fmt.install io.install os.install runtime.install strconv.install strings.install sync.install syscall.install ebnf.install: container/vector.install go/scanner.install go/token.install os.install strconv.install unicode.install utf8.install exec.install: os.install strings.install -exvar.install: bytes.install fmt.install http.install log.install strconv.install sync.install +expvar.install: bytes.install fmt.install http.install log.install strconv.install sync.install flag.install: fmt.install os.install strconv.install fmt.install: io.install os.install reflect.install strconv.install utf8.install go/ast.install: go/token.install unicode.install utf8.install diff --git a/src/pkg/Makefile b/src/pkg/Makefile index ad2b7828d..6dd11f93e 100644 --- a/src/pkg/Makefile +++ b/src/pkg/Makefile @@ -40,7 +40,7 @@ DIRS=\ debug/proc\ ebnf\ exec\ - exvar\ + expvar\ flag\ fmt\ go/ast\ diff --git a/src/pkg/expvar/Makefile b/src/pkg/expvar/Makefile new file mode 100644 index 000000000..49e8de6d1 --- /dev/null +++ b/src/pkg/expvar/Makefile @@ -0,0 +1,11 @@ +# 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. + +include $(GOROOT)/src/Make.$(GOARCH) + +TARG=expvar +GOFILES=\ + expvar.go\ + +include $(GOROOT)/src/Make.pkg diff --git a/src/pkg/expvar/expvar.go b/src/pkg/expvar/expvar.go new file mode 100644 index 000000000..9d04a427c --- /dev/null +++ b/src/pkg/expvar/expvar.go @@ -0,0 +1,222 @@ +// 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. + +// The expvar package 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. +package expvar + +import ( + "bytes"; + "fmt"; + "http"; + "log"; + "strconv"; + "sync"; +) + +// Var is an abstract type for all exported variables. +type Var interface { + String() string; +} + +// Int is a 64-bit integer variable, and satisfies the Var interface. +type Int struct { + i int64; + mu sync.Mutex; +} + +func (v *Int) String() string { + return strconv.Itoa64(v.i) +} + +func (v *Int) Add(delta int64) { + v.mu.Lock(); + defer v.mu.Unlock(); + v.i += delta; +} + +// Map is a string-to-Var map variable, and satisfies the Var interface. +type Map struct { + m map[string] Var; + mu sync.Mutex; +} + +// KeyValue represents a single entry in a Map. +type KeyValue struct { + Key string; + Value Var; +} + +func (v *Map) String() string { + v.mu.Lock(); + defer v.mu.Unlock(); + b := new(bytes.Buffer); + fmt.Fprintf(b, "{"); + first := true; + for key, val := range v.m { + if !first { + fmt.Fprintf(b, ", "); + } + fmt.Fprintf(b, "\"%s\": %v", key, val.String()); + first = false; + } + fmt.Fprintf(b, "}"); + return b.String() +} + +func (v *Map) Init() *Map { + v.m = make(map[string] Var); + return v +} + +func (v *Map) Get(key string) Var { + v.mu.Lock(); + defer v.mu.Unlock(); + if av, ok := v.m[key]; ok { + return av + } + return nil +} + +func (v *Map) Set(key string, av Var) { + v.mu.Lock(); + defer v.mu.Unlock(); + v.m[key] = av; +} + +func (v *Map) Add(key string, delta int64) { + v.mu.Lock(); + defer v.mu.Unlock(); + av, ok := v.m[key]; + if !ok { + av = new(Int); + v.m[key] = av; + } + + // Add to Int; ignore otherwise. + if iv, ok := av.(*Int); ok { + iv.Add(delta); + } +} + +// TODO(rsc): Make sure map access in separate thread is safe. +func (v *Map) iterate(c chan<- KeyValue) { + for k, v := range v.m { + c <- KeyValue{ k, v }; + } + close(c); +} + +func (v *Map) Iter() <-chan KeyValue { + c := make(chan KeyValue); + go v.iterate(c); + return c +} + +// String is a string variable, and satisfies the Var interface. +type String struct { + s string; +} + +func (v *String) String() string { + return strconv.Quote(v.s) +} + +func (v *String) Set(value string) { + v.s = value; +} + +// IntFunc wraps a func() int64 to create a value that satisfies the Var interface. +// The function will be called each time the Var is evaluated. +type IntFunc func() int64; + +func (v IntFunc) String() string { + return strconv.Itoa64(v()) +} + + +// All published variables. +var vars map[string] Var = make(map[string] Var); +var mutex sync.Mutex; + +// Publish declares an 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.Crash. +func Publish(name string, v Var) { + mutex.Lock(); + defer mutex.Unlock(); + if _, existing := vars[name]; existing { + log.Crash("Reuse of exported var name:", name); + } + vars[name] = v; +} + +// Get retrieves a named exported variable. +func Get(name string) Var { + if v, ok := vars[name]; ok { + return v + } + return nil +} + +// RemoveAll removes all exported variables. +// This is for tests; don't call this on a real server. +func RemoveAll() { + mutex.Lock(); + defer mutex.Unlock(); + vars = make(map[string] Var); +} + +// Convenience functions for creating new exported variables. + +func NewInt(name string) *Int { + v := new(Int); + Publish(name, v); + return v +} + +func NewMap(name string) *Map { + v := new(Map).Init(); + Publish(name, v); + return v +} + +func NewString(name string) *String { + v := new(String); + Publish(name, v); + return v +} + +// TODO(rsc): Make sure map access in separate thread is safe. +func iterate(c chan<- KeyValue) { + for k, v := range vars { + c <- KeyValue{ k, v }; + } + close(c); +} + +func Iter() <-chan KeyValue { + c := make(chan KeyValue); + go iterate(c); + return c +} + +func expvarHandler(c *http.Conn, req *http.Request) { + c.SetHeader("content-type", "application/json; charset=utf-8"); + fmt.Fprintf(c, "{\n"); + first := true; + for name, value := range vars { + if !first { + fmt.Fprintf(c, ",\n"); + } + first = false; + fmt.Fprintf(c, " %q: %s", name, value); + } + fmt.Fprintf(c, "\n}\n"); +} + +func init() { + http.Handle("/debug/vars", http.HandlerFunc(expvarHandler)); +} diff --git a/src/pkg/expvar/expvar_test.go b/src/pkg/expvar/expvar_test.go new file mode 100644 index 000000000..1f3e3d686 --- /dev/null +++ b/src/pkg/expvar/expvar_test.go @@ -0,0 +1,91 @@ +// 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 + +import ( + "json"; + "testing"; +) + +func TestInt(t *testing.T) { + reqs := NewInt("requests"); + if reqs.i != 0 { + t.Errorf("reqs.i = %v, want 4", reqs.i) + } + if reqs != Get("requests").(*Int) { + t.Errorf("Get() failed.") + } + + reqs.Add(1); + reqs.Add(3); + if reqs.i != 4 { + t.Errorf("reqs.i = %v, want 4", reqs.i) + } + + if s := reqs.String(); s != "4" { + t.Errorf("reqs.String() = %q, want \"4\"", s); + } +} + +func TestString(t *testing.T) { + name := NewString("my-name"); + if name.s != "" { + t.Errorf("name.s = %q, want \"\"", name.s) + } + + name.Set("Mike"); + if name.s != "Mike" { + t.Errorf("name.s = %q, want \"Mike\"", name.s) + } + + if s := name.String(); s != "\"Mike\"" { + t.Errorf("reqs.String() = %q, want \"\"Mike\"\"", s); + } +} + +func TestMapCounter(t *testing.T) { + colours := NewMap("bike-shed-colours"); + + colours.Add("red", 1); + colours.Add("red", 2); + colours.Add("blue", 4); + if x := colours.m["red"].(*Int).i; x != 3 { + t.Errorf("colours.m[\"red\"] = %v, want 3", x) + } + if x := colours.m["blue"].(*Int).i; x != 4 { + t.Errorf("colours.m[\"blue\"] = %v, want 4", x) + } + + // colours.String() should be '{"red":3, "blue":4}', + // though the order of red and blue could vary. + s := colours.String(); + j, ok, errtok := json.StringToJson(s); + if !ok { + t.Errorf("colours.String() isn't valid JSON: %v", errtok) + } + if j.Kind() != json.MapKind { + t.Error("colours.String() didn't produce a map.") + } + red := j.Get("red"); + if red.Kind() != json.NumberKind { + t.Error("red.Kind() is not a NumberKind.") + } + if x := red.Number(); x != 3 { + t.Error("red = %v, want 3", x) + } +} + +func TestIntFunc(t *testing.T) { + x := int(4); + ix := IntFunc(func() int64 { return int64(x) }); + if s := ix.String(); s != "4" { + t.Errorf("ix.String() = %v, want 4", s); + } + + x++; + if s := ix.String(); s != "5" { + t.Errorf("ix.String() = %v, want 5", s); + } +} diff --git a/src/pkg/exvar/Makefile b/src/pkg/exvar/Makefile deleted file mode 100644 index 795e8a644..000000000 --- a/src/pkg/exvar/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# 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. - -include $(GOROOT)/src/Make.$(GOARCH) - -TARG=exvar -GOFILES=\ - exvar.go\ - -include $(GOROOT)/src/Make.pkg diff --git a/src/pkg/exvar/exvar.go b/src/pkg/exvar/exvar.go deleted file mode 100644 index 479154850..000000000 --- a/src/pkg/exvar/exvar.go +++ /dev/null @@ -1,222 +0,0 @@ -// 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. - -// The exvar package 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. -package exvar - -import ( - "bytes"; - "fmt"; - "http"; - "log"; - "strconv"; - "sync"; -) - -// Var is an abstract type for all exported variables. -type Var interface { - String() string; -} - -// Int is a 64-bit integer variable, and satisfies the Var interface. -type Int struct { - i int64; - mu sync.Mutex; -} - -func (v *Int) String() string { - return strconv.Itoa64(v.i) -} - -func (v *Int) Add(delta int64) { - v.mu.Lock(); - defer v.mu.Unlock(); - v.i += delta; -} - -// Map is a string-to-Var map variable, and satisfies the Var interface. -type Map struct { - m map[string] Var; - mu sync.Mutex; -} - -// KeyValue represents a single entry in a Map. -type KeyValue struct { - Key string; - Value Var; -} - -func (v *Map) String() string { - v.mu.Lock(); - defer v.mu.Unlock(); - b := new(bytes.Buffer); - fmt.Fprintf(b, "{"); - first := true; - for key, val := range v.m { - if !first { - fmt.Fprintf(b, ", "); - } - fmt.Fprintf(b, "\"%s\": %v", key, val.String()); - first = false; - } - fmt.Fprintf(b, "}"); - return b.String() -} - -func (v *Map) Init() *Map { - v.m = make(map[string] Var); - return v -} - -func (v *Map) Get(key string) Var { - v.mu.Lock(); - defer v.mu.Unlock(); - if av, ok := v.m[key]; ok { - return av - } - return nil -} - -func (v *Map) Set(key string, av Var) { - v.mu.Lock(); - defer v.mu.Unlock(); - v.m[key] = av; -} - -func (v *Map) Add(key string, delta int64) { - v.mu.Lock(); - defer v.mu.Unlock(); - av, ok := v.m[key]; - if !ok { - av = new(Int); - v.m[key] = av; - } - - // Add to Int; ignore otherwise. - if iv, ok := av.(*Int); ok { - iv.Add(delta); - } -} - -// TODO(rsc): Make sure map access in separate thread is safe. -func (v *Map) iterate(c chan<- KeyValue) { - for k, v := range v.m { - c <- KeyValue{ k, v }; - } - close(c); -} - -func (v *Map) Iter() <-chan KeyValue { - c := make(chan KeyValue); - go v.iterate(c); - return c -} - -// String is a string variable, and satisfies the Var interface. -type String struct { - s string; -} - -func (v *String) String() string { - return strconv.Quote(v.s) -} - -func (v *String) Set(value string) { - v.s = value; -} - -// IntFunc wraps a func() int64 to create a value that satisfies the Var interface. -// The function will be called each time the Var is evaluated. -type IntFunc func() int64; - -func (v IntFunc) String() string { - return strconv.Itoa64(v()) -} - - -// All published variables. -var vars map[string] Var = make(map[string] Var); -var mutex sync.Mutex; - -// Publish declares an 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.Crash. -func Publish(name string, v Var) { - mutex.Lock(); - defer mutex.Unlock(); - if _, existing := vars[name]; existing { - log.Crash("Reuse of exported var name:", name); - } - vars[name] = v; -} - -// Get retrieves a named exported variable. -func Get(name string) Var { - if v, ok := vars[name]; ok { - return v - } - return nil -} - -// RemoveAll removes all exported variables. -// This is for tests; don't call this on a real server. -func RemoveAll() { - mutex.Lock(); - defer mutex.Unlock(); - vars = make(map[string] Var); -} - -// Convenience functions for creating new exported variables. - -func NewInt(name string) *Int { - v := new(Int); - Publish(name, v); - return v -} - -func NewMap(name string) *Map { - v := new(Map).Init(); - Publish(name, v); - return v -} - -func NewString(name string) *String { - v := new(String); - Publish(name, v); - return v -} - -// TODO(rsc): Make sure map access in separate thread is safe. -func iterate(c chan<- KeyValue) { - for k, v := range vars { - c <- KeyValue{ k, v }; - } - close(c); -} - -func Iter() <-chan KeyValue { - c := make(chan KeyValue); - go iterate(c); - return c -} - -func exvarHandler(c *http.Conn, req *http.Request) { - c.SetHeader("content-type", "application/json; charset=utf-8"); - fmt.Fprintf(c, "{\n"); - first := true; - for name, value := range vars { - if !first { - fmt.Fprintf(c, ",\n"); - } - first = false; - fmt.Fprintf(c, " %q: %s", name, value); - } - fmt.Fprintf(c, "\n}\n"); -} - -func init() { - http.Handle("/debug/vars", http.HandlerFunc(exvarHandler)); -} diff --git a/src/pkg/exvar/exvar_test.go b/src/pkg/exvar/exvar_test.go deleted file mode 100644 index eddbbf9e2..000000000 --- a/src/pkg/exvar/exvar_test.go +++ /dev/null @@ -1,91 +0,0 @@ -// 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 exvar - -import ( - "json"; - "testing"; -) - -func TestInt(t *testing.T) { - reqs := NewInt("requests"); - if reqs.i != 0 { - t.Errorf("reqs.i = %v, want 4", reqs.i) - } - if reqs != Get("requests").(*Int) { - t.Errorf("Get() failed.") - } - - reqs.Add(1); - reqs.Add(3); - if reqs.i != 4 { - t.Errorf("reqs.i = %v, want 4", reqs.i) - } - - if s := reqs.String(); s != "4" { - t.Errorf("reqs.String() = %q, want \"4\"", s); - } -} - -func TestString(t *testing.T) { - name := NewString("my-name"); - if name.s != "" { - t.Errorf("name.s = %q, want \"\"", name.s) - } - - name.Set("Mike"); - if name.s != "Mike" { - t.Errorf("name.s = %q, want \"Mike\"", name.s) - } - - if s := name.String(); s != "\"Mike\"" { - t.Errorf("reqs.String() = %q, want \"\"Mike\"\"", s); - } -} - -func TestMapCounter(t *testing.T) { - colours := NewMap("bike-shed-colours"); - - colours.Add("red", 1); - colours.Add("red", 2); - colours.Add("blue", 4); - if x := colours.m["red"].(*Int).i; x != 3 { - t.Errorf("colours.m[\"red\"] = %v, want 3", x) - } - if x := colours.m["blue"].(*Int).i; x != 4 { - t.Errorf("colours.m[\"blue\"] = %v, want 4", x) - } - - // colours.String() should be '{"red":3, "blue":4}', - // though the order of red and blue could vary. - s := colours.String(); - j, ok, errtok := json.StringToJson(s); - if !ok { - t.Errorf("colours.String() isn't valid JSON: %v", errtok) - } - if j.Kind() != json.MapKind { - t.Error("colours.String() didn't produce a map.") - } - red := j.Get("red"); - if red.Kind() != json.NumberKind { - t.Error("red.Kind() is not a NumberKind.") - } - if x := red.Number(); x != 3 { - t.Error("red = %v, want 3", x) - } -} - -func TestIntFunc(t *testing.T) { - x := int(4); - ix := IntFunc(func() int64 { return int64(x) }); - if s := ix.String(); s != "4" { - t.Errorf("ix.String() = %v, want 4", s); - } - - x++; - if s := ix.String(); s != "5" { - t.Errorf("ix.String() = %v, want 5", s); - } -} diff --git a/src/pkg/http/triv.go b/src/pkg/http/triv.go index 900dcbb5b..0c74aed12 100644 --- a/src/pkg/http/triv.go +++ b/src/pkg/http/triv.go @@ -7,7 +7,7 @@ package main import ( "bytes"; "bufio"; - "exvar"; + "expvar"; "flag"; "fmt"; "io"; @@ -19,7 +19,7 @@ import ( // hello world, the web server -var helloRequests = exvar.NewInt("hello-requests"); +var helloRequests = expvar.NewInt("hello-requests"); func HelloServer(c *http.Conn, req *http.Request) { helloRequests.Add(1); io.WriteString(c, "hello, world!\n"); @@ -30,7 +30,7 @@ type Counter struct { n int; } -// This makes Counter satisfy the exvar.Var interface, so we can export +// This makes Counter satisfy the expvar.Var interface, so we can export // it directly. func (ctr *Counter) String() string { return fmt.Sprintf("%d", ctr.n) @@ -56,7 +56,7 @@ func (ctr *Counter) ServeHTTP(c *http.Conn, req *http.Request) { // simple file server var webroot = flag.String("root", "/home/rsc", "web root directory") -var pathVar = exvar.NewMap("file-requests"); +var pathVar = expvar.NewMap("file-requests"); func FileServer(c *http.Conn, req *http.Request) { c.SetHeader("content-type", "text/plain; charset=utf-8"); pathVar.Add(req.Url.Path, 1); @@ -143,7 +143,7 @@ func main() { // The counter is published as a variable directly. ctr := new(Counter); http.Handle("/counter", ctr); - exvar.Publish("counter", ctr); + expvar.Publish("counter", ctr); http.Handle("/go/", http.HandlerFunc(FileServer)); http.Handle("/flags", http.HandlerFunc(FlagServer)); -- cgit v1.2.3