Bu örnekte, HTTP istemci isteğiyle ilgili bilgi almak ve hata ayıklama amacıyla bulguları yazdırmak için httptrace kullanacağız. İzleme, DNS aramasından başlayacak ve yanıtı almak için sonuna kadar gidecektir. Sonunda sonucu JSON formatında yazdıracağız. HTTP istemcisi sorunlarında hata ayıklamak istiyorsanız bu iyi bir başlangıç olabilir.


Örnek


package main

import (
"crypto/tls"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net"
"net/http"
"net/http/httptrace"
"time"
)

type Debug struct {
DNS struct{
Start string `json:"start"`
End string `json:"end"`
Host string `json:"host"`
Address []net.IPAddr `json:"address"`
Error error `json:"error"`
} `json:"dns"`
Dial struct{
Start string `json:"start"`
End string `json:"end"`
} `json:"dial"`
Connection struct{
Time string `json:"time"`
} `json:"connection"`
WroteAllRequestHeaders struct{
Time string `json:"time"`
} `json:"wrote_all_request_header"`
WroteAllRequest struct{
Time string `json:"time"`
} `json:"wrote_all_request"`
FirstReceivedResponseByte struct{
Time string `json:"time"`
} `json:"first_received_response_byte"`
}

func main() {
// Create trace struct.
trace, debug := trace()

// Prepare request with trace attached to it.
req, err := http.NewRequest(http.MethodGet, "http://localhost:8090/server/api/v1/users", nil)
if err != nil {
log.Fatalln("request error", err)
}
req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))

// MAke a request.
res, err := client().Do(req)
if err != nil {
log.Fatalln("client error", err)
}
defer res.Body.Close()

// Read response.
body, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Fatal(err)
}

// Print report.
data, err := json.MarshalIndent(debug, "", " ")
fmt.Println(string(data))
fmt.Println(string(body))
}

func client() *http.Client {
return &http.Client{
Transport: transport(),
}
}

func transport() *http.Transport {
return &http.Transport{
DisableKeepAlives: true,
TLSClientConfig: tlsConfig(),
}
}

func tlsConfig() *tls.Config {
return &tls.Config{
InsecureSkipVerify: true,
}
}

func trace() (*httptrace.ClientTrace, *Debug) {
d := &Debug{}

t := &httptrace.ClientTrace{
DNSStart: func(info httptrace.DNSStartInfo) {
t := time.Now().UTC().String()
log.Println(t, "dns start")
d.DNS.Start = t
d.DNS.Host = info.Host
},
DNSDone: func(info httptrace.DNSDoneInfo) {
t := time.Now().UTC().String()
log.Println(t, "dns end")
d.DNS.End = t
d.DNS.Address = info.Addrs
d.DNS.Error = info.Err
},
ConnectStart: func(network, addr string) {
t := time.Now().UTC().String()
log.Println(t, "dial start")
d.Dial.Start = t
},
ConnectDone: func(network, addr string, err error) {
t := time.Now().UTC().String()
log.Println(t, "dial end")
d.Dial.End = t
},
GotConn: func(connInfo httptrace.GotConnInfo) {
t := time.Now().UTC().String()
log.Println(t, "conn time")
d.Connection.Time = t
},
WroteHeaders: func() {
t := time.Now().UTC().String()
log.Println(t, "wrote all request headers")
d.WroteAllRequestHeaders.Time = t
},
WroteRequest: func(wr httptrace.WroteRequestInfo) {
t := time.Now().UTC().String()
log.Println(t, "wrote all request")
d.WroteAllRequest.Time = t
},
GotFirstResponseByte: func() {
t := time.Now().UTC().String()
log.Println(t, "first received response byte")
d.FirstReceivedResponseByte.Time = t
},
}

return t, d
}

Test


2020/03/26 18:11:28 2020-03-26 18:11:28.699923 +0000 UTC dns start
2020/03/26 18:11:28 2020-03-26 18:11:28.703246 +0000 UTC dns end
2020/03/26 18:11:28 2020-03-26 18:11:28.703556 +0000 UTC dial start
2020/03/26 18:11:28 2020-03-26 18:11:28.704488 +0000 UTC dial end
2020/03/26 18:11:28 2020-03-26 18:11:28.705182 +0000 UTC conn time
2020/03/26 18:11:28 2020-03-26 18:11:28.705841 +0000 UTC wrote all request headers
2020/03/26 18:11:28 2020-03-26 18:11:28.705920 +0000 UTC wrote all request
2020/03/26 18:11:28 2020-03-26 18:11:28.707156 +0000 UTC first received response byte

{
"dns": {
"start": "2020-03-26 18:11:28.699923 +0000 UTC",
"end": "2020-03-26 18:11:28.703246 +0000 UTC",
"host": "localhost",
"address": [
{
"IP": "::1",
"Zone": ""
},
{
"IP": "127.0.0.1",
"Zone": ""
}
],
"error": null
},
"dial": {
"start": "2020-03-26 18:11:28.703556 +0000 UTC",
"end": "2020-03-26 18:11:28.704488 +0000 UTC"
},
"connection": {
"time": "2020-03-26 18:11:28.705182 +0000 UTC"
},
"wrote_all_request_header": {
"time": "2020-03-26 18:11:28.705841 +0000 UTC"
},
"wrote_all_request": {
"time": "2020-03-26 18:11:28.705920 +0000 UTC"
},
"first_received_response_byte": {
"time": "2020-03-26 18:11:28.707156 +0000 UTC"
}
}

real server responding: 2020-03-26 18:11:28.706893 +0000 UTC