拉取代码
注意:
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 打包
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
}