Created
November 9, 2017 01:00
-
-
Save segfault88/7a876e3346aba7e6d2d72b54dd71db14 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"crypto/tls" | |
"encoding/csv" | |
"fmt" | |
"log" | |
"net/http" | |
"net/http/httptrace" | |
"os" | |
"os/signal" | |
"strconv" | |
"sync" | |
"time" | |
"github.com/davecgh/go-spew/spew" | |
) | |
type transport struct { | |
current *http.Request | |
} | |
func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) { | |
t.current = req | |
return http.DefaultTransport.RoundTrip(req) | |
} | |
func fromStart(start time.Time, end time.Time) string { | |
duration := float64(end.Sub(start).Nanoseconds()) / float64(time.Millisecond) | |
if duration <= 0 { | |
return "0.0" | |
} | |
return strconv.FormatFloat(duration, 'f', -1, 64) | |
} | |
func makeRequest(url string) []string { | |
t := &transport{} | |
req, err := http.NewRequest("GET", url, nil) | |
if err != nil { | |
log.Fatal(err) | |
} | |
start := time.Now() | |
var reused bool | |
var tDNSStart, | |
tDNSDone, | |
tFirstBytes, | |
tConnectStart, | |
tConnectDone, | |
tTLSStart, | |
tTLSDone, | |
tWroteHeaders, | |
tWroteRequest, | |
tDone time.Time | |
trace := &httptrace.ClientTrace{ | |
GotConn: func(info httptrace.GotConnInfo) { | |
reused = info.Reused | |
}, | |
DNSStart: func(_ httptrace.DNSStartInfo) { | |
tDNSStart = time.Now() | |
}, | |
DNSDone: func(_ httptrace.DNSDoneInfo) { | |
tDNSDone = time.Now() | |
}, | |
GotFirstResponseByte: func() { | |
tFirstBytes = time.Now() | |
}, | |
ConnectStart: func(_, _ string) { | |
tConnectStart = time.Now() | |
}, | |
ConnectDone: func(_, _ string, _ error) { | |
tConnectDone = time.Now() | |
}, | |
TLSHandshakeStart: func() { | |
tTLSStart = time.Now() | |
}, | |
TLSHandshakeDone: func(_ tls.ConnectionState, _ error) { | |
tTLSDone = time.Now() | |
}, | |
WroteHeaders: func() { | |
tWroteHeaders = time.Now() | |
}, | |
WroteRequest: func(_ httptrace.WroteRequestInfo) { | |
tWroteRequest = time.Now() | |
}, | |
} | |
req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace)) | |
req.Close = true | |
client := &http.Client{Transport: t} | |
d, err := client.Do(req) | |
if err != nil { | |
log.Fatal(err) | |
} | |
tDone = time.Now() | |
r := []string{ | |
start.String(), | |
url, | |
strconv.FormatBool(reused), | |
fromStart(start, tDNSStart), | |
fromStart(start, tDNSDone), | |
fromStart(start, tConnectStart), | |
fromStart(start, tConnectDone), | |
fromStart(start, tTLSStart), | |
fromStart(start, tTLSDone), | |
fromStart(start, tWroteHeaders), | |
fromStart(start, tWroteRequest), | |
fromStart(start, tFirstBytes), | |
fromStart(start, tDone), | |
d.Header["X-Amzn-Requestid"][0], | |
d.Header["X-Amz-Cf-Id"][0], | |
d.Header["Via"][0], | |
} | |
d.Body.Close() | |
return r | |
} | |
var lock = sync.Mutex{} | |
var wg = sync.WaitGroup{} | |
var columns = []string{ | |
"At", | |
"URL", | |
"Conn Reused", | |
"DNS Start", | |
"DNS Done", | |
"Connect Start", | |
"Connect Done", | |
"TLS Start", | |
"TLS Done", | |
"Wrote Headers", | |
"Wrote Request", | |
"First Response Byte", | |
"Done", | |
"X-Amzn-Requestid", | |
"X-Amz-Cf-Id", | |
"Via", | |
} | |
func monitor(writer *csv.Writer, shutdown chan bool, url string) { | |
i := 0 | |
c := time.Tick(30 * time.Second) | |
loop: | |
for { | |
i++ | |
result := makeRequest(url) | |
spew.Printf("Request # %d done to %s at %s\n", i, url, result[0]) | |
lock.Lock() | |
err := writer.Write(result) | |
if err != nil { | |
log.Fatal(err) | |
} | |
writer.Flush() | |
lock.Unlock() | |
select { | |
case <-shutdown: | |
break loop | |
case <-c: | |
continue loop | |
} | |
} | |
wg.Done() | |
} | |
func main() { | |
file, err := os.Create("result.csv") | |
if err != nil { | |
log.Fatal(err) | |
} | |
defer file.Close() | |
writer := csv.NewWriter(file) | |
defer writer.Flush() | |
writer.Write(columns) | |
urls := []string{"https://url/health"} | |
shutdown := make(chan bool) | |
for _, u := range urls { | |
wg.Add(1) | |
go monitor(writer, shutdown, u) | |
} | |
c := make(chan os.Signal, 1) | |
signal.Notify(c, os.Interrupt) | |
<-c | |
close(shutdown) | |
fmt.Printf("Waiting to finish.\n") | |
wg.Wait() | |
fmt.Printf("Done.\n") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment