node_exporter模块的二开方法

259 阅读1分钟

拉取代码

image.png 注意:

go.mod定义go的版本不能低于这个版本

自定义一个模块的二开方法

  • collect/目录下新建一个 user.go

  • 定义一个结构体体userExpiryCollector

type userExpiryCollector struct {
	logger  log.Logger
}
  • 写一个new xxCollector的工厂函数,一个参数为 log.logger
func NewUserExpiryCollector(logger log.Logger) (Collector, error) {
	return &userExpiryCollector{logger}, nil
}
  • 写一个 init方法调用 registerCollector 注册自己
func init() {
	registerCollector("user_expiry", defaultEnabled, NewUserExpiryCollector)
}
  • 给这个结构体绑定一个Update方法,签名如下
func (c *xxCollector) Update(ch chan<- prometheus.Metric) error {}

完成这个Update方法

流程说明

  • 分析/etc/shadow文件
    • 第4个字段是密码过期多少天
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:997:User for polkitd:/:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
chrony:x:998:996::/var/lib/chrony:/sbin/nologin
tom:x:1000:1000:tom:/home/tom:/bin/bash
nginx:x:997:995:Nginx web server:/var/lib/nginx:/sbin/nologin
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
mysql:x:27:27:MariaDB Server:/var/lib/mysql:/sbin/nologin
zhangsan:x:1001:1001::/home/zhangsan:/bin/bash


然后在Update中按行遍历

  • 按行遍历之后再按 :分割就能得到 user和过期天数
  • value 字符串转换为float64
  • 然后构建一个 metric对象塞入ch中即可
func (c *userExpiryCollector) Update(ch chan<- prometheus.Metric) error {
	output, err := ioutil.ReadFile("/etc/shadow")
	if err != nil {
		return err
	}

	lines := strings.Split(string(output), "\n")
	for _, line := range lines {
		fields := strings.Split(line, ":")
		if len(fields) >= 5 {
			expiryDays := fields[4]
			if expiryDays == "" {
				expiryDays = "0"
			}
			days, _ := strconv.ParseFloat(expiryDays, 64)
			ch <- prometheus.MustNewConstMetric(
				prometheus.NewDesc(
					prometheus.BuildFQName(namespace, "user", "expiry_days"),
					"Number of days until a user's password expires",
					[]string{"user"},
					nil,
				),
				prometheus.GaugeValue,
				days,
				fields[0],
			)
		}
	}
	return nil
}

运行我们的程序

  • 进入git bash 打包

image.png

 env GOOS=linux GOARCH=amd64 go build -v  node_exporter.go
  • 然后运行 chmod +x node_exporter ./node_exporter --web.listen-address=":9101"
  • 查询 metrics
 curl http://192.168.26.89:9101/metrics | grep node_user_expiry_days
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 73674    0 73674    0     0  7994k      0 --:--:-- --:--:-- --:--:-- 8993k
# HELP node_user_expiry_days Number of days until a user's password expires
# TYPE node_user_expiry_days gauge
node_user_expiry_days{user="adm"} 99999
node_user_expiry_days{user="apache"} 0
node_user_expiry_days{user="bin"} 99999
node_user_expiry_days{user="chrony"} 0
node_user_expiry_days{user="daemon"} 99999
node_user_expiry_days{user="dbus"} 0
node_user_expiry_days{user="ftp"} 99999
node_user_expiry_days{user="games"} 99999
node_user_expiry_days{user="halt"} 99999
node_user_expiry_days{user="lp"} 99999
node_user_expiry_days{user="mail"} 99999
node_user_expiry_days{user="mysql"} 0
node_user_expiry_days{user="nginx"} 0
node_user_expiry_days{user="nobody"} 99999
node_user_expiry_days{user="operator"} 99999
node_user_expiry_days{user="polkitd"} 0
node_user_expiry_days{user="postfix"} 0
node_user_expiry_days{user="root"} 99999
node_user_expiry_days{user="shutdown"} 99999
node_user_expiry_days{user="sshd"} 0
node_user_expiry_days{user="sync"} 99999
node_user_expiry_days{user="systemd-network"} 0
node_user_expiry_days{user="tom"} 30
node_user_expiry_days{user="zhangsan"} 99999

完整的user.go

package collector

import (
	"github.com/go-kit/log"
	"io/ioutil"
	"strconv"
	"strings"

	"github.com/prometheus/client_golang/prometheus"
)

type userExpiryCollector struct {
	logger log.Logger
}

func init() {
	registerCollector("user_expiry", defaultEnabled, NewUserExpiryCollector)
}

func NewUserExpiryCollector(logger log.Logger) (Collector, error) {
	return &userExpiryCollector{logger}, nil
}

func (c *userExpiryCollector) Update(ch chan<- prometheus.Metric) error {
	output, err := ioutil.ReadFile("/etc/shadow")
	if err != nil {
		return err
	}

	lines := strings.Split(string(output), "\n")
	for _, line := range lines {
		fields := strings.Split(line, ":")
		if len(fields) >= 5 {
			expiryDays := fields[4]
			if expiryDays == "" {
				expiryDays = "0"
			}
			days, _ := strconv.ParseFloat(expiryDays, 64)
			ch <- prometheus.MustNewConstMetric(
				prometheus.NewDesc(
					prometheus.BuildFQName(namespace, "user", "expiry_days"),
					"Number of days until a user's password expires",
					[]string{"user"},
					nil,
				),
				prometheus.GaugeValue,
				days,
				fields[0],
			)
		}
	}
	return nil
}