ProbeHTTP
函数用于通过 HTTP 协议对指定的目标地址进行监控和探测。通过使用 Prometheus 指标进行性能度量,函数支持捕获请求的各类数据,如响应时间、状态码、重定向次数、SSL/TLS 信息等。
本文将逐步解析这段代码,帮助您理解它的各个部分以及它是如何工作的。
1. 函数签名与参数说明
func ProbeHTTP(ctx context.Context, target string, module config.Module, registry *prometheus.Registry, logger *slog.Logger) (success bool)
ctx
: 上下文对象,通常用于控制请求的取消、超时等。target
: 需要探测的目标地址(URL)。module
: 配置模块,包含了 HTTP 请求相关的设置。registry
: Prometheus 注册表,用于注册并记录监控指标。logger
: 日志记录器,用于输出日志信息。success
: 函数执行结果标志,表示是否成功探测。
2. 定义 Prometheus 指标
var redirects int
var (
durationGaugeVec = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: "probe_http_duration_seconds",
Help: "Duration of http request by phase, summed over all redirects",
}, []string{"phase"})
contentLengthGauge = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "probe_http_content_length",
Help: "Length of http content response",
})
// 其他指标定义
)
在函数开头,定义了多个 Prometheus 指标,记录 HTTP 请求的各项数据:
durationGaugeVec
: 记录请求各阶段的持续时间(例如解析、连接、TLS 握手等)。contentLengthGauge
: 记录响应体的大小。redirectsGauge
: 记录重定向次数。statusCodeGauge
: 记录 HTTP 响应状态码。- 其他一些用于记录 SSL/TLS 信息的指标。
3. URL 解析与目标主机获取
targetURL, err := url.Parse(target)
if err != nil {
logger.Error("Could not parse target URL", "err", err)
return false
}
- 使用
url.Parse
解析传入的目标地址target
。 - 如果解析失败,则记录错误并返回
false
。
4. DNS 解析
ip, lookupTime, err = chooseProtocol(ctx, module.HTTP.IPProtocol, module.HTTP.IPProtocolFallback, targetHost, registry, logger)
durationGaugeVec.WithLabelValues("resolve").Add(lookupTime)
- 如果配置未跳过 DNS 解析阶段,调用
chooseProtocol
函数进行目标主机的 IP 地址解析,并记录 DNS 解析时间。
5. HTTP 客户端配置
client, err := pconfig.NewClientFromConfig(httpClientConfig, "http_probe", pconfig.WithKeepAlivesDisabled())
if err != nil {
logger.Error("Error generating HTTP client", "err", err)
return false
}
- 使用
pconfig.NewClientFromConfig
从配置生成一个 HTTP 客户端,并禁用持久连接。 - 如果客户端创建失败,则记录错误并返回
false
。
6. HTTP 请求创建
request, err := http.NewRequest(httpConfig.Method, targetURL.String(), body)
if err != nil {
logger.Error("Error creating request", "err", err)
return false
}
- 根据配置的 HTTP 方法(如
GET
)创建一个新的 HTTP 请求对象。如果请求创建失败,则记录错误并返回false
。
7. 设置 HTTP 请求头
for key, value := range httpConfig.Headers {
request.Header.Set(key, value)
}
- 将配置中的 HTTP 头信息设置到请求对象中。
8. 发送请求并处理响应
resp, err := client.Do(request)
if resp == nil {
resp = &http.Response{}
if err != nil {
logger.Error("Error for HTTP request", "err", err)
}
} else {
// 处理响应
}
- 使用配置的 HTTP 客户端发送请求并获取响应。如果响应为空,则处理错误信息。
9. 检查响应状态码
if len(httpConfig.ValidStatusCodes) != 0 {
for _, code := range httpConfig.ValidStatusCodes {
if resp.StatusCode == code {
success = true
break
}
}
if !success {
logger.Info("Invalid HTTP response status code", "status_code", resp.StatusCode)
}
} else if 200 <= resp.StatusCode && resp.StatusCode < 300 {
success = true
}
- 如果配置了有效的状态码列表,则检查响应状态码是否符合要求。
- 如果没有配置有效状态码,则默认为 2xx 范围内的状态码视为成功。
10. 正则匹配响应头和响应体
if httpConfig.FailIfHeaderMatchesRegexp != nil {
success = matchRegularExpressionsOnHeaders(resp.Header, httpConfig, logger)
}
- 根据配置的正则表达式,匹配响应头部和响应体。如果匹配失败,则设置
success = false
。
11. 处理压缩和体积限制
if httpConfig.Compression != "" {
dec, err := getDecompressionReader(httpConfig.Compression, resp.Body)
if err != nil {
logger.Info("Failed to get decompressor for HTTP response body", "err", err)
success = false
}
}
- 如果配置了压缩方式,则尝试对响应体进行解压。
- 如果配置了体积限制,则通过
http.MaxBytesReader
限制读取的字节数。
12. 记录响应时间
for i, trace := range tt.traces {
// 记录各阶段的响应时间
durationGaugeVec.WithLabelValues("connect").Add(trace.connectDone.Sub(trace.dnsDone).Seconds())
}
- 记录请求各阶段的响应时间,包括 DNS 解析、连接、TLS 握手等。
13. SSL/TLS 处理
if resp.TLS != nil {
isSSLGauge.Set(float64(1))
}
- 如果响应中包含 SSL/TLS 信息,则记录 SSL/TLS 相关数据,如证书信息、TLS 版本、加密套件等。
14. 返回结果
return success
- 最终返回
success
,表示 HTTP 请求是否成功。
总结
ProbeHTTP
函数是一个功能强大的 HTTP 探测工具,能够提供丰富的监控指标。通过使用 Prometheus 注册和报告指标,它能够帮助监控 HTTP 服务的健康状况,包括请求的持续时间、响应码、SSL/TLS 状态等信息。
如果需要进一步定制或优化该函数,可以根据实际需求调整配置项或增强日志记录机制。