mirror of
https://github.com/ClusterCockpit/cc-metric-collector.git
synced 2025-04-26 14:11:43 +02:00
* Remove go-toolkit as build requirement for RPM builds if run in CI * Remove condition around BuildRequires and use go-toolkit for RPM builds * use go-toolkit for RPM builds * Install go-toolkit to fulfill build requirements for RPM * Add golang-race for UBI9 and Alma9 * Fix wrongly named packages * Fix wrongly named packages * Fix Release part * Fix Release part * Fix documentation of RAPL collector * Mark all JSON config fields of message processor as omitempty * Generate HUGO inputs out of Markdown files * Check creation of CCMessage in NATS receiver * Use CCMessage FromBytes instead of Influx's decoder * Rename 'process_message' to 'process_messages' in metricRouter config This makes the behavior more consistent with the other modules, which have their MessageProcessor named 'process_messages'. This most likely was just a typo. * Add optional interface alias in netstat (#130) * Check creation of CCMessage in NATS receiver * add optional interface aliases for netstatMetric * small fix --------- Co-authored-by: Thomas Roehl <thomas.roehl@fau.de> Co-authored-by: exterr2f <Robert.Externbrink@rub.de> Co-authored-by: Thomas Gruber <Thomas.Roehl@googlemail.com> * Fix excluded metrics for diskstat and add exclude_mounts (#131) * Check creation of CCMessage in NATS receiver * fix excluded metrics and add optional mountpoint exclude --------- Co-authored-by: Thomas Roehl <thomas.roehl@fau.de> Co-authored-by: exterr2f <Robert.Externbrink@rub.de> Co-authored-by: Thomas Gruber <Thomas.Roehl@googlemail.com> * Add derived values for nfsiostat (#132) * Check creation of CCMessage in NATS receiver * add derived_values for nfsiostatMetric --------- Co-authored-by: Thomas Roehl <thomas.roehl@fau.de> Co-authored-by: exterr2f <Robert.Externbrink@rub.de> Co-authored-by: Thomas Gruber <Thomas.Roehl@googlemail.com> * Add exclude_devices to iostat (#133) * Check creation of CCMessage in NATS receiver * add exclude_device for iostatMetric * add md file --------- Co-authored-by: Thomas Roehl <thomas.roehl@fau.de> Co-authored-by: exterr2f <Robert.Externbrink@rub.de> Co-authored-by: Thomas Gruber <Thomas.Roehl@googlemail.com> * Add derived_values for numastats (#134) * Check creation of CCMessage in NATS receiver * add derived_values for numastats * change to ccMessage * remove vim command artefact --------- Co-authored-by: Thomas Roehl <thomas.roehl@fau.de> Co-authored-by: exterr2f <Robert.Externbrink@rub.de> Co-authored-by: Thomas Gruber <Thomas.Roehl@googlemail.com> * Fix artifacts of not done cc-lib switch * Fix artifacts in netstat collector of not done cc-lib switch * Change to cc-lib (#135) * Change to ccMessage from cc-lib * Remove local development path * Use receiver, sinks, ccLogger and ccConfig from cc-lib * Fix ccLogger import path * Update CI * Delete mountpoint when it vanishes, not just its data (#137) --------- Co-authored-by: Michael Panzlaff <michael.panzlaff@fau.de> Co-authored-by: brinkcoder <Robert.Externbrink@ruhr-uni-bochum.de> Co-authored-by: exterr2f <Robert.Externbrink@rub.de>
312 lines
7.4 KiB
Go
312 lines
7.4 KiB
Go
package collectors
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
|
|
cclog "github.com/ClusterCockpit/cc-lib/ccLogger"
|
|
lp "github.com/ClusterCockpit/cc-lib/ccMessage"
|
|
"golang.org/x/sys/unix"
|
|
|
|
"encoding/json"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const IB_BASEPATH = "/sys/class/infiniband/"
|
|
|
|
type InfinibandCollectorMetric struct {
|
|
name string
|
|
path string
|
|
unit string
|
|
scale int64
|
|
addToIBTotal bool
|
|
addToIBTotalPkgs bool
|
|
currentState int64
|
|
lastState int64
|
|
}
|
|
|
|
type InfinibandCollectorInfo struct {
|
|
LID string // IB local Identifier (LID)
|
|
device string // IB device
|
|
port string // IB device port
|
|
portCounterFiles []InfinibandCollectorMetric // mapping counter name -> InfinibandCollectorMetric
|
|
tagSet map[string]string // corresponding tag list
|
|
}
|
|
|
|
type InfinibandCollector struct {
|
|
metricCollector
|
|
config struct {
|
|
ExcludeDevices []string `json:"exclude_devices,omitempty"` // IB device to exclude e.g. mlx5_0
|
|
SendAbsoluteValues bool `json:"send_abs_values"` // Send absolut values as read from sys filesystem
|
|
SendTotalValues bool `json:"send_total_values"` // Send computed total values
|
|
SendDerivedValues bool `json:"send_derived_values"` // Send derived values e.g. rates
|
|
}
|
|
info []InfinibandCollectorInfo
|
|
lastTimestamp time.Time // Store time stamp of last tick to derive bandwidths
|
|
}
|
|
|
|
// Init initializes the Infiniband collector by walking through files below IB_BASEPATH
|
|
func (m *InfinibandCollector) Init(config json.RawMessage) error {
|
|
|
|
// Check if already initialized
|
|
if m.init {
|
|
return nil
|
|
}
|
|
|
|
var err error
|
|
m.name = "InfinibandCollector"
|
|
m.setup()
|
|
m.parallel = true
|
|
m.meta = map[string]string{
|
|
"source": m.name,
|
|
"group": "Network",
|
|
}
|
|
|
|
// Set default configuration,
|
|
m.config.SendAbsoluteValues = true
|
|
m.config.SendDerivedValues = false
|
|
// Read configuration file, allow overwriting default config
|
|
if len(config) > 0 {
|
|
err = json.Unmarshal(config, &m.config)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Loop for all InfiniBand directories
|
|
globPattern := filepath.Join(IB_BASEPATH, "*", "ports", "*")
|
|
ibDirs, err := filepath.Glob(globPattern)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to glob files with pattern %s: %v", globPattern, err)
|
|
}
|
|
if ibDirs == nil {
|
|
return fmt.Errorf("unable to find any directories with pattern %s", globPattern)
|
|
}
|
|
|
|
for _, path := range ibDirs {
|
|
|
|
// Skip, when no LID is assigned
|
|
line, err := os.ReadFile(filepath.Join(path, "lid"))
|
|
if err != nil {
|
|
continue
|
|
}
|
|
LID := strings.TrimSpace(string(line))
|
|
if LID == "0x0" {
|
|
continue
|
|
}
|
|
|
|
// Get device and port component
|
|
pathSplit := strings.Split(path, string(os.PathSeparator))
|
|
device := pathSplit[4]
|
|
port := pathSplit[6]
|
|
|
|
// Skip excluded devices
|
|
skip := false
|
|
for _, excludedDevice := range m.config.ExcludeDevices {
|
|
if excludedDevice == device {
|
|
skip = true
|
|
break
|
|
}
|
|
}
|
|
if skip {
|
|
continue
|
|
}
|
|
|
|
// Check access to counter files
|
|
countersDir := filepath.Join(path, "counters")
|
|
portCounterFiles := []InfinibandCollectorMetric{
|
|
{
|
|
name: "ib_recv",
|
|
path: filepath.Join(countersDir, "port_rcv_data"),
|
|
unit: "bytes",
|
|
scale: 4,
|
|
addToIBTotal: true,
|
|
lastState: -1,
|
|
},
|
|
{
|
|
name: "ib_xmit",
|
|
path: filepath.Join(countersDir, "port_xmit_data"),
|
|
unit: "bytes",
|
|
scale: 4,
|
|
addToIBTotal: true,
|
|
lastState: -1,
|
|
},
|
|
{
|
|
name: "ib_recv_pkts",
|
|
path: filepath.Join(countersDir, "port_rcv_packets"),
|
|
unit: "packets",
|
|
scale: 1,
|
|
addToIBTotalPkgs: true,
|
|
lastState: -1,
|
|
},
|
|
{
|
|
name: "ib_xmit_pkts",
|
|
path: filepath.Join(countersDir, "port_xmit_packets"),
|
|
unit: "packets",
|
|
scale: 1,
|
|
addToIBTotalPkgs: true,
|
|
lastState: -1,
|
|
},
|
|
}
|
|
for _, counter := range portCounterFiles {
|
|
err := unix.Access(counter.path, unix.R_OK)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to access %s: %v", counter.path, err)
|
|
}
|
|
}
|
|
|
|
m.info = append(m.info,
|
|
InfinibandCollectorInfo{
|
|
LID: LID,
|
|
device: device,
|
|
port: port,
|
|
portCounterFiles: portCounterFiles,
|
|
tagSet: map[string]string{
|
|
"type": "node",
|
|
"device": device,
|
|
"port": port,
|
|
"lid": LID,
|
|
},
|
|
})
|
|
}
|
|
|
|
if len(m.info) == 0 {
|
|
return fmt.Errorf("found no IB devices")
|
|
}
|
|
|
|
m.init = true
|
|
return nil
|
|
}
|
|
|
|
// Read reads Infiniband counter files below IB_BASEPATH
|
|
func (m *InfinibandCollector) Read(interval time.Duration, output chan lp.CCMessage) {
|
|
|
|
// Check if already initialized
|
|
if !m.init {
|
|
return
|
|
}
|
|
|
|
// Current time stamp
|
|
now := time.Now()
|
|
// time difference to last time stamp
|
|
timeDiff := now.Sub(m.lastTimestamp).Seconds()
|
|
// Save current timestamp
|
|
m.lastTimestamp = now
|
|
|
|
for i := range m.info {
|
|
info := &m.info[i]
|
|
|
|
var ib_total, ib_total_pkts int64
|
|
for i := range info.portCounterFiles {
|
|
counterDef := &info.portCounterFiles[i]
|
|
|
|
// Read counter file
|
|
line, err := os.ReadFile(counterDef.path)
|
|
if err != nil {
|
|
cclog.ComponentError(
|
|
m.name,
|
|
fmt.Sprintf("Read(): Failed to read from file '%s': %v", counterDef.path, err))
|
|
continue
|
|
}
|
|
data := strings.TrimSpace(string(line))
|
|
|
|
// convert counter to int64
|
|
v, err := strconv.ParseInt(data, 10, 64)
|
|
if err != nil {
|
|
cclog.ComponentError(
|
|
m.name,
|
|
fmt.Sprintf("Read(): Failed to convert Infininiband metrice %s='%s' to int64: %v", counterDef.name, data, err))
|
|
continue
|
|
}
|
|
// Scale raw value
|
|
v *= counterDef.scale
|
|
|
|
// Save current state
|
|
counterDef.currentState = v
|
|
|
|
// Send absolut values
|
|
if m.config.SendAbsoluteValues {
|
|
if y, err :=
|
|
lp.NewMessage(
|
|
counterDef.name,
|
|
info.tagSet,
|
|
m.meta,
|
|
map[string]interface{}{
|
|
"value": counterDef.currentState,
|
|
},
|
|
now); err == nil {
|
|
y.AddMeta("unit", counterDef.unit)
|
|
output <- y
|
|
}
|
|
}
|
|
|
|
// Send derived values
|
|
if m.config.SendDerivedValues {
|
|
if counterDef.lastState >= 0 {
|
|
rate := float64((counterDef.currentState - counterDef.lastState)) / timeDiff
|
|
if y, err :=
|
|
lp.NewMessage(
|
|
counterDef.name+"_bw",
|
|
info.tagSet,
|
|
m.meta,
|
|
map[string]interface{}{
|
|
"value": rate,
|
|
},
|
|
now); err == nil {
|
|
y.AddMeta("unit", counterDef.unit+"/sec")
|
|
output <- y
|
|
|
|
}
|
|
}
|
|
counterDef.lastState = counterDef.currentState
|
|
}
|
|
|
|
// Sum up total values
|
|
if m.config.SendTotalValues {
|
|
switch {
|
|
case counterDef.addToIBTotal:
|
|
ib_total += counterDef.currentState
|
|
case counterDef.addToIBTotalPkgs:
|
|
ib_total_pkts += counterDef.currentState
|
|
}
|
|
}
|
|
}
|
|
|
|
// Send total values
|
|
if m.config.SendTotalValues {
|
|
if y, err :=
|
|
lp.NewMessage(
|
|
"ib_total",
|
|
info.tagSet,
|
|
m.meta,
|
|
map[string]interface{}{
|
|
"value": ib_total,
|
|
},
|
|
now); err == nil {
|
|
y.AddMeta("unit", "bytes")
|
|
output <- y
|
|
}
|
|
|
|
if y, err :=
|
|
lp.NewMessage(
|
|
"ib_total_pkts",
|
|
info.tagSet,
|
|
m.meta,
|
|
map[string]interface{}{
|
|
"value": ib_total_pkts,
|
|
},
|
|
now); err == nil {
|
|
y.AddMeta("unit", "packets")
|
|
output <- y
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (m *InfinibandCollector) Close() {
|
|
m.init = false
|
|
}
|