Update cpustat collector

This commit is contained in:
Thomas Roehl 2022-02-16 03:28:46 +01:00
parent 542520d2c0
commit 6adcc077ba

@ -1,12 +1,15 @@
package collectors package collectors
import ( import (
"bufio"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "os"
"strconv" "strconv"
"strings" "strings"
"time" "time"
cclog "github.com/ClusterCockpit/cc-metric-collector/internal/ccLogger"
lp "github.com/ClusterCockpit/cc-metric-collector/internal/ccMetric" lp "github.com/ClusterCockpit/cc-metric-collector/internal/ccMetric"
) )
@ -18,72 +21,127 @@ type CpustatCollectorConfig struct {
type CpustatCollector struct { type CpustatCollector struct {
metricCollector metricCollector
config CpustatCollectorConfig config CpustatCollectorConfig
matches map[string]int
cputags map[string]map[string]string
nodetags map[string]string
} }
func (m *CpustatCollector) Init(config json.RawMessage) error { func (m *CpustatCollector) Init(config json.RawMessage) error {
m.name = "CpustatCollector" m.name = "CpustatCollector"
m.setup() m.setup()
m.meta = map[string]string{"source": m.name, "group": "CPU"} m.meta = map[string]string{"source": m.name, "group": "CPU"}
m.nodetags = map[string]string{"type": "node"}
if len(config) > 0 { if len(config) > 0 {
err := json.Unmarshal(config, &m.config) err := json.Unmarshal(config, &m.config)
if err != nil { if err != nil {
return err return err
} }
} }
matches := []string{
"",
"cpu_user",
"cpu_nice",
"cpu_system",
"cpu_idle",
"cpu_iowait",
"cpu_irq",
"cpu_softirq",
"cpu_steal",
"cpu_guest",
"cpu_guest_nice",
}
m.matches = make(map[string]int)
for index, match := range matches {
if len(match) > 0 {
doExclude := false
for _, exclude := range m.config.ExcludeMetrics {
if match == exclude {
doExclude = true
break
}
}
if !doExclude {
m.matches[match] = index
}
}
}
// Check input file
file, err := os.Open(string(CPUSTATFILE))
if err != nil {
cclog.ComponentError(m.name, err.Error())
}
defer file.Close()
// Pre-generate tags for all CPUs
m.cputags = make(map[string]map[string]string)
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
linefields := strings.Fields(line)
if strings.HasPrefix(linefields[0], "cpu") && strings.Compare(linefields[0], "cpu") != 0 {
cpustr := strings.TrimLeft(linefields[0], "cpu")
cpu, _ := strconv.Atoi(cpustr)
m.cputags[linefields[0]] = map[string]string{"type": "cpu", "type-id": fmt.Sprintf("%d", cpu)}
}
}
m.init = true m.init = true
return nil return nil
} }
func (c *CpustatCollector) parseStatLine(line string, cpu int, exclude []string, output chan lp.CCMetric) { func (m *CpustatCollector) parseStatLine(linefields []string, tags map[string]string, output chan lp.CCMetric) {
ls := strings.Fields(line) values := make(map[string]float64)
matches := []string{"", "cpu_user", "cpu_nice", "cpu_system", "cpu_idle", "cpu_iowait", "cpu_irq", "cpu_softirq", "cpu_steal", "cpu_guest", "cpu_guest_nice"} total := 0.0
for _, ex := range exclude { for match, index := range m.matches {
matches, _ = RemoveFromStringList(matches, ex) if len(match) > 0 {
} x, err := strconv.ParseInt(linefields[index], 0, 64)
var tags map[string]string
if cpu < 0 {
tags = map[string]string{"type": "node"}
} else {
tags = map[string]string{"type": "cpu", "type-id": fmt.Sprintf("%d", cpu)}
}
for i, m := range matches {
if len(m) > 0 {
x, err := strconv.ParseInt(ls[i], 0, 64)
if err == nil { if err == nil {
y, err := lp.New(m, tags, c.meta, map[string]interface{}{"value": int(x)}, time.Now()) values[match] = float64(x)
if err == nil { total += values[match]
output <- y
}
} }
} }
} }
for name, value := range values {
y, err := lp.New(name, tags, m.meta, map[string]interface{}{"value": (value * 100.0) / total}, time.Now())
if err == nil {
output <- y
}
}
} }
func (m *CpustatCollector) Read(interval time.Duration, output chan lp.CCMetric) { func (m *CpustatCollector) Read(interval time.Duration, output chan lp.CCMetric) {
if !m.init { if !m.init {
return return
} }
buffer, err := ioutil.ReadFile(string(CPUSTATFILE)) num_cpus := 0
file, err := os.Open(string(CPUSTATFILE))
if err != nil { if err != nil {
return cclog.ComponentError(m.name, err.Error())
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
linefields := strings.Fields(line)
if strings.Compare(linefields[0], "cpu") == 0 {
m.parseStatLine(linefields, m.nodetags, output)
} else if strings.HasPrefix(linefields[0], "cpu") {
m.parseStatLine(linefields, m.cputags[linefields[0]], output)
num_cpus++
}
} }
ll := strings.Split(string(buffer), "\n") y, err := lp.New("num_cpus",
for _, line := range ll { m.nodetags,
if len(line) == 0 { m.meta,
continue map[string]interface{}{"value": int(num_cpus)},
} time.Now(),
ls := strings.Fields(line) )
if strings.Compare(ls[0], "cpu") == 0 { if err == nil {
m.parseStatLine(line, -1, m.config.ExcludeMetrics, output) output <- y
} else if strings.HasPrefix(ls[0], "cpu") {
cpustr := strings.TrimLeft(ls[0], "cpu")
cpu, _ := strconv.Atoi(cpustr)
m.parseStatLine(line, cpu, m.config.ExcludeMetrics, output)
}
} }
} }