Go 部落格
引入 HTTP Tracing
簡介
在 Go 1.7 中,我們引入了 HTTP tracing,它是一種在 HTTP 客戶端請求的整個生命週期中收集細粒度資訊的機制。HTTP tracing 的支援由 net/http/httptrace
包提供。收集到的資訊可用於除錯延遲問題、服務監控、編寫自適應系統等。
HTTP 事件
httptrace
包提供了許多鉤子,用於在 HTTP 往返過程中收集有關各種事件的資訊。這些事件包括
- 連線建立
- 連線複用
- DNS 查詢
- 將請求寫入網路
- 讀取響應
Tracing 事件
您可以透過將包含鉤子函式的 *httptrace.ClientTrace
放入請求的 context.Context
中來啟用 HTTP tracing。各種 http.RoundTripper
實現透過查詢 context 中的 *httptrace.ClientTrace
並呼叫相關的鉤子函式來報告內部事件。
tracing 作用域限定在請求的 context 中,使用者應在發起請求之前將 *httptrace.ClientTrace
放入請求的 context 中。
req, _ := http.NewRequest("GET", "http://example.com", nil) trace := &httptrace.ClientTrace{ DNSDone: func(dnsInfo httptrace.DNSDoneInfo) { fmt.Printf("DNS Info: %+v\n", dnsInfo) }, GotConn: func(connInfo httptrace.GotConnInfo) { fmt.Printf("Got Conn: %+v\n", connInfo) }, } req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace)) if _, err := http.DefaultTransport.RoundTrip(req); err != nil { log.Fatal(err) }
在往返過程中,http.DefaultTransport
會在事件發生時呼叫每個鉤子。上面的程式會在 DNS 查詢完成後立即列印 DNS 資訊。類似地,當與請求的主機建立連線時,它會列印連線資訊。
使用 http.Client 進行 tracing
tracing 機制旨在追蹤單個 http.Transport.RoundTrip
生命週期中的事件。然而,客戶端可能需要進行多次往返才能完成一個 HTTP 請求。例如,在 URL 重定向的情況下,註冊的鉤子會隨著客戶端跟隨 HTTP 重定向而多次被呼叫,從而發起多個請求。使用者需要負責在 http.Client
級別識別此類事件。下面的程式透過使用 http.RoundTripper
包裝器來識別當前請求。
package main import ( "fmt" "log" "net/http" "net/http/httptrace" ) // transport is an http.RoundTripper that keeps track of the in-flight // request and implements hooks to report HTTP tracing events. type transport struct { current *http.Request } // RoundTrip wraps http.DefaultTransport.RoundTrip to keep track // of the current request. func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) { t.current = req return http.DefaultTransport.RoundTrip(req) } // GotConn prints whether the connection has been used previously // for the current request. func (t *transport) GotConn(info httptrace.GotConnInfo) { fmt.Printf("Connection reused for %v? %v\n", t.current.URL, info.Reused) } func main() { t := &transport{} req, _ := http.NewRequest("GET", "https://google.com", nil) trace := &httptrace.ClientTrace{ GotConn: t.GotConn, } req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace)) client := &http.Client{Transport: t} if _, err := client.Do(req); err != nil { log.Fatal(err) } }
程式將跟隨 google.com 重定向至 www.google.com 並輸出
Connection reused for https://google.com? false
Connection reused for https://www.google.com/? false
net/http
包中的 Transport 支援對 HTTP/1 和 HTTP/2 請求進行 tracing。
如果您是自定義 http.RoundTripper
實現的作者,您可以透過檢查請求 context 中的 *httptest.ClientTrace
並在事件發生時呼叫相關鉤子來支援 tracing。
結論
HTTP tracing 對於那些有興趣除錯 HTTP 請求延遲和編寫出站流量網路除錯工具的人來說是 Go 的一個寶貴補充。透過啟用此新功能,我們希望看到社群湧現出 HTTP 除錯、基準測試和視覺化工具,例如 httpstat。
下一篇文章:Go 的七年
上一篇文章:使用 Subtests 和 Sub-benchmarks
部落格索引