Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting TTFB (time to first byte) value in golang

Tags:

http

curl

go

I am trying to get value TTFB and Connect value

    c := exec.Command(
        "curl", "-w",
        "Connect: %{time_connect} TTFB: %{time_starttransfer} Total time: %{time_total}",
        "-o",
        "/dev/null",
        "http://my.domain/favicon.ico")

    cID, err := c.Run()
    fmt.Printf("%s", cID)

It prints a sting like

Connect: 0.205 TTFB: 0.353 Total time: 0.354

However, I need only the value of TTFB , Connect, Total time value in golang variable.

Also, Is there any way I can get the values without specifically using curl?

like image 644
Jagrati Avatar asked Jan 03 '18 12:01

Jagrati


People also ask

Why is TTFB waiting so long?

The most common culprit for high TTFB is dynamic content generation. This refers to the time it takes PHP and database queries to generate your webpages. The primary contributing factors to slow dynamic content generation are large files, excess or slow database queries, and autoload data.

What is a good time to first byte?

What is a Good TTFB? According to SearchEnginePeople and Google, your TTFB needs to be less than 200 milliseconds (ms). This number also differs by the type of content on your page. Static content should load at 100ms while dynamic content should load at a speed of 200 – 500ms.


1 Answers

There's builtin support for this since Go 1.7. Go 1.7 added HTTP Tracing, read blog post: Introducing HTTP Tracing

You can specify callback functions which get called at the appropriate phases / points when making an HTTP(S) request. You can specify your callback functions by creating a value of httptrace.ClientTrace, and "arm" it using httptrace.WithClientTrace().

Here's an example function which gets a URL param, and prints the timing of getting it:

func timeGet(url string) {
    req, _ := http.NewRequest("GET", url, nil)

    var start, connect, dns, tlsHandshake time.Time

    trace := &httptrace.ClientTrace{
        DNSStart: func(dsi httptrace.DNSStartInfo) { dns = time.Now() },
        DNSDone: func(ddi httptrace.DNSDoneInfo) {
            fmt.Printf("DNS Done: %v\n", time.Since(dns))
        },

        TLSHandshakeStart: func() { tlsHandshake = time.Now() },
        TLSHandshakeDone: func(cs tls.ConnectionState, err error) {
            fmt.Printf("TLS Handshake: %v\n", time.Since(tlsHandshake))
        },

        ConnectStart: func(network, addr string) { connect = time.Now() },
        ConnectDone: func(network, addr string, err error) {
            fmt.Printf("Connect time: %v\n", time.Since(connect))
        },

        GotFirstResponseByte: func() {
            fmt.Printf("Time from start to first byte: %v\n", time.Since(start))
        },
    }

    req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
    start = time.Now()
    if _, err := http.DefaultTransport.RoundTrip(req); err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Total time: %v\n", time.Since(start))
}

Example calling it:

timeGet("https://google.com")

Example output:

DNS Done: 7.998465ms
Connect time: 12.677085ms
TLS Handshake: 128.65394ms
Time from start to first byte: 176.461087ms
Total time: 176.723402ms

Also be sure to check out github.com/davecheney/httpstat which gives you a CLI utility that also uses the httptracing package under the hood.

like image 132
icza Avatar answered Sep 21 '22 12:09

icza