Commit b94e5131 authored by Marcelo E. Magallon's avatar Marcelo E. Magallon

Add expvar middleware

Right now it has a very simple configuration:

	expvar /debug/vars

It will return a JSON object with memory statistics and the command line
used to start caddy, which are the two expvars that expvar registers by
default.
parent b6e5a599
......@@ -62,6 +62,7 @@ var directiveOrder = []directive{
{"basicauth", setup.BasicAuth},
{"internal", setup.Internal},
{"pprof", setup.PProf},
{"expvar", setup.ExpVar},
{"proxy", setup.Proxy},
{"fastcgi", setup.FastCGI},
{"websocket", setup.WebSocket},
......
package setup
import (
_ "expvar"
"github.com/mholt/caddy/middleware"
"github.com/mholt/caddy/middleware/expvar"
)
// ExpVar configures a new ExpVar middleware instance.
func ExpVar(c *Controller) (middleware.Middleware, error) {
resource, err := expVarParse(c)
if err != nil {
return nil, err
}
expvar := expvar.ExpVar{Resource: resource}
return func(next middleware.Handler) middleware.Handler {
expvar.Next = next
return expvar
}, nil
}
func expVarParse(c *Controller) (expvar.Resource, error) {
var resource expvar.Resource
var err error
for c.Next() {
args := c.RemainingArgs()
switch len(args) {
case 1:
resource = expvar.Resource(args[0])
default:
return resource, c.ArgErr()
}
}
return resource, err
}
package setup
import (
"testing"
"github.com/mholt/caddy/middleware/expvar"
)
func TestExpvar(t *testing.T) {
c := NewTestController(`expvar /d/v`)
mid, err := ExpVar(c)
if err != nil {
t.Errorf("Expected no errors, got: %v", err)
}
if mid == nil {
t.Fatal("Expected middleware, was nil instead")
}
handler := mid(EmptyNext)
myHandler, ok := handler.(expvar.ExpVar)
if !ok {
t.Fatalf("Expected handler to be type ExpVar, got: %#v", handler)
}
if myHandler.Resource != "/d/v" {
t.Errorf("Expected /d/v as expvar resource")
}
if !SameNext(myHandler.Next, EmptyNext) {
t.Error("'Next' field of handler was not set properly")
}
}
package expvar
import (
"expvar"
"fmt"
"net/http"
"github.com/mholt/caddy/middleware"
)
// ExpVar is a simple struct to hold expvar's configuration
type ExpVar struct {
Next middleware.Handler
Resource Resource
}
// ServeHTTP handles requests to expvar's configured entry point with
// expvar, or passes all other requests up the chain.
func (e ExpVar) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
if middleware.Path(r.URL.Path).Matches(string(e.Resource)) {
expvarHandler(w, r)
return 0, nil
}
return e.Next.ServeHTTP(w, r)
}
// expvarHandler returns a JSON object will all the published variables.
//
// This is lifted straight from the expvar package.
func expvarHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
fmt.Fprintf(w, "{\n")
first := true
expvar.Do(func(kv expvar.KeyValue) {
if !first {
fmt.Fprintf(w, ",\n")
}
first = false
fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
})
fmt.Fprintf(w, "\n}\n")
}
// Resource contains the path to the expvar entry point
type Resource string
package expvar
import (
"fmt"
"net/http"
"net/http/httptest"
"testing"
"github.com/mholt/caddy/middleware"
)
func TestExpVar(t *testing.T) {
rw := ExpVar{
Next: middleware.HandlerFunc(contentHandler),
Resource: "/d/v",
}
tests := []struct {
from string
result int
}{
{"/d/v", 0},
{"/x/y", http.StatusOK},
}
for i, test := range tests {
req, err := http.NewRequest("GET", test.from, nil)
if err != nil {
t.Fatalf("Test %d: Could not create HTTP request %v", i, err)
}
rec := httptest.NewRecorder()
result, err := rw.ServeHTTP(rec, req)
if err != nil {
t.Fatalf("Test %d: Could not ServeHTTP %v", i, err)
}
if result != test.result {
t.Errorf("Test %d: Expected Header '%d' but was '%d'",
i, test.result, result)
}
}
}
func contentHandler(w http.ResponseWriter, r *http.Request) (int, error) {
fmt.Fprintf(w, r.URL.String())
return http.StatusOK, nil
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment