【Blackbox Exporter】prober.Handler源码详细分析

打印 上一主题 下一主题

主题 841|帖子 841|积分 2523

  1.         http.HandleFunc(path.Join(*routePrefix, "/probe"), func(w http.ResponseWriter, r *http.Request) {
  2.                 sc.Lock()
  3.                 conf := sc.C
  4.                 sc.Unlock()
  5.                 prober.Handler(w, r, conf, logger, rh, *timeoutOffset, nil, moduleUnknownCounter, allowedLevel)
  6.         })
复制代码

我们了解到blackbox_exporter中都是通过哀求/probe来进行端口探测的,那么本日我们来详尽的分析prober.Handler相干源码。

  
函数签名

  1. func Handler(w http.ResponseWriter, r *http.Request, c *config.Config, logger *slog.Logger, rh *ResultHistory, timeoutOffset float64, params url.Values, moduleUnknownCounter prometheus.Counter, logLevelProber *promslog.AllowedLevel)
复制代码


  • w http.ResponseWriter:HTTP 响应对象,用于向客户端发送响应。
  • r *http.Request:HTTP 哀求对象,包含哀求信息。
  • c *config.Config:包含设置的对象,包含了可用的探针模块等设置。
  • logger *slog.Logger:日志记载器,用于输出日志。
  • rh *ResultHistory:用于记载效果汗青的对象。
  • timeoutOffset float64:超时偏移量,大概用于调整默认的超时设置。
  • params url.Values:URL 查询参数,通常包含了目的和其他探测信息。
  • moduleUnknownCounter prometheus.Counter:Prometheus 计数器,用于统计未知模块的次数。
  • logLevelProber *promslog.AllowedLevel:日志级别,控制探测日志的详细程度。
1. 获取 URL 查询参数 params

  1. if params == nil {
  2.     params = r.URL.Query()
  3. }
复制代码


  • 如果 params 参数为空(即传入的 URL 查询参数为空),则利用 HTTP 哀求的查询参数 r.URL.Query()。
2. 获取探针模块名称

  1. moduleName := params.Get("module")
  2. if moduleName == "" {
  3.     moduleName = "http_2xx"
  4. }
  5. module, ok := c.Modules[moduleName]
  6. if !ok {
  7.     http.Error(w, fmt.Sprintf("Unknown module %q", moduleName), http.StatusBadRequest)
  8.     logger.Debug("Unknown module", "module", moduleName)
  9.     if moduleUnknownCounter != nil {
  10.         moduleUnknownCounter.Add(1)
  11.     }
  12.     return
  13. }
复制代码


  • 获取 URL 查询参数中的 module 参数。如果没有传递 module 参数,默认设置为 http_2xx。
  • 通过 moduleName 从设置 c.Modules 中获取对应的模块设置。如果模块不存在,返回 HTTP 错误 400 BadRequest。
3. 解析超时设置

  1. timeoutSeconds, err := getTimeout(r, module, timeoutOffset)
  2. if err != nil {
  3.     http.Error(w, fmt.Sprintf("Failed to parse timeout from Prometheus header: %s", err), http.StatusInternalServerError)
  4.     return
  5. }
复制代码


  • 调用 getTimeout 函数从哀求头或模块设置中解析超时设置,超时偏移量会影响最终的超时值。
  • 如果解析超时出错,则返回 500 InternalServerError。
4. 创建上下文(Context)

  1. ctx, cancel := context.WithTimeout(r.Context(), time.Duration(timeoutSeconds*float64(time.Second)))
  2. defer cancel()
  3. r = r.WithContext(ctx)
复制代码


  • 利用 context.WithTimeout 创建一个带有超时设置的上下文 ctx,并将其与哀求 r 关联。超时会在 timeoutSeconds 秒后触发。
5. 创建 Prometheus 指标

  1. probeSuccessGauge := prometheus.NewGauge(prometheus.GaugeOpts{
  2.     Name: "probe_success",
  3.     Help: "Displays whether or not the probe was a success",
  4. })
  5. probeDurationGauge := prometheus.NewGauge(prometheus.GaugeOpts{
  6.     Name: "probe_duration_seconds",
  7.     Help: "Returns how long the probe took to complete in seconds",
  8. })
复制代码


  • 创建两个 Prometheus Gauge 范例的指标:

    • probe_success: 表示探测是否乐成(1:乐成,0:失败)。
    • probe_duration_seconds: 表示探测完成的时长(单位:秒)。

6. 获取目的(target)

  1. target := params.Get("target")
  2. if target == "" {
  3.     http.Error(w, "Target parameter is missing", http.StatusBadRequest)
  4.     return
  5. }
复制代码


  • 获取 URL 查询参数中的 target 参数,表示需要探测的目的地点。如果没有提供目的地点,则返回 400 BadRequest 错误。
7. 获取探针范例和处理

  1. prober, ok := Probers[module.Prober]
  2. if !ok {
  3.     http.Error(w, fmt.Sprintf("Unknown prober %q", module.Prober), http.StatusBadRequest)
  4.     return
  5. }
复制代码


  • 根据 module.Prober 获取对应的探针。如果探针范例不存在,则返回 400 BadRequest 错误。
8. 设置 hostname(针对 HTTP 或 TCP 探测)

  1. hostname := params.Get("hostname")
  2. if module.Prober == "http" && hostname != "" {
  3.     err = setHTTPHost(hostname, &module)
  4.     if err != nil {
  5.         http.Error(w, err.Error(), http.StatusBadRequest)
  6.         return
  7.     }
  8. }
  9. if module.Prober == "tcp" && hostname != "" {
  10.     if module.TCP.TLSConfig.ServerName == "" {
  11.         module.TCP.TLSConfig.ServerName = hostname
  12.     }
  13. }
复制代码


  • 如果是 http 探针并且 hostname 不为空,则调用 setHTTPHost 设置 HTTP 哀求的 Host 头。
  • 如果是 tcp 探针并且 hostname 不为空,则设置 TLS 设置中的 ServerName。
9. 设置日志级别

  1. if logLevelProber == nil {
  2.     logLevelProber = &promslog.AllowedLevel{}
  3. }
  4. if logLevelProber.String() == "" {
  5.     _ = logLevelProber.Set("info")
  6. }
  7. sl := newScrapeLogger(logger, moduleName, target, logLevelProber)
  8. slLogger := slog.New(sl)
复制代码


  • 如果没有提供 logLevelProber,则利用默认的日志级别 “info”。
  • 创建一个新的日志记载器 slLogger,用于记载探测过程中的信息。
10. 开始探测

  1. slLogger.Info("Beginning probe", "probe", module.Prober, "timeout_seconds", timeoutSeconds)
  2. start := time.Now()
  3. registry := prometheus.NewRegistry()
  4. registry.MustRegister(probeSuccessGauge)
  5. registry.MustRegister(probeDurationGauge)
  6. success := prober(ctx, target, module, registry, slLogger)
  7. duration := time.Since(start).Seconds()
  8. probeDurationGauge.Set(duration)
  9. if success {
  10.     probeSuccessGauge.Set(1)
  11.     slLogger.Info("Probe succeeded", "duration_seconds", duration)
  12. } else {
  13.     slLogger.Error("Probe failed", "duration_seconds", duration)
  14. }
复制代码


  • 记载日志开始探测。
  • 利用 prober(即相应的探针函数)开始实际的探测操作,并记载探测的持续时间。
  • 根据探测效果,设置 probe_success 和 probe_duration_seconds 指标。
11. 记载效果

  1. debugOutput := DebugOutput(&module, &sl.buffer, registry)
  2. rh.Add(moduleName, target, debugOutput, success)
复制代码


  • 调用 DebugOutput 函数天生调试输出,并将效果添加到 ResultHistory(用于记载汗青效果)。
12. 返回调试输出(如果启用)

  1. if r.URL.Query().Get("debug") == "true" {
  2.     w.Header().Set("Content-Type", "text/plain")
  3.     w.Write([]byte(debugOutput))
  4.     return
  5. }
复制代码


  • 如果查询参数 debug=true,则返回调试输出。
13. 返回 Prometheus 格式的指标

  1. h := promhttp.HandlerFor(registry, promhttp.HandlerOpts{})
  2. h.ServeHTTP(w, r)
复制代码


  • 创建 Prometheus 格式的 HTTP 处理程序,并返回探测效果的指标数据。
总结

它通过解析哀求参数来实行指定范例的探测(如 HTTP、TCP 探测),并天生相应的 Prometheus 指标。返回的指标可以被 Prometheus 服务器抓取并进行监控。此外,代码还处理了探测过程中的日志记载和调试输出。
prober(ctx, target, module, registry, slLogger)是整个实行探测的核心部门,下一篇将重点分析此函数

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

乌市泽哥

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表