Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

httptrace底层链路追踪 #66

Open
dduo518 opened this issue Dec 12, 2022 · 0 comments
Open

httptrace底层链路追踪 #66

dduo518 opened this issue Dec 12, 2022 · 0 comments
Labels

Comments

@dduo518
Copy link
Owner

dduo518 commented Dec 12, 2022

httptrace

httptrace 包提供了对 HTTP 跟踪的支持。收集的信息可用于调试延迟问题、服务监控、编写自适应系统等。

http 事件

httptrace 包提供了许多挂钩,用于在 HTTP 往返期间收集有关各种事件的信息。这些事件包括:

  • Connection creation
  • Connection reuse
  • DNS lookups
  • Writing the request to the wire
  • Reading the response

链路追踪事件

http.RoundTripper 实现通过查找放入请求的context.Context上下文的*httptrace.ClientTrace来启用 HTTP 跟踪, 并调用相关的钩子函数来报告内部事件。跟踪的范围是请求的上下文,应该在开始请求之前将 *httptrace.ClientTrace 放入请求上下文。

示例

package main

import (
	"fmt"
	"log"
	"net/http"
	"net/http/httptrace"
)

func main() {
	t := &transport{}
	req, _ := http.NewRequest("GET", "https://www.google.com.hk", nil)
	trace := &httptrace.ClientTrace{
		GotConn:      t.GotConn,
		GetConn:      t.GetConn,
		ConnectStart: t.ConnectStart,
		ConnectDone:  t.ConnectDone,
	}
	req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
	client := &http.Client{Transport: t}
	if _, err := client.Do(req);err != nil {
		log.Fatal(err)
	}
}
type transport struct {
	current *http.Request
}
func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {
	t.current = req
	return http.DefaultTransport.RoundTrip(req)
}

func (t *transport) GotConn(info httptrace.GotConnInfo) {
	fmt.Printf("GotConn Connection reused for %v? %v\n", t.current.URL, info.Reused)
}

func (t *transport) GetConn(hostPort string) {
	fmt.Printf("GetConn connection hostPort: %v\n", hostPort)
}

func (t *transport) ConnectStart(network, addr string) {
	fmt.Printf("ConnectStart network %s | addr: %s \n", network, addr)
}
func (t *transport) ConnectDone(network, addr string, err error) {
	fmt.Printf("ConnectDone network %s | addr: %s\n", network, addr)
}

http实现

在http中的RoundTrip接口实现钩子函数的执行

func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (pc *persistConn, err error) {
	req := treq.Request
	trace := treq.trace
	ctx := req.Context()
	if trace != nil && trace.GetConn != nil {
		trace.GetConn(cm.addr())
	}
    // ...
    if w.pc != nil && w.pc.alt == nil && trace != nil && trace.GotConn != nil {
		trace.GotConn(httptrace.GotConnInfo{Conn: w.pc.conn, Reused: w.pc.isReused()})
	}
}

// 创建 tcp 连接
func (sd *sysDialer) dialSingle(ctx context.Context, ra Addr) (c Conn, err error) {
	trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace)
	if trace != nil {
		raStr := ra.String()
		if trace.ConnectStart != nil {
			trace.ConnectStart(sd.network, raStr)
		}
		if trace.ConnectDone != nil {
			defer func() { trace.ConnectDone(sd.network, raStr, err) }()
		}
	}
}

作用

对调试 HTTP请求延迟和编写出站流量网络调试工具来说,HTTP跟踪是 Go 的一个非常有用的包。

@dduo518 dduo518 added the golang label Dec 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant