Golang httptrace 的示例
httptrace
包是从 Go1.7 开始包含在 Go (Golang) 标准库中的新包。 如果我们想要监控 http 请求的性能,或者如果我们想要收集和监控有关我们的 http 客户端的统计信息,该包将非常有用。 主要思想是能够跟踪在 http 请求的生命周期内发生的一组事件。 比如dns解析、tcp连接创建、写入tcp连接的数据、从tcp连接接收到的数据等等。
在这篇文章中,我们将了解如何使用 httptrace
包来监控我们的 Go (Golang) http 请求的性能。
1. 初始化 httptrace.ClientTrace
httptrace
包的主要导出类型是 ClientTrace
结构类型。 它用于定义我们要监听的事件。 这些事件被定义为函数,也称为“钩子”。 让我们来看看其中的一些。
这是 httptrace.ClientTrace
结构的精简版
ClientTrace
是一组钩子,可在传出 HTTP 请求的各个阶段运行。 任何特定的钩子都可以是 nil
type ClientTrace struct {
// GetConn is called before a connection is created or
// retrieved from an idle pool. The hostPort is the
// "host:port" of the target or proxy. GetConn is called even
// if there's already an idle cached connection available.
GetConn func(hostPort string)
// GotConn is called after a successful connection is
// obtained. There is no hook for failure to obtain a
// connection; instead, use the error from
// Transport.RoundTrip.
GotConn func(GotConnInfo)
[...]
// DNSStart is called when a DNS lookup begins.
DNSStart func(DNSStartInfo)
// DNSDone is called when a DNS lookup ends.
DNSDone func(DNSDoneInfo)
// ConnectStart is called when a new connection's Dial begins.
// If net.Dialer.DualStack (IPv6 "Happy Eyeballs") support is
// enabled, this may be called multiple times.
ConnectStart func(network, addr string)
// ConnectDone is called when a new connection's Dial
// completes. The provided err indicates whether the
// connection completedly successfully.
// If net.Dialer.DualStack ("Happy Eyeballs") support is
// enabled, this may be called multiple times.
ConnectDone func(network, addr string, err error)
[...]
}
我们在 ClientTrace
中看到的每个定义的函数都是我们在 Go 中创建和发送 http 请求时想要监听的事件。 让我们使用其中一些来跟踪我们的 http 请求示例中的事件。
package main
import (
"fmt"
"log"
"net/http"
"net/http/httptrace"
)
func main() {
req, _ := http.NewRequest(http.MethodGet, "http://example.com", nil)
clientTrace := &httptrace.ClientTrace{
GetConn: func(hostPort string) { fmt.Println("starting to create conn ", hostPort) },
DNSStart: func(info httptrace.DNSStartInfo) { fmt.Println("starting to look up dns", info) },
DNSDone: func(info httptrace.DNSDoneInfo) { fmt.Println("done looking up dns", info) },
ConnectStart: func(network, addr string) { fmt.Println("starting tcp connection", network, addr) },
ConnectDone: func(network, addr string, err error) { fmt.Println("tcp connection created", network, addr, err) },
GotConn: func(info httptrace.GotConnInfo) { fmt.Println("connection established", info) },
}
}
2. 使用 httptrace.WithClientTrace 创建上下文
为了使用我们的客户端跟踪指令(函数钩子),我们需要将结构附加到上下文中,该上下文稍后传递到请求上下文中并由 http 客户端使用。 我们可以使用 httptrace.WithClientTrace
函数来做到这一点
func WithClientTrace(ctx context.Context, trace *ClientTrace) context.Context
WithClientTrace
根据提供的父 ctx 返回一个新的上下文。 使用返回的上下文发出的 HTTP 客户端请求将使用提供的跟踪挂钩,以及之前使用 ctx 注册的任何挂钩。 将首先调用提供的跟踪中定义的任何挂钩。
这是我们需要添加到示例中的内容
clientTraceCtx := httptrace.WithClientTrace(req.Context(), clientTrace)
3. 将 httptrace.ClientTrace 与我们的 HTTP 客户端一起使用
我们的最终结果如下。 定义客户端跟踪钩子,使用客户端跟踪创建上下文并将其传递到我们的请求对象中。
package main
import (
"fmt"
"log"
"net/http"
"net/http/httptrace"
)
func main() {
req, _ := http.NewRequest(http.MethodGet, "http://example.com", nil)
clientTrace := &httptrace.ClientTrace{
GetConn: func(hostPort string) { fmt.Println("starting to create conn ", hostPort) },
DNSStart: func(info httptrace.DNSStartInfo) { fmt.Println("starting to look up dns", info) },
DNSDone: func(info httptrace.DNSDoneInfo) { fmt.Println("done looking up dns", info) },
ConnectStart: func(network, addr string) { fmt.Println("starting tcp connection", network, addr) },
ConnectDone: func(network, addr string, err error) { fmt.Println("tcp connection created", network, addr, err) },
GotConn: func(info httptrace.GotConnInfo) { fmt.Println("connection established", info) },
}
clientTraceCtx := httptrace.WithClientTrace(req.Context(), clientTrace)
req = req.WithContext(clientTraceCtx)
_, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
}
预期结果如下
starting to create conn example.com:80
starting to look up dns {example.com}
done looking up dns {[{93.184.216.34 } {2606:2800:220:1:248:1893:25c8:1946 }] false}
starting tcp connection tcp 93.184.216.34:80
tcp connection created tcp 93.184.216.34:80
connection established {0xc000010090 false false 0s}
这些只是我们可以用来在 Go 中跟踪传出 HTTP 请求的可能事件的一个子集。 但是正如我们从这个示例中看到的那样,这对于跟踪正在发生的事情和对我们的 http 客户端进行故障排除已经非常有用
相关文章
在 Golang 中使用 If-Else 和 Switch Loop Inside HTML 模板
发布时间:2023/04/27 浏览次数:65 分类:Go
-
本篇文章介绍了在 Golang 的 HTML 模板中使用 if-else 和 switch 循环。因此,只要输出是 HTML,就应该始终使用 HTML 模板包而不是文本模板。
Golang 中的零值 Nil
发布时间:2023/04/27 浏览次数:166 分类:Go
-
本篇文章介绍 nil 在 Golang 中的含义,nil 是 Go 编程语言中的零值,是众所周知且重要的预定义标识符。
Golang 中的 Lambda 表达式
发布时间:2023/04/27 浏览次数:93 分类:Go
-
本篇文章介绍如何在 Golang 中创建 lambda 表达式。Lambda 表达式似乎不存在于 Golang 中。 函数文字、lambda 函数或闭包是匿名函数的另一个名称。
在 Go 中使用断言
发布时间:2023/04/27 浏览次数:181 分类:Go
-
本篇文章介绍了 assert 在 GoLang 中的使用。在 Go 语言中使用断言:GoLang 不提供对断言的任何内置支持,但我们可以使用来自 Testify API 的广泛使用的第三方包断言。
Go 中的随机数生成
发布时间:2023/04/27 浏览次数:114 分类:Go
-
本篇文章介绍如何在 Go 语言中使用随机数生成功能。Go 中的随机数生成 Go 语言为随机数生成功能提供内置支持。 内置包 math 有方法 rand(),用于随机数生成。
在 Go 中使用 Electron API 创建 GUI
发布时间:2023/04/27 浏览次数:124 分类:Go
-
本篇文章介绍如何在 Go 语言中使用 Electron API 创建 GUI。Electron API 或 Astilectron 用于为 GoLang 创建 GUI。
在 GoLang 中安装包
发布时间:2023/04/27 浏览次数:122 分类:Go
-
使用 Go 语言的 get 命令安装所需的包非常容易。 Go 语言提供了多种命令来执行某些任务,get 就是其中之一。