Compare commits

..

1 Commits

Author SHA1 Message Date
Thomas Roehl
b77d9a6cf0 Add include configuration to diskstat collector 2025-12-19 17:32:54 +01:00
2 changed files with 102 additions and 16 deletions

View File

@@ -23,13 +23,22 @@ const MOUNTFILE = `/proc/self/mounts`
type DiskstatCollectorConfig struct { type DiskstatCollectorConfig struct {
ExcludeMetrics []string `json:"exclude_metrics,omitempty"` ExcludeMetrics []string `json:"exclude_metrics,omitempty"`
ExcludeMounts []string `json:"exclude_mounts,omitempty"` ExcludeDevices []string `json:"exclude_devices,omitempty"`
ExcludeMountpoints []string `json:"exclude_mountpoints,omitempty"`
IncludeDevices []string `json:"include_devices,omitempty"`
IncludeMountpoints []string `json:"include_mountpoints,omitempty"`
UseMountpoint bool `json:"mountpoint_as_stype,omitempty"`
UseIncludeConfig bool `json:"use_include_config,omitempty"`
} }
type DiskstatCollector struct { type DiskstatCollector struct {
metricCollector metricCollector
config DiskstatCollectorConfig config DiskstatCollectorConfig
allowedMetrics map[string]bool allowedMetrics map[string]bool
includeDevices map[string]bool
includeMountpoints map[string]bool
excludeDevices map[string]bool
excludeMountpoints map[string]bool
} }
func (m *DiskstatCollector) Init(config json.RawMessage) error { func (m *DiskstatCollector) Init(config json.RawMessage) error {
@@ -37,6 +46,7 @@ func (m *DiskstatCollector) Init(config json.RawMessage) error {
m.parallel = true m.parallel = true
m.meta = map[string]string{"source": m.name, "group": "Disk"} m.meta = map[string]string{"source": m.name, "group": "Disk"}
m.setup() m.setup()
m.config.UseIncludeConfig = false
if len(config) > 0 { if len(config) > 0 {
if err := json.Unmarshal(config, &m.config); err != nil { if err := json.Unmarshal(config, &m.config); err != nil {
return err return err
@@ -52,12 +62,50 @@ func (m *DiskstatCollector) Init(config json.RawMessage) error {
m.allowedMetrics[excl] = false m.allowedMetrics[excl] = false
} }
} }
file, err := os.Open(MOUNTFILE) file, err := os.Open(MOUNTFILE)
if err != nil { if err != nil {
cclog.ComponentError(m.name, err.Error()) cclog.ComponentError(m.name, err.Error())
return err return err
} }
defer file.Close() defer file.Close()
availDevices := make(map[string]struct{})
availMpoints := make(map[string]struct{})
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
if len(line) == 0 {
continue
}
linefields := strings.Fields(line)
availDevices[linefields[0]] = struct{}{}
availMpoints[linefields[1]] = struct{}{}
}
m.includeDevices = make(map[string]bool)
for _, incl := range m.config.IncludeDevices {
if _, ok := availDevices[incl]; ok {
m.includeDevices[incl] = true
} else {
cclog.ComponentWarn(m.name, "Included Mount device ", incl, " does not exist")
}
}
m.includeMountpoints = make(map[string]bool)
for _, incl := range m.config.IncludeMountpoints {
if _, ok := availMpoints[incl]; ok {
m.includeMountpoints[incl] = true
} else {
cclog.ComponentWarn(m.name, "Included Mount point ", incl, " does not exist")
}
}
m.excludeMountpoints = make(map[string]bool)
for _, excl := range m.config.ExcludeMountpoints {
m.excludeMountpoints[excl] = true
}
m.excludeDevices = make(map[string]bool)
for _, excl := range m.config.ExcludeDevices {
m.excludeDevices[excl] = true
}
m.init = true m.init = true
return nil return nil
} }
@@ -75,6 +123,8 @@ func (m *DiskstatCollector) Read(interval time.Duration, output chan lp.CCMessag
defer file.Close() defer file.Close()
part_max_used := uint64(0) part_max_used := uint64(0)
part_max_used_device := ""
part_max_used_mountpoint := ""
scanner := bufio.NewScanner(file) scanner := bufio.NewScanner(file)
mountLoop: mountLoop:
for scanner.Scan() { for scanner.Scan() {
@@ -82,9 +132,9 @@ mountLoop:
if len(line) == 0 { if len(line) == 0 {
continue continue
} }
if !strings.HasPrefix(line, "/dev") { // if !strings.HasPrefix(line, "/dev") {
continue // continue
} // }
linefields := strings.Fields(line) linefields := strings.Fields(line)
if strings.Contains(linefields[0], "loop") { if strings.Contains(linefields[0], "loop") {
continue continue
@@ -95,8 +145,16 @@ mountLoop:
mountPath := strings.Replace(linefields[1], `\040`, " ", -1) mountPath := strings.Replace(linefields[1], `\040`, " ", -1)
for _, excl := range m.config.ExcludeMounts { if m.config.UseIncludeConfig {
if strings.Contains(mountPath, excl) { _, ok1 := m.includeDevices[linefields[0]]
_, ok2 := m.includeMountpoints[linefields[1]]
if !(ok1 || ok2) {
continue mountLoop
}
} else {
_, ok1 := m.excludeDevices[linefields[0]]
_, ok2 := m.excludeMountpoints[linefields[1]]
if ok1 || ok2 {
continue mountLoop continue mountLoop
} }
} }
@@ -109,7 +167,10 @@ mountLoop:
if stat.Blocks == 0 || stat.Bsize == 0 { if stat.Blocks == 0 || stat.Bsize == 0 {
continue continue
} }
tags := map[string]string{"type": "node", "device": linefields[0]} tags := map[string]string{"type": "node", "stype": "filesystem", "stype-id": linefields[0]}
if m.config.UseMountpoint {
tags["stype-id"] = linefields[1]
}
total := (stat.Blocks * uint64(stat.Bsize)) / uint64(1000000000) total := (stat.Blocks * uint64(stat.Bsize)) / uint64(1000000000)
if m.allowedMetrics["disk_total"] { if m.allowedMetrics["disk_total"] {
y, err := lp.NewMessage("disk_total", tags, m.meta, map[string]interface{}{"value": total}, time.Now()) y, err := lp.NewMessage("disk_total", tags, m.meta, map[string]interface{}{"value": total}, time.Now())
@@ -130,11 +191,17 @@ mountLoop:
perc := (100 * (total - free)) / total perc := (100 * (total - free)) / total
if perc > part_max_used { if perc > part_max_used {
part_max_used = perc part_max_used = perc
part_max_used_mountpoint = linefields[1]
part_max_used_device = linefields[0]
} }
} }
} }
if m.allowedMetrics["part_max_used"] { if m.allowedMetrics["part_max_used"] && len(part_max_used_mountpoint) > 0 {
y, err := lp.NewMessage("part_max_used", map[string]string{"type": "node"}, m.meta, map[string]interface{}{"value": int(part_max_used)}, time.Now()) tags := map[string]string{"type": "node", "stype": "filesystem", "stype-id": part_max_used_device}
if m.config.UseMountpoint {
tags["stype-id"] = part_max_used_mountpoint
}
y, err := lp.NewMessage("part_max_used", tags, m.meta, map[string]interface{}{"value": int(part_max_used)}, time.Now())
if err == nil { if err == nil {
y.AddMeta("unit", "percent") y.AddMeta("unit", "percent")
output <- y output <- y

View File

@@ -16,19 +16,38 @@ hugo_path: docs/reference/cc-metric-collector/collectors/diskstat.md
"exclude_metrics": [ "exclude_metrics": [
"disk_total" "disk_total"
], ],
"exclude_mounts": [ "exclude_devices": [
"slurm-tmpfs" "slurm-tmpfs"
],
"exclude_mountpoints": [
"/tmp"
],
"mountpoint_as_stype": true,
"use_include_config": false,
"include_devices": [
"/dev/sda3"
],
"include_mountpoints" : [
"/home"
] ]
} }
``` ```
The `diskstat` collector reads data from `/proc/self/mounts` and outputs a handful **node** metrics. If a metric is not required, it can be excluded from forwarding it to the sink. Additionally, any mount point containing one of the strings specified in `exclude_mounts` will be skipped during metric collection. The `diskstat` collector reads data from `/proc/self/mounts` and outputs a handful **node** metrics with `stype=filesystem,stype-id=<mountdevice>`. If a metric is not required, it can be excluded from forwarding it to the sink.
Metrics per device (with `device` tag): For sending the `mountpoint` instead of the `mountdevice` in the `stype-id`, use `mountpoint_as_stype`.
There are two ways to specify for which devices or mountpoints the collector generates metrics. It's "either ...or".
- Excluding devices and mount points using `exclude_devices` and `exclude_mountpoints`. All devices (*) will be read that are not explicitly excluded
- Include devices and mount points by setting `use_include_config:true` and using `include_devices` and `include_mountpoints`.
(*) File systems where the mount device (first column in `/proc/self/mounts`) contains `loop` are always excluded. Filesystems where the mount point (second column in `/proc/self/mounts`) contains `boot` are also always excluded.
Metrics per filesystem (with `stype=filesystem` tag and `stype-id` based on the configuration):
* `disk_total` (unit `GBytes`) * `disk_total` (unit `GBytes`)
* `disk_free` (unit `GBytes`) * `disk_free` (unit `GBytes`)
Global metrics: Global metrics (with `stype=filesystem` tag and `stype-id` pointing to the max. used filesystem device or mount point based on the configuration):
* `part_max_used` (unit `percent`) * `part_max_used` (unit `percent`)