Go の net/http/httptrace を用いた HTTP リクエストの追跡

2026/05/29 1:46

Go の net/http/httptrace を用いた HTTP リクエストの追跡

RSS: https://news.ycombinator.com/rss

要約

日本語翻訳:

Go の標準ライブラリの

net/http
パッケージは、外部プロキシやサードパーティ製エージェントを必要とせずに、HTTP パフォーマンスのボトルネックを診断するための強力な内蔵ソリューションを提供します。
httptrace
パッケージ(Go 1.7 から利用可能)を活用することで、開発者は外出先リクエストの各ステージを観察するために特定のフックを付け加えることができ、DNS リゾリューションや接続取得から TLS ハンドシェイク、ボディ消費までを含みます。この機能は、
httptrace.WithClientTrace
を用いて
ClientTrace
構造体をリクエストコンテキストにリンクするか、またはトランスポート層を
TracingTransport
でラップすることで実現されます。
ClientTrace
はオプションの関数フィールドを持ち、未設定のフィールドは nil としてスキップされるため、新しいフックが追加された際にも後方互換性を保ち、複数の観測セットが無縫に連携することを可能にします。ボディ消費を含む正確な総実行時間の測定のためには、レスポンスボディを特殊な
timedBody
でラップします。これらの機能はコンテキストの伝播を介して既存のミドルウェアと自然に統合されるため、エンジニアはすぐに詳細なタイミング分解を示す
curl
ユーティリティに似た、自己完結型の Go プログラムを実装できます。このアプローチは外部依存関係の排除と、接続の再利用(
GotConnInfo.Reused
および
WasIdle
経由)に対する粒度の細かな可視性提供によってデバッグを簡素化し、APM エージェントやインストルメンテーションライブラリを必要とせずに、DNS 解決や TLS ハンドシェイクなど遅いコンポーネントをネイティブコードベース内で迅速に特定することを可能にします。

本文

Go の標準ライブラリ
net/http/httptrace
で HTTP リクエストの詳細をトレースする

2026 年 5 月 26 日公開

Go 1.7 に導入された標準ライブラリ

net/http/httptrace
は、トランスポートの外から HTTP リクエストの内部動作を詳細に観測できます。しかし、多くの Go 開発者がまだ利用していないのが現状です。


httptrace
が公開するフックポイント

このパッケージは、以下のようなネットワーク上の重要な瞬間におけるフックを提供します。

  • DNS の名前解決 (
    DNSStart
    ,
    DNSDone
    )
  • コネクションの取得 (
    ConnectStart
    ,
    ConnectDone
    )
  • TLS ハンドシェイク (
    TLSHandshakeStart
    ,
    TLSHandshakeDone
    )
  • ネットワーク上の転送開始 (
    GetConn
    )
  • 最初の応答バイト受信 (
    GotFirstResponseByte
    )

これらは、従来のログやメトリクスだけでは捉えることが困難な「搬送層の外」とからの観測を可能にします。


設計思想:なぜ
context
を使っているのか?

インターフェースではなく
*ClientTrace
コンテキストを採用した理由

直感的な設計(

Tracer
インターフェースをフィールドとして持つ)とは異なる、Go の標準ライブラリのアプローチには明確な利点があります。

  • ミドルウェアとの互換性: 追跡情報は
    context.Context
    に格納されるため、コンテキストを中継するあらゆるミドルウェアで自動的に動作します。追加のコストなしで実装が広がります。
  • 無状態設計: 共有可変状態が存在しないため、同じ
    http.Client
    で複数のリクエストを送信しても、それぞれ異なる追跡情報を安全に管理できます。
  • ゼロコストのオプション: リクエストに追跡を付与しないとトランスポートは無視するため、「未使用時のオーバーヘッド」はほぼありません

追跡対象とするのは任意のフィールド(関数)のみで構いません。設定されていないフィールドは

nil
としてスキップされます。

// クライアント作成サンプル
trace := &httptrace.ClientTrace{
    DNSStart: func(info httptrace.DNSStartInfo) {
        fmt.Printf("DNS start: %s\n", info.Host)
    },
    GotFirstResponseByte: func() {
        fmt.Println("First byte received")
    },
}

ctx := httptrace.WithClientTrace(context.Background(), trace)
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, "https://example.com", nil)

実装例:
curl --trace
に似た CLI ツール

URL を受け取り、各フックのタイミングを計測して出力するシンプルな CLI ツールを作成できます。これにより、DNS ルックアップや TLS ハンドシェイクなど、どこに時間がかかるかが一目でわかります。

タイミング計測構造体

type timings struct {
    start         time.Time
    dnsStart      time.Time
    dnsDone       time.Time
    connectStart  time.Time
    connectDone   time.Time
    tlsStart      time.Time
    tlsDone       time.Time
    gotConn       time.Time
    firstByte     time.Time
    done          time.Time
}

func (t *timings) elapsed(at time.Time) time.Duration {
    return at.Sub(t.start)
}

クライアントトレース作成

func newTrace(t *timings) *httptrace.ClientTrace {
    return &httptrace.ClientTrace{
        DNSStart: func(_ httptrace.DNSStartInfo) {
            t.dnsStart = time.Now()
        },
        DNSDone: func(_ httptrace.DNSDoneInfo) {
            t.dnsDone = time.Now()
        },
        ConnectStart: func(_, _ string) {
            t.connectStart = time.Now()
        },
        ConnectDone: func(_, _ string, _ error) {
            t.connectDone = time.Now()
        },
        TLSHandshakeStart: func() {
            t.tlsStart = time.Now()
        },
        TLSHandshakeDone: func(_ tls.ConnectionState, _ error) {
            t.tlsDone = time.Now()
        },
        GotConn: func(_ httptrace.GotConnInfo) {
            t.gotConn = time.Now()
        },
        GotFirstResponseByte: func() {
            t.firstByte = time.Now()
        },
    }
}

メイン処理と出力

func main() {
    url := os.Args[1]
    t := &timings{start: time.Now()}
    trace := newTrace(t)

    ctx := httptrace.WithClientTrace(context.Background(), trace)
    req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    res, err := http.DefaultClient.Do(req)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
    res.Body.Close()
    t.done = time.Now()

    // 分解表示出力
    fmt.Printf("DNS lookup:       %v\n", t.dnsDone.Sub(t.dnsStart))
    fmt.Printf("TCP connect:      %v\n", t.connectDone.Sub(t.connectStart))
    fmt.Printf("TLS handshake:    %v\n", t.tlsDone.Sub(t.tlsStart))
    fmt.Printf("Server processing: %v\n", t.firstByte.Sub(t.gotConn))
    fmt.Printf("Content transfer: %v\n", t.done.Sub(t.firstByte))
    fmt.Printf("Total:            %v\n", t.done.Sub(t.start))
}

特徴: 依存グラフ内の計測ライブラリも不要で、プロキシや APM エージェントなしでも動作します。

注意点:

  • DNSStart
    /
    DNSDone
    : ドメインが既にキャッシュされている場合はフックが発火しないことがあります。
  • TLSHandshake
    : HTTPS の場合のみ発火します。
  • GotConn
    : コネクションの再利用の有無は
    info.Reused
    フラグで確認可能。

実装例:すべてのリクエストを追跡する
RoundTripper

特定のクライアントを通じて自動追跡を行いたい場合は、

http.RoundTripper
をラップしてコンテキストに追跡情報を付与します。

トレース付きトランスポートの定義

type TracingTransport struct {
    Base http.RoundTripper
    Log  func(req *http.Request, t *timings)
}

func (tt *TracingTransport) RoundTrip(req *http.Request) (*http.Response, error) {
    base := tt.Base
    if base == nil {
        base = http.DefaultTransport
    }

    t := &timings{start: time.Now()}
    trace := newTrace(t)
    
    // コンテキストに追跡情報を追加(既存があれば上書きされます)
    req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))

    res, err := base.RoundTrip(req)
    t.done = time.Now()

    if tt.Log != nil {
        tt.Log(req, t)
    }

    return res, err
}

使用例

client := &http.Client{
    Transport: &TracingTransport{
        Log: func(req *http.Request, t *timings) {
            log.Printf("%s %s dns=%v tls=%v ttfb=%v total=%v",
                req.Method, req.URL,
                t.dnsDone.Sub(t.dnsStart),
                t.tlsDone.Sub(t.tlsStart),
                t.firstByte.Sub(t.gotConn),
                t.done.Sub(t.start),
            )
        },
    },
}

client.Get("https://example.com")

コンポジションの注意点: 呼び出し元がすでに

ClientTrace
を設定した場合、単純な置換ではなく統合されます。最後の追跡情報が優先されますが、両方のフックが発火する可能性があります。

ボディ転送時間の正確な計測

重要なのは、

t.done
が**「レスポンスボディを読み終えた時点」で測定されること**です。 現在の
RoundTrip
ではヘッダー読み取りまでしか計測されません。全体の転送時間を正しく測るには、ボディリーダーをラップしてクローズ時に時刻を取得する必要があります。

type timedBody struct {
    io.ReadCloser
    onClose func()
}

func (tb *timedBody) Close() error {
    tb.onClose()
    return tb.ReadCloser.Close()
}

// RoundTrip 内での使用例:
res.Body = &timedBody{
    ReadCloser: res.Body,
    onClose:    func() { t.done = time.Now() },
}

コネクションの再利用(プール)の確認

httptrace
は、クライアントがコネクションを適切に再利用しているかを確認する強力な手段を提供します。

GotConnInfo
構造体には以下のフィールドが含まれます:

  • Reused bool
    : コネクションが再利用されたかどうか
  • WasIdle bool
    : 無負荷状態にあったか
  • IdleTime time.Duration
    : 無負荷時間の長さ(再利用時のみ)
GotConn: func(info httptrace.GotConnInfo) {
    t.gotConn = time.Now()
    if info.Reused {
        log.Printf("connection reused (idle for %v)", info.IdleTime)
    } else {
        log.Printf("new connection to %s", info.Conn.RemoteAddr())
    },
},

トラブルシューティング:

  • 同一ホストへの反復呼び出しで常に
    Reused: false
    が出る場合、コードが意図せずコネクションプールを妨げている可能性があります(例:リクエストごとのクライアント作成、未クローズのボディなど)。

まとめ

net/http/httptrace
は以下の理由から非常に有用です。

  • 低いオーバーヘッド: 無効化可能なオプション設計であり、利用しない場合のコストはほぼゼロです。
  • コンテキストベースの設計:
    context.Context
    を介して動作するため、標準ライブラリの他のコンポーネントやミドルウェアとシームレスに連携します。
  • 手軽なデバッグツール: 外部エージェントを使わず、単一ファイルで HTTP 呼び出しのボトルネックを特定できます。

詳細な追跡情報が必要な場合、Limeleaf のような Web サイトや API 監視ツールを検討することをお勧めします。

同じ日のほかのニュース

一覧に戻る →

2026/06/02 1:31

最新のインスタグラムの「 exploits(バグ)」で最もユニークなのは私がこれまでに見た中で一番奇妙なものです。

## 日本語翻訳: 洗練されたセキュリティ上の不備により、ハッカーらは警報を触発することなく Instagram のアカウントを乗っ取り、@obamawhitehouse や @ocmssf のような高価値なユーザー名を対象に Meta の「Takeover Flow」を利用した。攻撃者は被害者のユーザー名を使用してプロセスを開始し、VPN または代理サーバーを介して請求をアカウントの報告された都市の近くから経路化することで、位置情報に基づくセキュリティを回避した。彼らは Meta の AI サポートチャットボットに連絡し、アカウントが侵害されたことをごりごしくれ、検証コードを受信するメールアドレスを任意で指定することを要求した。Instagram のシステムは、この要求されたメールアドレスが以前にそのアカウントと関連付けられていたかどうかを検証しなかった。AI がコードを送信すると、それはパスワードリセットリンクのトリガーとしての検証に使われ、完全な所有権が付与された。Meta のサポート AI はビデオでの自己撮影(生真面目)を身分証明として要求する可能性があるが、ターゲットのフィードから単純に AI でアニメーション化された公開写真は、このチェックを成功裡に回避した。回復フローは、そのリクエストを「本当の」所有者による完全なアカウントリセットとして扱い、2FA を完全に回避し、メール、テキスト、またはプッシュ通知を触発することなく進んだ。正当なユーザーのセッションは沈黙的に破棄され、連絡先情報が攻撃者の情報で置換されたため、標準的なチャネルでの回復は不可能になった。ブラックマーケットの Telegram グループが「アカウント乗っ取り」サービスを提供し始め、高価値なハンドルを利活用した。この脆弱性は数週間、あるいは数ヶ月間 Meta が修復するまで稼働していたと報告されており、その地下市場は一瞬で消え失せた。実験的な AI サポートグループに参加しているユーザーは、自動化されたアシスタンスを手動で無効化できないため、引き続き曝されている。この事象は、将来的な回復プロセスが人工知能や位置情報に基づく回避技術によって容易に操作されるのを防ぐためには、自動的なりすましおよびリモートスプーフィング攻撃に対するより強力な検証プロトコルの強化を強く示唆している。

2026/06/02 5:40

デバッグプロジェクト

## 日本語訳: Debug は、地球上で最も致命的な動物の一つである*Aedes aegypti*蚊の個体群を安全に抑制し、デング熱、ジカ熱、黄熱病、チクングニア熱といった致死性の疾患に対する革命的な対策を開拓しています。化学物質や遺伝子改変に依存する従来のアプローチとは異なり、当社の技術は自然存在する細菌*Wolbachia*を運ぶ雄性不稔の雌蚊を放出します。この生物は、これらの雄蚊が野生の雌蚊と繁殖することを妨げ、毒物を導入することなく個体群を自然に減少させます。吸血せず病気を媒介しない雄蚊であるため、「良い虫」としてこれを放出することは、立ち枯れた水の撤去や効果低下しつつ毒性が強まり過ぎる殺虫剤の使用といった陳腐な手法の持続可能な代替手段を提供します。現在、ほとんどの蚊媒感染症には効果的なワクチンがないことを考慮すると、この解決策は不可欠な新たなアプローチとなります。科学専門知識を国際パートナーと組み合わせ、Debug は地域コミュニティおよび政府との協力のもとで放出規模の拡大を目指しています。その最終的な影響は大きいです:刺す蚊の数を減らして病気の伝播率を下げ、安全でスケーラブルな生物学的制御戦略を通じて数百万人の人々がより長く健康な生活を送るのを支援します。 ## 元テキスト: ## Summary: Debug is pioneering a revolutionary method to combat deadly diseases like dengue, Zika, yellow fever, and chikungunya by safely suppressing populations of *Aedes aegypti* mosquitoes, which are among the deadliest animals on Earth. Unlike traditional approaches relying on chemicals or genetic modification, their technology releases sterile male mosquitoes carrying the natural bacterium *Wolbachia*. This organism prevents these males from reproducing with wild female counterparts, naturally causing population decline without introducing toxins. Since male mosquitoes do not bite or spread disease, releasing these "good bugs" offers a sustainable alternative to outdated methods like clearing standing water and using pesticides that are losing efficacy or becoming too toxic. Given that most mosquito-borne illnesses currently lack effective vaccines, this solution provides a vital new approach. By leveraging scientific expertise alongside international partners, Debug aims to scale up releases in collaboration with local communities and governments. The ultimate impact is significant: reducing biting mosquitoes to lower disease transmission rates, thereby helping millions of people live longer, healthier lives through a safe and scalable biological control strategy.

2026/06/02 1:41

スタンフォード大学CS336コース用 AI エージェントガイドライン

## 日本語翻訳: 本ドキュメントは、スタンフォード大学の CS336 コースにおいて AI コーディングアシスタントが従う厳格な倫理的境界線を設定する:すなわち、これらは何らかのコードを書いたり課題を直接解決したりしてはならない。むしろ、これらのエージェントは、学生による学習体験を維持することを目的とした教学補助手段としてのみ機能すべきである。本コースが手動作業としての Python と PyTorch の実装に大きく依存し、かつ支援枠組みが限られていることを考慮すると、AI の主たる役割は、公式の講義資料とデバッグツールの活用を通じて背後にある理論を説明し、エッジケースにおけるロジックを検証し、学生を導くことにある。 ユーザーから直接の修正、TODO 節の完了、またはリポジトリへの編集といった要請を受けた場合、エージェントはその要求を拒否し、概念の説明や、shape アサーションやアブレーションなどの健全性チェックを提案することで方向転換しなければならない。この方針は、学生がトラン스포ーマー、最適化アルゴリズム、トレーニングループなど複雑なコンポーネントの習得という核心的学習目標を回避することを防止するものである。システムはこの方針を強制するためには、明確な質問を投げかけ、公式ドキュメントを参照し、単に「如何做るか」を届けるのではなく、技術的決定の背後にある「なぜか」を説明することで、デバッグと概念的理解を通じて真の能力を確保するよう求める。

Go の net/http/httptrace を用いた HTTP リクエストの追跡 | そっか~ニュース