Go 部落格

介紹 HTTP 追蹤

Jaana Burcu Dogan
2016 年 10 月 4 日

簡介

在 Go 1.7 中,我們引入了 HTTP 追蹤,這是一種在 HTTP 用戶端要求生命週期中收集細部資訊的功能。HTTP 追蹤的支援功能是由 net/http/httptrace 套件提供。所收集的資訊可用於除錯延遲問題、服務監控及撰寫適應式系統等用途。

HTTP 活動

httptrace 套件提供許多掛勾,方便在 HTTP 行程期間收集各種活動的資訊。這些活動包括

  • 建立連線
  • 重複使用連線
  • DNS 查詢
  • 將要求寫入協定
  • 讀取回應

追蹤活動

你可以透過將包含掛勾函式的 *httptrace.ClientTrace 放入要求的 context.Context 中,啟用 HTTP 追蹤。各種 http.RoundTripper 實作會尋找上下文的 *httptrace.ClientTrace 並呼叫相關的掛勾函式,來報告內部事件。

追蹤範圍限於要求的上下文,而且使用者應在開始要求之前將 *httptrace.ClientTrace 放入要求的上下文中。

    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 追蹤

追蹤機制旨在追蹤單一 http.Transport.RoundTrip 生命週期中的事件。不過,客戶端可能藉由多次往返行程來完成 HTTP 請求。例如,在 URL 重新導向的情況下,客戶端會追蹤 HTTP 重新導向,並會呼叫已註冊的掛勾多次,進而執行多項請求。使用者有責任在 http.Client 層級識別此類事件。下方程式使用 http.RoundTripper wrapper 識別目前的請求。

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 請求。

如果您是自訂 http.RoundTripper 實作的作者,則可以透過檢查要求內容中是否有 *httptest.ClientTrace 來支援追蹤,並在事件發生時呼叫相關的掛勾。

結論

HTTP 追蹤對於有興趣除錯 HTTP 請求延遲,以及撰寫用於除錯傳出流量的網路除錯工具的人來說,是 Go 的一個寶貴附加功能。藉由啟用這個新功能,我們希望看到來自社群的 HTTP 除錯、基準測試和視覺化工具,例如 httpstat

下一篇文章:Go 的七年
上一篇文章:使用子測試和子基準測試
部落格索引