The easier but not as accurate way to do it would be using a middleware to wrap your handler function.
func timer(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
startTime := time.Now()
h.ServeHTTP(w, r)
duration := time.Now().Sub(startTime)
})
}
Then
http.Handle("/route",timer(yourHandler))
This is more accurately the time taken to process the request and form the response and not the time between writes.
If you absolutely need a more accurate duration then the parts of code you're looking to change reside in the net/http
package.
It would be around here.
The highlighted line go c.serve(ctx)
is where the the go routine for serving the request is spawned.
for {
rw, e := l.Accept()
if e != nil {
if ne, ok := e.(net.Error); ok && ne.Temporary() {
if tempDelay == 0 {
tempDelay = 5 * time.Millisecond
} else {
tempDelay *= 2
}
if max := 1 * time.Second; tempDelay > max {
tempDelay = max
}
srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)
time.Sleep(tempDelay)
continue
}
return e
}
tempDelay = 0
c := srv.newConn(rw)
c.setState(c.rwc, StateNew) // before Serve can return
go func(){
startTime := time.Now()
c.serve(ctx)
duration := time.Now().Sub(startTime)
}()
}
Note : The request actually gets written in the net.Conn
somewhere inside l.Accept()
but the highlighted point is the only place where we can have the approximate start time and end time within the same scope in the code.