mirror of
https://github.com/prometheus/node_exporter.git
synced 2025-01-28 14:22:51 -08:00
20b551ab2b
Remove all hardcoded references to `/proc`. For all collectors that do not use `github.com/prometheus/procfs` yet, provide a wrapper to generate the full paths. Reformulate help strings, errors and comments to remove absolute references to `/proc`. This is a breaking change: the `-collector.ipvs.procfs` flag is removed in favor of the general flag. Since it only affected that collector it was only useful for development, so this should not cause many issues.
115 lines
2.9 KiB
Go
115 lines
2.9 KiB
Go
// +build !nosockstat
|
|
|
|
package collector
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
"io"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
sockStatSubsystem = "sockstat"
|
|
)
|
|
|
|
// Used for calculating the total memory bytes on TCP and UDP.
|
|
var pageSize = os.Getpagesize()
|
|
|
|
type sockStatCollector struct {
|
|
metrics map[string]prometheus.Gauge
|
|
}
|
|
|
|
func init() {
|
|
Factories[sockStatSubsystem] = NewSockStatCollector
|
|
}
|
|
|
|
// NewSockStatCollector returns a new Collector exposing socket stats.
|
|
func NewSockStatCollector() (Collector, error) {
|
|
return &sockStatCollector{
|
|
metrics: map[string]prometheus.Gauge{},
|
|
}, nil
|
|
}
|
|
|
|
func (c *sockStatCollector) Update(ch chan<- prometheus.Metric) (err error) {
|
|
sockStats, err := getSockStats(procFilePath("net/sockstat"))
|
|
if err != nil {
|
|
return fmt.Errorf("couldn't get sockstats: %s", err)
|
|
}
|
|
for protocol, protocolStats := range sockStats {
|
|
for name, value := range protocolStats {
|
|
key := protocol + "_" + name
|
|
if _, ok := c.metrics[key]; !ok {
|
|
c.metrics[key] = prometheus.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Namespace: Namespace,
|
|
Subsystem: sockStatSubsystem,
|
|
Name: key,
|
|
Help: fmt.Sprintf("Number of %s sockets in state %s.", protocol, name),
|
|
},
|
|
)
|
|
}
|
|
v, err := strconv.ParseFloat(value, 64)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid value %s in sockstats: %s", value, err)
|
|
}
|
|
c.metrics[key].Set(v)
|
|
}
|
|
}
|
|
for _, m := range c.metrics {
|
|
m.Collect(ch)
|
|
}
|
|
return err
|
|
}
|
|
|
|
func getSockStats(fileName string) (map[string]map[string]string, error) {
|
|
file, err := os.Open(fileName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer file.Close()
|
|
|
|
return parseSockStats(file, fileName)
|
|
}
|
|
|
|
func parseSockStats(r io.Reader, fileName string) (map[string]map[string]string, error) {
|
|
var (
|
|
sockStat = map[string]map[string]string{}
|
|
scanner = bufio.NewScanner(r)
|
|
)
|
|
|
|
for scanner.Scan() {
|
|
line := strings.Split(string(scanner.Text()), " ")
|
|
// Remove trailing ':'.
|
|
protocol := line[0][:len(line[0])-1]
|
|
sockStat[protocol] = map[string]string{}
|
|
|
|
for i := 1; i < len(line) && i+1 < len(line); i++ {
|
|
sockStat[protocol][line[i]] = line[i+1]
|
|
i++
|
|
}
|
|
}
|
|
|
|
// The mem metrics is the count of pages used. Multiply the mem metrics by
|
|
// the page size from the kernel to get the number of bytes used.
|
|
//
|
|
// Update the TCP mem from page count to bytes.
|
|
pageCount, err := strconv.Atoi(sockStat["TCP"]["mem"])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid value %s in sockstats: %s", sockStat["TCP"]["mem"], err)
|
|
}
|
|
sockStat["TCP"]["mem_bytes"] = strconv.Itoa(pageCount * pageSize)
|
|
|
|
// Update the UDP mem from page count to bytes.
|
|
pageCount, err = strconv.Atoi(sockStat["UDP"]["mem"])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid value %s in sockstats: %s", sockStat["UDP"]["mem"], err)
|
|
}
|
|
sockStat["UDP"]["mem_bytes"] = strconv.Itoa(pageCount * pageSize)
|
|
|
|
return sockStat, nil
|
|
}
|