Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Golang http handler - time taken for request

Tags:

go

I am trying to set a timer to count how much time is needed for my server to finish a request and I want the timer to stop after the last byte of the response is sent.

I found that the http server will only send the response after the handler function returns.

Is there any way to add a callback after the response is sent ?

Or is there a better way to count the time taken from the first byte of the request coming in till the last byte byte of the response is sent ?

like image 707
Artorias Avatar asked Nov 15 '16 04:11

Artorias


People also ask

What is HTTP handler Golang?

Go handlers can be any struct that has a method named ServeHTTP with two parameters: an HTTPResponseWriter interface and a pointer to a Request struct. Handler functions are functions that behave like handlers. Handler functions have the same signature as the ServeHTTP method and are used to process requests.

How do I send HTTP POST request in Golang?

Using the "net/http" package, we can make a HTTP POST request. During this post request, we can send JSON data in binary format using the "json" package. The following code shows how we can make the create user request on server "reqres.in", by sending the USER JSON object.

What is Servemux in Golang?

Whereas a servemux (also known as a router) stores a mapping between the predefined URL paths for your application and the corresponding handlers. Usually you have one servemux for your application containing all your routes. Go's net/http package ships with the simple but effective http.

Why Go HTTP request is a pointer?

The reason why it's a pointer to Request is simple: changes to Request by the handler need to be visible to the server, so we're only passing it by reference instead of by value.


1 Answers

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.

like image 190
John S Perayil Avatar answered Nov 07 '22 05:11

John S Perayil