Go - Logging responses to incoming HTTP requests inside http.HandleFunc -
this follow-up question in go, how inspect http response written http.responsewriter? since solution there requires faking request, works great unit test not on live server.
i dump out http response web service returning in response requests receives users log file (or console). output should tell me headers , json payload.
how 1 go that?
if there httputil.dumpresponse equivalent takes http.responsewriter argument rather http.response perfect, can access header http.responsewriter
r = mux.newrouter() r.handlefunc("/path", func (w http.responsewriter, r *http.request) { fmt.printf("r.handlefunc /path\n") resp := server.newresponse() defer resp.close() r.parseform() // server work here // ... // insert debug code here, // // dump = http.dumpresponsefromwriter(w) // fmt.printf("%s\n", dump) }); http.handle("/path", r)
middleware chaining
a common solution problem called middleware chain. there several libraries provide functionality e.g. negroni.
it's form of continuation-passing style write middleware functions (taken negroni's readme):
func mymiddleware(rw http.responsewriter, r *http.request, next http.handlerfunc) { // stuff before next(rw, r) // stuff after }
and negroni gives http handler calls middlewares in right order.
we implement solution differently less magical , more functional (as in functional programming) approach. define handler combinators follows:
func newfoohandler(next http.handlerfunc) http.handlerfunc { return func(w http.responsewriter, r *http.request) { // stuff before next(r,w) // stuff after } }
then define chain combination:
h := newfoohandler(newbarhandler(newbazhandler(sink)))
now h
http.handlerfunc
foo, bar, baz. sink
empty last handler, nothing (to "finish" chain.)
applying solution problem
define handler combinator:
func newresponselogginghandler(next http.handlerfunc) http.handlerfunc { return func(w http.responsewriter, r *http.request) { // switch out response writer recorder // subsequent handlers c := httptest.newrecorder() next(c, r) // copy response recorder // actual response writer k, v := range c.headermap { w.header()[k] = v } w.writeheader(c.code) c.body.writeto(w) } }
now problem boils down handler management. you'll want handler applied chains in category. this, can use combinators again (this equivalent negroni's classic()
method):
func newdefaulthandler(next http.handlerfunc) http.handlerfunc { return newresponselogginghandler(newotherstuffhandler(next)) }
after this, whenever start chain this:
h := newdefaulthandler(...)
it automatically include response logging , default stuff defined in newdefaulthandler
.
Comments
Post a Comment