forked from prometheus/node_exporter
/
lastlogin.go
101 lines (83 loc) · 2.17 KB
/
lastlogin.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// +build !nolastlogin
package collector
import (
"bufio"
"fmt"
"io"
"os/exec"
"strings"
"time"
"github.com/golang/glog"
"github.com/prometheus/client_golang/prometheus"
)
const lastLoginSubsystem = "last_login"
type lastLoginCollector struct {
config Config
metric prometheus.Gauge
}
func init() {
Factories["lastlogin"] = NewLastLoginCollector
}
// Takes a config struct and prometheus registry and returns a new Collector exposing
// load, seconds since last login and a list of tags as specified by config.
func NewLastLoginCollector(config Config) (Collector, error) {
return &lastLoginCollector{
config: config,
metric: prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: lastLoginSubsystem,
Name: "time",
Help: "The time of the last login.",
}),
}, nil
}
func (c *lastLoginCollector) Update(ch chan<- prometheus.Metric) (err error) {
last, err := getLastLoginTime()
if err != nil {
return fmt.Errorf("Couldn't get last seen: %s", err)
}
glog.V(1).Infof("Set node_last_login_time: %f", last)
c.metric.Set(last)
c.metric.Collect(ch)
return err
}
func getLastLoginTime() (float64, error) {
who := exec.Command("who", "/var/log/wtmp", "-l", "-u", "-s")
output, err := who.StdoutPipe()
if err != nil {
return 0, err
}
err = who.Start()
if err != nil {
return 0, err
}
reader := bufio.NewReader(output)
var last time.Time
for {
line, isPrefix, err := reader.ReadLine()
if err == io.EOF {
break
}
if isPrefix {
return 0, fmt.Errorf("line to long: %s(...)", line)
}
fields := strings.Fields(string(line))
lastDate := fields[2]
lastTime := fields[3]
dateParts, err := splitToInts(lastDate, "-") // 2013-04-16
if err != nil {
return 0, fmt.Errorf("Couldn't parse date in line '%s': %s", fields, err)
}
timeParts, err := splitToInts(lastTime, ":") // 11:33
if err != nil {
return 0, fmt.Errorf("Couldn't parse time in line '%s': %s", fields, err)
}
last_t := time.Date(dateParts[0], time.Month(dateParts[1]), dateParts[2], timeParts[0], timeParts[1], 0, 0, time.UTC)
last = last_t
}
err = who.Wait()
if err != nil {
return 0, err
}
return float64(last.Unix()), nil
}