bignum\
bufio\
exec\
+ exvar\
flag\
log\
malloc\
bignum\
bufio\
exec\
+ exvar\
flag\
log\
once\
bignum.6: fmt.dirinstall
bufio.6: io.dirinstall os.dirinstall
exec.6: os.dirinstall strings.install
+exvar.6: fmt.dirinstall sync.dirinstall
flag.6: fmt.dirinstall os.dirinstall strconv.dirinstall
log.6: fmt.dirinstall io.dirinstall os.dirinstall time.dirinstall
path.6: io.dirinstall
--- /dev/null
+// 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.
+package exvar
+
+import (
+ "fmt";
+ "sync";
+)
+
+// Global state.
+var (
+ mutex sync.Mutex;
+ intVars = make(map[string] int);
+ mapVars = make(map[string] map[string] int);
+ // TODO(dsymonds):
+ // - string-valued vars
+ // - docstrings
+ // - dynamic lookup vars (via chan)
+)
+
+// Increment adds inc to the var called name.
+func Increment(name string, inc int) {
+ mutex.Lock();
+ defer mutex.Unlock();
+
+ if x, ok := intVars[name]; ok {
+ intVars[name] += inc
+ } else {
+ intVars[name] = inc
+ }
+}
+
+// Set sets the var called name to value.
+func Set(name string, value int) {
+ intVars[name] = value
+}
+
+// Get retrieves an integer-valued var called name.
+func Get(name string) (x int, ok bool) {
+ x, ok = intVars[name];
+ return
+}
+
+// TODO(dsymonds): Functions for map-valued vars.
+
+// String produces a string of all the vars in textual format.
+func String() string {
+ mutex.Lock();
+ defer mutex.Unlock();
+
+ s := "";
+ for name, value := range intVars {
+ s += fmt.Sprintln(name, value)
+ }
+ return s
+}
--- /dev/null
+// 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 (
+ "exvar";
+ "fmt";
+ "testing";
+)
+
+func TestSimpleCounter(t *testing.T) {
+ // Unknown exvar should be zero, and return !ok.
+ x, ok := Get("requests");
+ if x != 0 || ok {
+ t.Errorf("Get(nonexistent) = (%v, %v), want (%v, %v)",
+ x, ok, 0, false)
+ }
+
+ Increment("requests", 1);
+ Increment("requests", 3);
+ x, ok = Get("requests");
+ if x != 4 || !ok {
+ t.Errorf("Get('requests') = (%v, %v), want (%v, %v)",
+ x, ok, 4, true)
+ }
+
+ out := String();
+ if out != "requests 4\n" {
+ t.Errorf("String() = \"%v\", want \"requests 4\n\"",
+ out);
+ }
+}
+
+func hammer(name string, total int, done chan <- int) {
+ for i := 0; i < total; i++ {
+ Increment(name, 1)
+ }
+ done <- 1
+}
+
+func TestHammer(t *testing.T) {
+ Set("hammer-times", 0);
+ sync := make(chan int);
+ hammer_times := int(1e5);
+ go hammer("hammer-times", hammer_times, sync);
+ go hammer("hammer-times", hammer_times, sync);
+ <-sync;
+ <-sync;
+ if final, ok := Get("hammer-times"); final != 2 * hammer_times {
+ t.Errorf("hammer-times = %v, want %v", final, 2 * hammer_times)
+ }
+}
import (
"bufio";
+ "exvar";
"flag";
"fmt";
"http";
// hello world, the web server
func HelloServer(c *http.Conn, req *http.Request) {
+ exvar.Increment("hello-requests", 1);
io.WriteString(c, "hello, world!\n");
}
+// Handler for /exvar requests.
+func ExvarServer(c *http.Conn, req *http.Request) {
+ c.SetHeader("content-type", "text/plain; charset=utf-8");
+ io.WriteString(c, exvar.String());
+}
+
// simple counter server
type Counter struct {
n int;
}
func (ctr *Counter) ServeHTTP(c *http.Conn, req *http.Request) {
+ exvar.Increment("counter-requests", 1);
fmt.Fprintf(c, "counter = %d\n", ctr.n);
ctr.n++;
}
http.Handle("/args", http.HandlerFunc(ArgServer));
http.Handle("/go/hello", http.HandlerFunc(HelloServer));
http.Handle("/chan", ChanCreate());
+ http.Handle("/exvar", http.HandlerFunc(ExvarServer));
err := http.ListenAndServe(":12345", nil);
if err != nil {
panic("ListenAndServe: ", err.String())