这两个函数是 Go 语言 node_exporter
的核心部分,主要与 Prometheus 指标的收集、注册、处理以及 HTTP 处理器的创建相关。我们将逐步解析每个函数的逻辑。
目录
1. newHandler函数
func newHandler(includeExporterMetrics bool, maxRequests int, logger *slog.Logger) *handler {
h := &handler{
exporterMetricsRegistry: prometheus.NewRegistry(),
includeExporterMetrics: includeExporterMetrics,
maxRequests: maxRequests,
logger: logger,
}
if h.includeExporterMetrics {
h.exporterMetricsRegistry.MustRegister(
promcollectors.NewProcessCollector(promcollectors.ProcessCollectorOpts{}),
promcollectors.NewGoCollector(),
)
}
if innerHandler, err := h.innerHandler(); err != nil {
panic(fmt.Sprintf("Couldn't create metrics handler: %s", err))
} else {
h.unfilteredHandler = innerHandler
}
return h
}
解析:
-
创建
handler
对象:h := &handler{ exporterMetricsRegistry: prometheus.NewRegistry(), includeExporterMetrics: includeExporterMetrics, maxRequests: maxRequests, logger: logger, }
- 这段代码初始化了一个
handler
实例,并设置其属性:exporterMetricsRegistry
: 创建一个新的 PrometheusRegistry
,用来注册指标。includeExporterMetrics
: 是否包括node_exporter
自身的指标(如进程、Go runtime 等)。maxRequests
: 配置最大并发请求数。logger
: 用于记录日志的logger
对象。
- 这段代码初始化了一个
-
如果
includeExporterMetrics
为true
,注册与 exporter 自身相关的指标:if h.includeExporterMetrics { h.exporterMetricsRegistry.MustRegister( promcollectors.NewProcessCollector(promcollectors.ProcessCollectorOpts{}), promcollectors.NewGoCollector(), ) }
- 如果
includeExporterMetrics
为true
,则将ProcessCollector
和GoCollector
注册到exporterMetricsRegistry
中。ProcessCollector
采集与进程相关的指标(如进程的 CPU、内存使用等)。GoCollector
采集 Go runtime 的指标(如 goroutine 数、GC 状态等)。
- 如果
-
调用
innerHandler
函数创建内部处理器:if innerHandler, err := h.innerHandler(); err != nil { panic(fmt.Sprintf("Couldn't create metrics handler: %s", err)) } else { h.unfilteredHandler = innerHandler }
- 调用
innerHandler
方法来创建一个指标处理器。如果出错,则程序会 panic 并打印错误信息。否则,将生成的处理器赋值给h.unfilteredHandler
。
- 调用
-
返回创建的
handler
对象:return h
- 返回构建好的
handler
实例。
- 返回构建好的
2. innerHandler函数
func (h *handler) innerHandler(filters ...string) (http.Handler, error) {
nc, err := collector.NewNodeCollector(h.logger, filters...)
if err != nil {
return nil, fmt.Errorf("couldn't create collector: %s", err)
}
// Only log the creation of an unfiltered handler, which should happen
// only once upon startup.
if len(filters) == 0 {
h.logger.Info("Enabled collectors")
for n := range nc.Collectors {
h.enabledCollectors = append(h.enabledCollectors, n)
}
sort.Strings(h.enabledCollectors)
for _, c := range h.enabledCollectors {
h.logger.Info(c)
}
}
r := prometheus.NewRegistry()
r.MustRegister(versioncollector.NewCollector("node_exporter"))
if err := r.Register(nc); err != nil {
return nil, fmt.Errorf("couldn't register node collector: %s", err)
}
var handler http.Handler
if h.includeExporterMetrics {
handler = promhttp.HandlerFor(
prometheus.Gatherers{h.exporterMetricsRegistry, r},
promhttp.HandlerOpts{
ErrorLog: slog.NewLogLogger(h.logger.Handler(), slog.LevelError),
ErrorHandling: promhttp.ContinueOnError,
MaxRequestsInFlight: h.maxRequests,
Registry: h.exporterMetricsRegistry,
},
)
// Note that we have to use h.exporterMetricsRegistry here to
// use the same promhttp metrics for all expositions.
handler = promhttp.InstrumentMetricHandler(
h.exporterMetricsRegistry, handler,
)
} else {
handler = promhttp.HandlerFor(
r,
promhttp.HandlerOpts{
ErrorLog: slog.NewLogLogger(h.logger.Handler(), slog.LevelError),
ErrorHandling: promhttp.ContinueOnError,
MaxRequestsInFlight: h.maxRequests,
},
)
}
return handler, nil
}
解析:
-
创建
NodeCollector
:nc, err := collector.NewNodeCollector(h.logger, filters...) if err != nil { return nil, fmt.Errorf("couldn't create collector: %s", err) }
- 创建一个
NodeCollector
实例来收集系统的节点级指标。如果发生错误,则返回错误信息。
- 创建一个
-
记录启用的采集器:
if len(filters) == 0 { h.logger.Info("Enabled collectors") for n := range nc.Collectors { h.enabledCollectors = append(h.enabledCollectors, n) } sort.Strings(h.enabledCollectors) for _, c := range h.enabledCollectors { h.logger.Info(c) } }
- 如果没有传入过滤器(即默认启用所有采集器),则记录启用的采集器。
- 将启用的采集器按名称排序,并逐个输出日志。
-
创建一个新的
prometheus.Registry
:r := prometheus.NewRegistry() r.MustRegister(versioncollector.NewCollector("node_exporter"))
- 创建一个新的
Registry
实例并注册versioncollector
(记录node_exporter
版本信息)。
- 创建一个新的
-
注册
NodeCollector
:if err := r.Register(nc); err != nil { return nil, fmt.Errorf("couldn't register node collector: %s", err) }
- 将
NodeCollector
注册到 Prometheus 的Registry
中。如果注册失败,则返回错误。
- 将
-
根据
includeExporterMetrics
决定使用哪个处理器:var handler http.Handler if h.includeExporterMetrics { handler = promhttp.HandlerFor( prometheus.Gatherers{h.exporterMetricsRegistry, r}, promhttp.HandlerOpts{ ErrorLog: slog.NewLogLogger(h.logger.Handler(), slog.LevelError), ErrorHandling: promhttp.ContinueOnError, MaxRequestsInFlight: h.maxRequests, Registry: h.exporterMetricsRegistry, }, ) handler = promhttp.InstrumentMetricHandler( h.exporterMetricsRegistry, handler, ) } else { handler = promhttp.HandlerFor( r, promhttp.HandlerOpts{ ErrorLog: slog.NewLogLogger(h.logger.Handler(), slog.LevelError), ErrorHandling: promhttp.ContinueOnError, MaxRequestsInFlight: h.maxRequests, }, ) }
- 如果
includeExporterMetrics
为true
,则创建一个promhttp.Handler
,用于处理包括node_exporter
自身的指标在内的所有指标。使用prometheus.Gatherers{h.exporterMetricsRegistry, r}
来聚合来自exporterMetricsRegistry
和r
的指标。 - 如果
includeExporterMetrics
为false
,则只创建一个包含r
的处理器。
- 如果
-
返回 HTTP 处理器:
return handler, nil
- 返回构建好的 HTTP 处理器。
总结:
-
newHandler
:该函数主要负责创建handler
对象,初始化 Prometheus 指标的注册表,并根据是否需要包括node_exporter
自身的指标来注册相应的指标。如果需要,还会调用innerHandler
来创建一个指标处理器。 -
innerHandler
:该函数负责创建NodeCollector
,注册节点采集器,创建并配置 Prometheus 的Registry
,然后根据是否包含node_exporter
自身的指标来创建并返回一个 HTTP 处理器。
这两个函数共同作用,负责创建 node_exporter
的 HTTP 处理器并提供 Prometheus 格式的指标。