Skip to content

Commit

Permalink
nsq*: log HTTP requests
Browse files Browse the repository at this point in the history
  • Loading branch information
mreiferson committed Jul 26, 2015
1 parent 9376ebc commit 8a9f047
Show file tree
Hide file tree
Showing 5 changed files with 297 additions and 222 deletions.
87 changes: 81 additions & 6 deletions internal/http_api/api_response.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@ package http_api
import (
"encoding/json"
"fmt"
"io"
"net/http"
"strconv"
"time"

"github.com/bitly/nsq/internal/app"
"github.com/julienschmidt/httprouter"
)

type Decorator func(APIHandler) APIHandler

type APIHandler func(http.ResponseWriter, *http.Request, httprouter.Params) (interface{}, error)

type Err struct {
Expand All @@ -28,8 +33,24 @@ func acceptVersion(req *http.Request) int {
return 0
}

func NegotiateVersion(f APIHandler) httprouter.Handle {
return func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
func PlainText(f APIHandler) APIHandler {
return func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) {
code := 200
data, err := f(w, req, ps)
if err != nil {
code = err.(Err).Code
data = err.Error()
}
response := data.(string)
w.Header().Set("Content-Length", strconv.Itoa(len(response)))
w.WriteHeader(code)
io.WriteString(w, response)
return nil, nil
}
}

func NegotiateVersion(f APIHandler) APIHandler {
return func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) {
data, err := f(w, req, ps)
if err != nil {
if acceptVersion(req) == 1 {
Expand All @@ -38,24 +59,26 @@ func NegotiateVersion(f APIHandler) httprouter.Handle {
// this handler always returns 500 for backwards compatibility
Respond(w, 500, err.Error(), nil)
}
return
return nil, nil
}
if acceptVersion(req) == 1 {
RespondV1(w, 200, data)
} else {
Respond(w, 200, "OK", data)
}
return nil, nil
}
}

func V1(f APIHandler) httprouter.Handle {
return func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
func V1(f APIHandler) APIHandler {
return func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) {
data, err := f(w, req, ps)
if err != nil {
RespondV1(w, err.(Err).Code, err)
return
return nil, nil
}
RespondV1(w, 200, data)
return nil, nil
}
}

Expand Down Expand Up @@ -125,3 +148,55 @@ func RespondV1(w http.ResponseWriter, code int, data interface{}) {
w.WriteHeader(code)
w.Write(response)
}

func Decorate(f APIHandler, ds ...Decorator) httprouter.Handle {
decorated := f
for _, decorate := range ds {
decorated = decorate(decorated)
}
return func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
decorated(w, req, ps)
}
}

func Log(l app.Logger) Decorator {
return func(f APIHandler) APIHandler {
return func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) {
start := time.Now()
response, err := f(w, req, ps)
elapsed := time.Since(start)
status := 200
if e, ok := err.(Err); ok {
status = e.Code
}
l.Output(2, fmt.Sprintf("%d %s %s (%s) %s",
status, req.Method, req.URL.RequestURI(), req.RemoteAddr, elapsed))
return response, err
}
}
}

func LogPanicHandler(l app.Logger) func(w http.ResponseWriter, req *http.Request, p interface{}) {
return func(w http.ResponseWriter, req *http.Request, p interface{}) {
l.Output(2, fmt.Sprintf("ERROR: panic in HTTP handler - %s", p))
Decorate(func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) {
return nil, Err{500, "INTERNAL_ERROR"}
}, Log(l), V1)(w, req, nil)
}
}

func LogNotFoundHandler(l app.Logger) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
Decorate(func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) {
return nil, Err{404, "NOT_FOUND"}
}, Log(l), V1)(w, req, nil)
})
}

func LogMethodNotAllowedHandler(l app.Logger) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
Decorate(func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) {
return nil, Err{405, "METHOD_NOT_ALLOWED"}
}, Log(l), V1)(w, req, nil)
})
}
Loading

0 comments on commit 8a9f047

Please sign in to comment.