This commit is contained in:
parent
f84419de0d
commit
5df32a9b98
4 changed files with 198 additions and 0 deletions
|
@ -14,6 +14,7 @@ import (
|
||||||
_ "git.faercol.me/monitoring/sys-exporter/collector/loadavg"
|
_ "git.faercol.me/monitoring/sys-exporter/collector/loadavg"
|
||||||
_ "git.faercol.me/monitoring/sys-exporter/collector/meminfo"
|
_ "git.faercol.me/monitoring/sys-exporter/collector/meminfo"
|
||||||
_ "git.faercol.me/monitoring/sys-exporter/collector/pacman"
|
_ "git.faercol.me/monitoring/sys-exporter/collector/pacman"
|
||||||
|
_ "git.faercol.me/monitoring/sys-exporter/collector/sysinfo"
|
||||||
_ "git.faercol.me/monitoring/sys-exporter/collector/systemd"
|
_ "git.faercol.me/monitoring/sys-exporter/collector/systemd"
|
||||||
_ "git.faercol.me/monitoring/sys-exporter/collector/uptime"
|
_ "git.faercol.me/monitoring/sys-exporter/collector/uptime"
|
||||||
)
|
)
|
||||||
|
|
167
collector/sysinfo/sysinfo.go
Normal file
167
collector/sysinfo/sysinfo.go
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
package sysinfo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.faercol.me/monitoring/sys-exporter/registry"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
var versionRegexp = regexp.MustCompile(`(?m)^(\w+) version ([^ ]+) .*$`)
|
||||||
|
|
||||||
|
const (
|
||||||
|
hosnameFile = "/etc/hostname"
|
||||||
|
osRealeaseFile = "/etc/os-release"
|
||||||
|
versionFile = "/proc/version"
|
||||||
|
)
|
||||||
|
|
||||||
|
var labels = []string{
|
||||||
|
"hostname",
|
||||||
|
"kernel",
|
||||||
|
"os",
|
||||||
|
"distro",
|
||||||
|
"distro_version",
|
||||||
|
}
|
||||||
|
|
||||||
|
type SysinfoCollector struct {
|
||||||
|
hostname string
|
||||||
|
kernelVersion string
|
||||||
|
os string
|
||||||
|
distro string
|
||||||
|
distroVersion string
|
||||||
|
|
||||||
|
hostnameFile string
|
||||||
|
osReleaseFile string
|
||||||
|
versionFile string
|
||||||
|
|
||||||
|
promExporter *prometheus.GaugeVec
|
||||||
|
updateFreq time.Duration
|
||||||
|
l *zap.SugaredLogger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SysinfoCollector) Collect() interface{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SysinfoCollector) labels() prometheus.Labels {
|
||||||
|
return prometheus.Labels{
|
||||||
|
"hostname": c.hostname,
|
||||||
|
"kernel": c.kernelVersion,
|
||||||
|
"os": c.os,
|
||||||
|
"distro": c.distro,
|
||||||
|
"distro_version": c.distroVersion,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SysinfoCollector) updateHostname() error {
|
||||||
|
rawHostname, err := os.ReadFile(c.hostnameFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.hostname = strings.TrimSpace(string(rawHostname))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SysinfoCollector) updateKernelVersion() error {
|
||||||
|
rawVersion, err := os.ReadFile(c.versionFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches := versionRegexp.FindAllStringSubmatch(string(rawVersion), -1); matches == nil {
|
||||||
|
return errors.New("failed to match /proc/version")
|
||||||
|
} else {
|
||||||
|
c.os = matches[0][1]
|
||||||
|
c.kernelVersion = matches[0][2]
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SysinfoCollector) updateDistro() error {
|
||||||
|
rawContent, err := os.ReadFile(c.osReleaseFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
releaseData, err := parseOSRelease(rawContent)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to parse /etc/os-release file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch releaseData["ID"] {
|
||||||
|
case "arch":
|
||||||
|
c.distro = "Arch Linux"
|
||||||
|
c.distroVersion = releaseData["BUILD_ID"]
|
||||||
|
case "debian":
|
||||||
|
c.distro = "Debian GNU/Linux"
|
||||||
|
c.distroVersion = releaseData["VERSION"]
|
||||||
|
default:
|
||||||
|
c.distro = releaseData["NAME"]
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SysinfoCollector) update() error {
|
||||||
|
if err := c.updateKernelVersion(); err != nil {
|
||||||
|
return fmt.Errorf("failed to get kernel version: %w", err)
|
||||||
|
}
|
||||||
|
if err := c.updateHostname(); err != nil {
|
||||||
|
return fmt.Errorf("failed to get hostname: %w", err)
|
||||||
|
}
|
||||||
|
if err := c.updateDistro(); err != nil {
|
||||||
|
return fmt.Errorf("failed to get distro info: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.promExporter.With(c.labels()).Set(1)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SysinfoCollector) Run(ctx context.Context, l *zap.SugaredLogger) {
|
||||||
|
c.l = l
|
||||||
|
|
||||||
|
c.l.Debug("Initializing collector")
|
||||||
|
if err := c.update(); err != nil {
|
||||||
|
c.l.Errorf("Failed to init collector: %s\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
c.l.Debug("Stopping collector")
|
||||||
|
return
|
||||||
|
case <-time.After(c.updateFreq):
|
||||||
|
c.l.Debug("Updating collector")
|
||||||
|
if err := c.update(); err != nil {
|
||||||
|
c.l.Errorf("Failed to update collector: %s\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SysinfoCollector) PromCollector() prometheus.Collector {
|
||||||
|
return c.promExporter
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() *SysinfoCollector {
|
||||||
|
return &SysinfoCollector{
|
||||||
|
updateFreq: 30 * time.Minute,
|
||||||
|
hostnameFile: hosnameFile,
|
||||||
|
osReleaseFile: osRealeaseFile,
|
||||||
|
versionFile: versionFile,
|
||||||
|
promExporter: prometheus.NewGaugeVec(prometheus.GaugeOpts{Namespace: "system", Name: "info", Help: "System global information"}, labels),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registry.R.MustRegisterCollector("system.info", New())
|
||||||
|
}
|
29
collector/sysinfo/utils.go
Normal file
29
collector/sysinfo/utils.go
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
package sysinfo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func parseOSRelease(content []byte) (map[string]string, error) {
|
||||||
|
res := make(map[string]string)
|
||||||
|
|
||||||
|
for _, line := range strings.Split(string(content), "\n") {
|
||||||
|
if line == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
lineVals := strings.SplitN(line, "=", 2)
|
||||||
|
if len(lineVals) != 2 {
|
||||||
|
return nil, fmt.Errorf("impossible to split line %q", line)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := res[lineVals[0]]; ok {
|
||||||
|
return nil, fmt.Errorf("duplicate key %q", lineVals[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
res[lineVals[0]] = lineVals[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
|
@ -5,3 +5,4 @@ collectors:
|
||||||
- system.meminfo
|
- system.meminfo
|
||||||
- services.systemd
|
- services.systemd
|
||||||
- system.uptime
|
- system.uptime
|
||||||
|
- system.info
|
||||||
|
|
Loading…
Reference in a new issue