Goブログ
HTTPトレーシングの紹介
はじめに
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
ラッパーを使用して現在のリクエストを識別します。
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への貴重な追加機能です。この新しい機能を有効にすることで、httpstatなどの、コミュニティからのHTTPデバッグ、ベンチマーク、視覚化ツールが見られることを期待しています。
次の記事:Goの7年間
前の記事:サブテストとサブベンチマークの使用
ブログインデックス