5.5 node_exporter采集原理简介

本节重点介绍 :

  • node_exporter主流程源码追踪
  • mem模块采集的流程

node_exporter主流程源码追踪

采集器的初始化

  • 初始化handler
  • 源码位置 D:\nyy_work\go_path\pkg\mod\github.com\prometheus\node_exporter@v1.2.2\node_exporter.go
http.Handle(*metricsPath, newHandler(!*disableExporterMetrics, *maxRequests, logger))
  • 调用 newHandler,其中最关键一句是 innerHandler
	if innerHandler, err := h.innerHandler(); err != nil {
		panic(fmt.Sprintf("Couldn't create metrics handler: %s", err))
  • 调用 innerHandler ,其中干这么几件事
    • 根据过滤器初始化node_collector nc
    • 把 nc注册到 prometheus的 registry 上r.Register(nc)
  • 源码如下
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 {
		level.Info(h.logger).Log("msg", "Enabled collectors")
		collectors := []string{}
		for n := range nc.Collectors {
			collectors = append(collectors, n)
		}
		sort.Strings(collectors)
		for _, c := range collectors {
			level.Info(h.logger).Log("collector", c)
		}
	}

	r := prometheus.NewRegistry()
	r.MustRegister(version.NewCollector("node_exporter"))
	if err := r.Register(nc); err != nil {
		return nil, fmt.Errorf("couldn't register node collector: %s", err)
	}
	handler := promhttp.HandlerFor(
		prometheus.Gatherers{h.exporterMetricsRegistry, r},
		promhttp.HandlerOpts{
			ErrorLog:            stdlog.New(log.NewStdlibAdapter(level.Error(h.logger)), "", 0),
			ErrorHandling:       promhttp.ContinueOnError,
			MaxRequestsInFlight: h.maxRequests,
			Registry:            h.exporterMetricsRegistry,
		},
	)
	if h.includeExporterMetrics {
		// Note that we have to use h.exporterMetricsRegistry here to
		// use the same promhttp metrics for all expositions.
		handler = promhttp.InstrumentMetricHandler(
			h.exporterMetricsRegistry, handler,
		)
	}
	return handler, nil
}

NewNodeCollector 初始化nc

  • 源码位置 D:\nyy_work\go_path\pkg\mod\github.com\prometheus\node_exporter@v1.2.2\collector\collector.go
    • 根据 各个模块注册的 collectorState获取他们的执行函数 collector
// NewNodeCollector creates a new NodeCollector.
func NewNodeCollector(logger log.Logger, filters ...string) (*NodeCollector, error) {
	f := make(map[string]bool)
	for _, filter := range filters {
		enabled, exist := collectorState[filter]
		if !exist {
			return nil, fmt.Errorf("missing collector: %s", filter)
		}
		if !*enabled {
			return nil, fmt.Errorf("disabled collector: %s", filter)
		}
		f[filter] = true
	}
	collectors := make(map[string]Collector)
	initiatedCollectorsMtx.Lock()
	defer initiatedCollectorsMtx.Unlock()
	for key, enabled := range collectorState {
		if !*enabled || (len(f) > 0 && !f[key]) {
			continue
		}
		if collector, ok := initiatedCollectors[key]; ok {
			collectors[key] = collector
		} else {
			collector, err := factories[key](log.With(logger, "collector", key))
			if err != nil {
				return nil, err
			}
			collectors[key] = collector
			initiatedCollectors[key] = collector
		}
	}
	return &NodeCollector{Collectors: collectors, logger: logger}, nil
}
  • 各个模块会调用 在各自的init 函数中调用 registerCollector ,向 collectorState和factories注册自己
func registerCollector(collector string, isDefaultEnabled bool, factory func(logger log.Logger) (Collector, error)) {
	var helpDefaultState string
	if isDefaultEnabled {
		helpDefaultState = "enabled"
	} else {
		helpDefaultState = "disabled"
	}

	flagName := fmt.Sprintf("collector.%s", collector)
	flagHelp := fmt.Sprintf("Enable the %s collector (default: %s).", collector, helpDefaultState)
	defaultValue := fmt.Sprintf("%v", isDefaultEnabled)

	flag := kingpin.Flag(flagName, flagHelp).Default(defaultValue).Action(collectorFlagAction(collector)).Bool()
	collectorState[collector] = flag

	factories[collector] = factory
}

p1.png

执行采集

  • prometheus sdk中执行采集就是执行对应的 Collect方法
  • 源码位置 D:\nyy_work\go_path\pkg\mod\github.com\prometheus\node_exporter@v1.2.2\collector\collector.go
// Collect implements the prometheus.Collector interface.
func (n NodeCollector) Collect(ch chan<- prometheus.Metric) {
	wg := sync.WaitGroup{}
	wg.Add(len(n.Collectors))
	for name, c := range n.Collectors {
		go func(name string, c Collector) {
			execute(name, c, ch, n.logger)
			wg.Done()
		}(name, c)
	}
	wg.Wait()
}
  • 调用 execute函数,可以看到就是调用各个 collector模块的 update函数p2.png

mem采集模块的内容

  • Update源码位置 D:\nyy_work\go_path\pkg\mod\github.com\prometheus\node_exporter@v1.2.2\collector\meminfo.go
  • 源码如下
// Update calls (*meminfoCollector).getMemInfo to get the platform specific
// memory metrics.
func (c *meminfoCollector) Update(ch chan<- prometheus.Metric) error {
	var metricType prometheus.ValueType
	memInfo, err := c.getMemInfo()
	if err != nil {
		return fmt.Errorf("couldn't get meminfo: %w", err)
	}
	level.Debug(c.logger).Log("msg", "Set node_mem", "memInfo", memInfo)
	for k, v := range memInfo {
		if strings.HasSuffix(k, "_total") {
			metricType = prometheus.CounterValue
		} else {
			metricType = prometheus.GaugeValue
		}
		ch <- prometheus.MustNewConstMetric(
			prometheus.NewDesc(
				prometheus.BuildFQName(namespace, memInfoSubsystem, k),
				fmt.Sprintf("Memory information field %s.", k),
				nil, nil,
			),
			metricType, v,
		)
	}
	return nil
}
  • 内容分析
    • 通过c.getMemInfo() 获取到memInfo
    • 在linux 中memInfo中对应的就是 /proc/meminfo ,逐行解析
    • 遍历推送即可

本节重点总结 :

  • node_exporter主流程源码追踪
  • mem模块采集的流程
如果你想使用podman部署node-exporter,可以按照以下步骤进行操作: 1. 创建一个名为node-exporter的目录,用于存放node-exporter的配置文件和数据。使用以下命令创建: ``` mkdir node-exporter ``` 2. 创建一个名为node-exporter.service的systemd服务单元文件,用于启动node-exporter服务。使用以下命令创建: ``` sudo vi /etc/systemd/system/node-exporter.service ``` 将以下内容复制粘贴到文件中: ``` [Unit] Description=Node Exporter [Service] Restart=always ExecStartPre=podman rm node-exporter ExecStart=/usr/bin/podman run --name node-exporter --net=host --pid=host --privileged=true -v /proc:/host/proc:ro -v /sys:/host/sys:ro -v /:/rootfs:ro -v /etc/node-exporter:/etc/node-exporter:z quay.io/prometheus/node-exporter [Install] WantedBy=multi-user.target ``` 保存并退出文件。 3. 创建一个名为node-exporter的配置文件目录,用于存放node-exporter的配置文件。使用以下命令创建: ``` sudo mkdir /etc/node-exporter ``` 4. 创建一个名为node-exporter.yml的node-exporter配置文件,用于指定node-exporter的参数和监控对象。使用以下命令创建: ``` sudo vi /etc/node-exporter/node-exporter.yml ``` 将以下内容复制粘贴到文件中: ``` global: scrape_interval: 15s scrape_configs: - job_name: 'node' metrics_path: /metrics static_configs: - targets: ['localhost:9100'] ``` 保存并退出文件。 5. 重新加载systemd守护程序并启动node-exporter服务。使用以下命令执行: ``` sudo systemctl daemon-reload sudo systemctl enable node-exporter sudo systemctl start node-exporter ``` 6. 确认node-exporter服务已经成功启动。使用以下命令查看服务状态: ``` sudo systemctl status node-exporter ``` 如果服务状态显示为“active (running)”则表示服务已经启动成功。 希望以上步骤能够帮助你成功部署node-exporter服务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

福大大架构师每日一题

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值