Skip to content

Instantly share code, notes, and snippets.

@colm-mchugh
Last active August 29, 2015 14:09
Show Gist options
  • Save colm-mchugh/f1fffa88e68da2ac3121 to your computer and use it in GitHub Desktop.
Save colm-mchugh/f1fffa88e68da2ac3121 to your computer and use it in GitHub Desktop.
Expose gometrics using expvar
go get
go run expvar_demo.go
curl http://localhost:8080/hello?user=lassie
curl http://localhost:8080/hello?user=tom
curl http://localhost:8080/hello?user=IveAVeryLoooongName
curl http://localhost:8080/debug/vars # or open browser and go to http://localhost:8080/debug/vars
/*
You can access the exposed metrics via HTTP at /debug/vars, you'll get a JSON
object with your exposed variables and some pre defined system ones.
*/
package main
import (
"expvar"
"fmt"
"io"
"log"
"net/http"
"os"
"time"
"github.com/rcrowley/go-metrics"
)
// log:
var (
infoLog *log.Logger
)
func init() {
// Register the metrics we want to record - use the default registry of the metrics package
metrics.Register("request_count", metrics.NewCounter())
metrics.Register("request_overall_time", metrics.NewCounter())
metrics.Register("request_rate", metrics.NewMeter())
metrics.Register("response_size", metrics.NewHistogram(metrics.NewExpDecaySample(1028, 0.015)))
metrics.Register("request_time", metrics.NewTimer())
// Expose the metrics to expvars
publish_expvars(metrics.DefaultRegistry)
infoLog = log.New(os.Stdout, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile)
}
func now() interface{} {
return time.Now().Format(time.RFC3339Nano)
}
// record metrics; rs = size of the response, respTime = time taken to process request (nanosecs)
func updateMetrics(rs int, respTime time.Duration) {
// Update metrics
metrics.Get("request_count").(metrics.Counter).Inc(1)
metrics.Get("request_overall_time").(metrics.Counter).Inc(int64(respTime))
metrics.Get("request_rate").(metrics.Meter).Mark(1)
metrics.Get("response_size").(metrics.Histogram).Update(int64(rs))
metrics.Get("request_time").(metrics.Timer).Update(respTime)
}
// Service Implementation:
func HelloServer(w http.ResponseWriter, req *http.Request) {
reqStart := time.Now()
user := req.FormValue("user")
msg := fmt.Sprintf("Hello %s!!\n", user)
io.WriteString(w, msg)
updateMetrics(len(msg), time.Since(reqStart))
}
func HelloStats(w http.ResponseWriter, req *http.Request) {
http.Redirect(w, req, "/debug/vars", http.StatusFound)
}
// Service Set-Up:
func main() {
http.HandleFunc("/stats", HelloStats)
http.HandleFunc("/hello", HelloServer)
http.ListenAndServe(":8080", nil)
}
// publish_expvars: expose each metric in the given registry to expvars
func publish_expvars(r metrics.Registry) {
du := float64(time.Nanosecond)
percentiles := []float64{0.50, 0.75, 0.95, 0.99, 0.999}
r.Each(func(name string, i interface{}) {
switch m := i.(type) {
case metrics.Counter:
expvar.Publish(fmt.Sprintf("%s.Count", name), expvar.Func(func() interface{} {
return m.Count()
}))
case metrics.Meter:
expvar.Publish(fmt.Sprintf("%s.Rate1", name), expvar.Func(func() interface{} {
return m.Rate1()
}))
expvar.Publish(fmt.Sprintf("%s.Rate5", name), expvar.Func(func() interface{} {
return m.Rate5()
}))
expvar.Publish(fmt.Sprintf("%s.Rate15", name), expvar.Func(func() interface{} {
return m.Rate15()
}))
expvar.Publish(fmt.Sprintf("%s.Mean", name), expvar.Func(func() interface{} {
return m.RateMean()
}))
case metrics.Histogram:
expvar.Publish(fmt.Sprintf("%s.Count", name), expvar.Func(func() interface{} {
return m.Count()
}))
expvar.Publish(fmt.Sprintf("%s.Mean", name), expvar.Func(func() interface{} {
return m.Mean()
}))
expvar.Publish(fmt.Sprintf("%s.Min", name), expvar.Func(func() interface{} {
return m.Min()
}))
expvar.Publish(fmt.Sprintf("%s.Max", name), expvar.Func(func() interface{} {
return m.Max()
}))
expvar.Publish(fmt.Sprintf("%s.StdDev", name), expvar.Func(func() interface{} {
return m.StdDev()
}))
expvar.Publish(fmt.Sprintf("%s.Variance", name), expvar.Func(func() interface{} {
return m.Variance()
}))
for _, p := range percentiles {
expvar.Publish(fmt.Sprintf("%s.Percentile%2.3f", name, p), expvar.Func(func() interface{} {
return m.Percentile(p)
}))
}
case metrics.Timer:
expvar.Publish(fmt.Sprintf("%s.Rate1", name), expvar.Func(func() interface{} {
return m.Rate1()
}))
expvar.Publish(fmt.Sprintf("%s.Rate5", name), expvar.Func(func() interface{} {
return m.Rate5()
}))
expvar.Publish(fmt.Sprintf("%s.Rate15", name), expvar.Func(func() interface{} {
return m.Rate15()
}))
expvar.Publish(fmt.Sprintf("%s.RateMean", name), expvar.Func(func() interface{} {
return m.RateMean()
}))
expvar.Publish(fmt.Sprintf("%s.Mean", name), expvar.Func(func() interface{} {
return du * m.Mean()
}))
expvar.Publish(fmt.Sprintf("%s.Min", name), expvar.Func(func() interface{} {
return int64(du) * m.Min()
}))
expvar.Publish(fmt.Sprintf("%s.Max", name), expvar.Func(func() interface{} {
return int64(du) * m.Max()
}))
expvar.Publish(fmt.Sprintf("%s.StdDev", name), expvar.Func(func() interface{} {
return du * m.StdDev()
}))
expvar.Publish(fmt.Sprintf("%s.Variance", name), expvar.Func(func() interface{} {
return du * m.Variance()
}))
for _, p := range percentiles {
expvar.Publish(fmt.Sprintf("%s.Percentile%2.3f", name, p), expvar.Func(func() interface{} {
return m.Percentile(p)
}))
}
}
})
expvar.Publish("time", expvar.Func(now))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment