mirror of
				https://github.com/ClusterCockpit/cc-metric-collector.git
				synced 2025-11-04 10:45:06 +01:00 
			
		
		
		
	added beegfs collectors and docs
This commit is contained in:
		
							
								
								
									
										207
									
								
								collectors/beegfsmetaMetric.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										207
									
								
								collectors/beegfsmetaMetric.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,207 @@
 | 
			
		||||
package collectors
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
	"os/user"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	lp "github.com/ClusterCockpit/cc-metric-collector/internal/ccMetric"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Struct for the collector-specific JSON config
 | 
			
		||||
type BeegfsMetaCollectorConfig struct {
 | 
			
		||||
	Beegfs            string   `json:"beegfs_path"`
 | 
			
		||||
	ExcludeMetrics    []string `json:"exclude_metrics,omitempty"`
 | 
			
		||||
	ExcludeFilesystem []string `json:"exclude_filesystem"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type BeegfsMetaCollector struct {
 | 
			
		||||
	metricCollector
 | 
			
		||||
	tags    map[string]string
 | 
			
		||||
	matches map[string]string
 | 
			
		||||
	config  BeegfsMetaCollectorConfig
 | 
			
		||||
	skipFS  map[string]struct{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *BeegfsMetaCollector) Init(config json.RawMessage) error {
 | 
			
		||||
	// Check if already initialized
 | 
			
		||||
	if m.init {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	// Metrics
 | 
			
		||||
	var nodeMdstat_array = [39]string{
 | 
			
		||||
		"sum", "ack", "close", "entInf",
 | 
			
		||||
		"fndOwn", "mkdir", "create", "rddir",
 | 
			
		||||
		"refrEn", "mdsInf", "rmdir", "rmLnk",
 | 
			
		||||
		"mvDirIns", "mvFiIns", "open", "ren",
 | 
			
		||||
		"sChDrct", "sAttr", "sDirPat", "stat",
 | 
			
		||||
		"statfs", "trunc", "symlnk", "unlnk",
 | 
			
		||||
		"lookLI", "statLI", "revalLI", "openLI",
 | 
			
		||||
		"createLI", "hardlnk", "flckAp", "flckEn",
 | 
			
		||||
		"flckRg", "dirparent", "listXA", "getXA",
 | 
			
		||||
		"rmXA", "setXA", "mirror"}
 | 
			
		||||
 | 
			
		||||
	m.name = "BeegfsMetaCollector"
 | 
			
		||||
	m.setup()
 | 
			
		||||
	// Set default beegfs-ctl binary
 | 
			
		||||
 | 
			
		||||
	m.config.Beegfs = "/usr/bin/beegfs-ctl"
 | 
			
		||||
 | 
			
		||||
	// Read JSON configuration
 | 
			
		||||
	if len(config) > 0 {
 | 
			
		||||
		err := json.Unmarshal(config, &m.config)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	println(m.config.Beegfs)
 | 
			
		||||
	//create map with possible variables
 | 
			
		||||
	m.matches = make(map[string]string)
 | 
			
		||||
	for _, value := range nodeMdstat_array {
 | 
			
		||||
		_, skip := stringArrayContains(m.config.ExcludeMetrics, value)
 | 
			
		||||
		if skip {
 | 
			
		||||
			m.matches["other"] = "0"
 | 
			
		||||
		} else {
 | 
			
		||||
			m.matches[value] = "0"
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m.meta = map[string]string{
 | 
			
		||||
		"source": m.name,
 | 
			
		||||
		"group":  "BeegfsMeta",
 | 
			
		||||
	}
 | 
			
		||||
	m.tags = map[string]string{
 | 
			
		||||
		"type":       "node",
 | 
			
		||||
		"filesystem": "",
 | 
			
		||||
	}
 | 
			
		||||
	m.skipFS = make(map[string]struct{})
 | 
			
		||||
	for _, fs := range m.config.ExcludeFilesystem {
 | 
			
		||||
		m.skipFS[fs] = struct{}{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Beegfs file system statistics can only be queried by user root
 | 
			
		||||
	user, err := user.Current()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("BeegfsMetaCollector.Init(): Failed to get current user: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if user.Uid != "0" {
 | 
			
		||||
		return fmt.Errorf("BeegfsMetaCollector.Init(): BeeGFS file system statistics can only be queried by user root")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check if beegfs-ctl is in executable search path
 | 
			
		||||
	_, err = exec.LookPath(m.config.Beegfs)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("BeegfsMetaCollector.Init(): Failed to find beegfs-ctl binary '%s': %v", m.config.Beegfs, err)
 | 
			
		||||
	}
 | 
			
		||||
	m.init = true
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *BeegfsMetaCollector) Read(interval time.Duration, output chan lp.CCMetric) {
 | 
			
		||||
	if !m.init {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	//get mounpoint
 | 
			
		||||
	buffer, _ := ioutil.ReadFile(string("/proc/mounts"))
 | 
			
		||||
	mounts := strings.Split(string(buffer), "\n")
 | 
			
		||||
	var mountpoint string
 | 
			
		||||
	for _, line := range mounts {
 | 
			
		||||
		if len(line) == 0 {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		f := strings.Fields(line)
 | 
			
		||||
		if strings.Contains(f[0], "beegfs_ondemand") {
 | 
			
		||||
			// Skip excluded filesystems
 | 
			
		||||
			if _, skip := m.skipFS[mountpoint]; skip {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			mountpoint = f[1]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	m.tags["filesystem"] = mountpoint
 | 
			
		||||
 | 
			
		||||
	// bwwgfs-ctl:
 | 
			
		||||
	// --clientstats: Show client IO statistics.
 | 
			
		||||
	// --nodetype=meta: The node type to query (meta, storage).
 | 
			
		||||
	// --interval:
 | 
			
		||||
	// --mount=/mnt/beeond/: Which mount point
 | 
			
		||||
	//cmd := exec.Command(m.config.Beegfs, "/root/mc/test.txt")
 | 
			
		||||
	mountoption := "--mount=" + mountpoint
 | 
			
		||||
	cmd := exec.Command(m.config.Beegfs, "--clientstats",
 | 
			
		||||
		"--nodetype=meta", mountoption, "--allstats")
 | 
			
		||||
	cmd.Stdin = strings.NewReader("\n")
 | 
			
		||||
	cmdStdout := new(bytes.Buffer)
 | 
			
		||||
	cmdStderr := new(bytes.Buffer)
 | 
			
		||||
	cmd.Stdout = cmdStdout
 | 
			
		||||
	cmd.Stderr = cmdStderr
 | 
			
		||||
	err := cmd.Run()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "BeegfsMetaCollector.Read(): Failed to execute command \"%s\": %s\n", cmd.String(), err.Error())
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "BeegfsMetaCollector.Read(): command exit code: \"%d\"\n", cmd.ProcessState.ExitCode())
 | 
			
		||||
		data, _ := ioutil.ReadAll(cmdStderr)
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "BeegfsMetaCollector.Read(): command stderr: \"%s\"\n", string(data))
 | 
			
		||||
		data, _ = ioutil.ReadAll(cmdStdout)
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "BeegfsMetaCollector.Read(): command stdout: \"%s\"\n", string(data))
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	// Read I/O statistics
 | 
			
		||||
	scanner := bufio.NewScanner(cmdStdout)
 | 
			
		||||
 | 
			
		||||
	sumLine := regexp.MustCompile(`^Sum:\s+\d+\s+\[[a-zA-Z]+\]+`)
 | 
			
		||||
	//Line := regexp.MustCompile(`^(.*)\s+(\d)+\s+\[([a-zA-Z]+)\]+`)
 | 
			
		||||
	statsLine := regexp.MustCompile(`^(.*?)\s+?(\d.*?)$`)
 | 
			
		||||
	singleSpacePattern := regexp.MustCompile(`\s+`)
 | 
			
		||||
	removePattern := regexp.MustCompile(`[\[|\]]`)
 | 
			
		||||
 | 
			
		||||
	for scanner.Scan() {
 | 
			
		||||
		readLine := scanner.Text()
 | 
			
		||||
		//fmt.Println(readLine)
 | 
			
		||||
		// Jump few lines, we only want the I/O stats from nodes
 | 
			
		||||
		if !sumLine.MatchString(readLine) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		match := statsLine.FindStringSubmatch(readLine)
 | 
			
		||||
		// nodeName = "Sum:" or would be nodes
 | 
			
		||||
		// nodeName := match[1]
 | 
			
		||||
		//Remove multiple whitespaces
 | 
			
		||||
		dummy := removePattern.ReplaceAllString(match[2], " ")
 | 
			
		||||
		metaStats := strings.TrimSpace(singleSpacePattern.ReplaceAllString(dummy, " "))
 | 
			
		||||
		split := strings.Split(metaStats, " ")
 | 
			
		||||
 | 
			
		||||
		// fill map with values
 | 
			
		||||
		// split[i+1] = mdname
 | 
			
		||||
		// split[i] = amount of md operations
 | 
			
		||||
		for i := 0; i <= len(split)-1; i += 2 {
 | 
			
		||||
			if _, ok := m.matches[split[i+1]]; ok {
 | 
			
		||||
				m.matches[split[i+1]] = split[i]
 | 
			
		||||
			} else {
 | 
			
		||||
				f1, _ := strconv.ParseFloat(m.matches["other"], 32)
 | 
			
		||||
				f2, _ := strconv.ParseFloat(split[i], 32)
 | 
			
		||||
				//mdStat["other"] = fmt.Sprintf("%f", f1+f2)
 | 
			
		||||
				m.matches["other"] = fmt.Sprintf("%f", f1+f2)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for key, data := range m.matches {
 | 
			
		||||
			value, _ := strconv.ParseFloat(data, 32)
 | 
			
		||||
			y, err := lp.New(key, m.tags, m.meta, map[string]interface{}{"value": value}, time.Now())
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				output <- y
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *BeegfsMetaCollector) Close() {
 | 
			
		||||
	m.init = false
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										70
									
								
								collectors/beegfsmetaMetric.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								collectors/beegfsmetaMetric.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
			
		||||
## `BeeGFS on Demand` collector
 | 
			
		||||
This Collector is to collect BeeGFS on Demand (BeeOND) metadata clientstats.
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
  "beegfs_meta": {
 | 
			
		||||
	"beegfs_path": "/usr/bin/beegfs-ctl",
 | 
			
		||||
    "exclude_filesystem": [
 | 
			
		||||
      "/mnt/ignore_me"
 | 
			
		||||
    ],
 | 
			
		||||
    "exclude_metrics": [     
 | 
			
		||||
          "ack",
 | 
			
		||||
          "entInf",
 | 
			
		||||
          "fndOwn"
 | 
			
		||||
  }
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `BeeGFS On Demand (BeeOND)` collector uses the `beegfs-ctl` command to read performance metrics for
 | 
			
		||||
BeeGFS filesystems.
 | 
			
		||||
 | 
			
		||||
The reported filesystems can be filtered with the `exclude_filesystem` option
 | 
			
		||||
in the configuration.
 | 
			
		||||
 | 
			
		||||
The path to the `beegfs-ctl` command can be configured with the `beegfs_path` option
 | 
			
		||||
in the configuration.
 | 
			
		||||
 | 
			
		||||
When using the `exclude_metrics` option, the excluded metrics are summed as `other`.
 | 
			
		||||
 | 
			
		||||
Available Metrics:
 | 
			
		||||
 | 
			
		||||
* sum
 | 
			
		||||
* ack
 | 
			
		||||
* close
 | 
			
		||||
* entInf
 | 
			
		||||
* fndOwn
 | 
			
		||||
* mkdir
 | 
			
		||||
* create
 | 
			
		||||
* rddir
 | 
			
		||||
* refrEnt
 | 
			
		||||
* mdsInf
 | 
			
		||||
* rmdir
 | 
			
		||||
* rmLnk
 | 
			
		||||
* mvDirIns
 | 
			
		||||
* mvFiIns
 | 
			
		||||
* open
 | 
			
		||||
* ren
 | 
			
		||||
* sChDrct
 | 
			
		||||
* sAttr
 | 
			
		||||
* sDirPat
 | 
			
		||||
* stat
 | 
			
		||||
* statfs
 | 
			
		||||
* trunc
 | 
			
		||||
* symlnk
 | 
			
		||||
* unlnk
 | 
			
		||||
* lookLI
 | 
			
		||||
* statLI
 | 
			
		||||
* revalLI
 | 
			
		||||
* openLI
 | 
			
		||||
* createLI
 | 
			
		||||
* hardlnk
 | 
			
		||||
* flckAp
 | 
			
		||||
* flckEn
 | 
			
		||||
* flckRg
 | 
			
		||||
* dirparent
 | 
			
		||||
* listXA
 | 
			
		||||
* getXA
 | 
			
		||||
* rmXA
 | 
			
		||||
* setXA
 | 
			
		||||
* mirror
 | 
			
		||||
 | 
			
		||||
The collector adds a `filesystem` tag to all metrics
 | 
			
		||||
							
								
								
									
										201
									
								
								collectors/beegfsstorageMetric.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								collectors/beegfsstorageMetric.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,201 @@
 | 
			
		||||
package collectors
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
	"os/user"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	lp "github.com/ClusterCockpit/cc-metric-collector/internal/ccMetric"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Struct for the collector-specific JSON config
 | 
			
		||||
type BeegfsStorageCollectorConfig struct {
 | 
			
		||||
	Beegfs            string   `json:"beegfs_path"`
 | 
			
		||||
	ExcludeMetrics    []string `json:"exclude_metrics,omitempty"`
 | 
			
		||||
	ExcludeFilesystem []string `json:"exclude_filesystem"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type BeegfsStorageCollector struct {
 | 
			
		||||
	metricCollector
 | 
			
		||||
	tags    map[string]string
 | 
			
		||||
	matches map[string]string
 | 
			
		||||
	config  BeegfsStorageCollectorConfig
 | 
			
		||||
	skipFS  map[string]struct{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *BeegfsStorageCollector) Init(config json.RawMessage) error {
 | 
			
		||||
	// Check if already initialized
 | 
			
		||||
	if m.init {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	// Metrics
 | 
			
		||||
	var storageStat_array = [18]string{
 | 
			
		||||
		"sum", "ack", "sChDrct", "getFSize",
 | 
			
		||||
		"sAttr", "statfs", "trunc", "close",
 | 
			
		||||
		"fsync", "ops-rd", "MiB-rd/s", "ops-wr",
 | 
			
		||||
		"MiB-wr/s", "gendbg", "hrtbeat", "remNode",
 | 
			
		||||
		"storInf", "unlnk"}
 | 
			
		||||
 | 
			
		||||
	m.name = "BeegfsStorageCollector"
 | 
			
		||||
	m.setup()
 | 
			
		||||
	// Set default beegfs-ctl binary
 | 
			
		||||
 | 
			
		||||
	m.config.Beegfs = "/usr/bin/beegfs-ctl"
 | 
			
		||||
 | 
			
		||||
	// Read JSON configuration
 | 
			
		||||
	if len(config) > 0 {
 | 
			
		||||
		err := json.Unmarshal(config, &m.config)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	println(m.config.Beegfs)
 | 
			
		||||
	//create map with possible variables
 | 
			
		||||
	m.matches = make(map[string]string)
 | 
			
		||||
	for _, value := range storageStat_array {
 | 
			
		||||
		_, skip := stringArrayContains(m.config.ExcludeMetrics, value)
 | 
			
		||||
		if skip {
 | 
			
		||||
			m.matches["other"] = "0"
 | 
			
		||||
		} else {
 | 
			
		||||
			m.matches[value] = "0"
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m.meta = map[string]string{
 | 
			
		||||
		"source": m.name,
 | 
			
		||||
		"group":  "BeegfsStorage",
 | 
			
		||||
	}
 | 
			
		||||
	m.tags = map[string]string{
 | 
			
		||||
		"type":       "node",
 | 
			
		||||
		"filesystem": "",
 | 
			
		||||
	}
 | 
			
		||||
	m.skipFS = make(map[string]struct{})
 | 
			
		||||
	for _, fs := range m.config.ExcludeFilesystem {
 | 
			
		||||
		m.skipFS[fs] = struct{}{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Beegfs file system statistics can only be queried by user root
 | 
			
		||||
	user, err := user.Current()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("BeegfsStorageCollector.Init(): Failed to get current user: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if user.Uid != "0" {
 | 
			
		||||
		return fmt.Errorf("BeegfsStorageCollector.Init(): BeeGFS file system statistics can only be queried by user root")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check if beegfs-ctl is in executable search path
 | 
			
		||||
	_, err = exec.LookPath(m.config.Beegfs)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("BeegfsStorageCollector.Init(): Failed to find beegfs-ctl binary '%s': %v", m.config.Beegfs, err)
 | 
			
		||||
	}
 | 
			
		||||
	m.init = true
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *BeegfsStorageCollector) Read(interval time.Duration, output chan lp.CCMetric) {
 | 
			
		||||
	if !m.init {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	//get mounpoint
 | 
			
		||||
	buffer, _ := ioutil.ReadFile(string("/proc/mounts"))
 | 
			
		||||
	mounts := strings.Split(string(buffer), "\n")
 | 
			
		||||
	var mountpoint string
 | 
			
		||||
	for _, line := range mounts {
 | 
			
		||||
		if len(line) == 0 {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		f := strings.Fields(line)
 | 
			
		||||
		if strings.Contains(f[0], "beegfs_ondemand") {
 | 
			
		||||
			// Skip excluded filesystems
 | 
			
		||||
			if _, skip := m.skipFS[mountpoint]; skip {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			mountpoint = f[1]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	m.tags["filesystem"] = mountpoint
 | 
			
		||||
 | 
			
		||||
	// bwwgfs-ctl:
 | 
			
		||||
	// --clientstats: Show client IO statistics.
 | 
			
		||||
	// --nodetype=meta: The node type to query (meta, storage).
 | 
			
		||||
	// --interval:
 | 
			
		||||
	// --mount=/mnt/beeond/: Which mount point
 | 
			
		||||
	//cmd := exec.Command(m.config.Beegfs, "/root/mc/test.txt")
 | 
			
		||||
	mountoption := "--mount=" + mountpoint
 | 
			
		||||
	cmd := exec.Command(m.config.Beegfs, "--clientstats",
 | 
			
		||||
		"--nodetype=storage", mountoption, "--allstats")
 | 
			
		||||
	cmd.Stdin = strings.NewReader("\n")
 | 
			
		||||
	cmdStdout := new(bytes.Buffer)
 | 
			
		||||
	cmdStderr := new(bytes.Buffer)
 | 
			
		||||
	cmd.Stdout = cmdStdout
 | 
			
		||||
	cmd.Stderr = cmdStderr
 | 
			
		||||
	err := cmd.Run()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "BeegfsStorageCollector.Read(): Failed to execute command \"%s\": %s\n", cmd.String(), err.Error())
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "BeegfsStorageCollector.Read(): command exit code: \"%d\"\n", cmd.ProcessState.ExitCode())
 | 
			
		||||
		data, _ := ioutil.ReadAll(cmdStderr)
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "BeegfsStorageCollector.Read(): command stderr: \"%s\"\n", string(data))
 | 
			
		||||
		data, _ = ioutil.ReadAll(cmdStdout)
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "BeegfsStorageCollector.Read(): command stdout: \"%s\"\n", string(data))
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	// Read I/O statistics
 | 
			
		||||
	scanner := bufio.NewScanner(cmdStdout)
 | 
			
		||||
 | 
			
		||||
	sumLine := regexp.MustCompile(`^Sum:\s+\d+\s+\[[a-zA-Z]+\]+`)
 | 
			
		||||
	//Line := regexp.MustCompile(`^(.*)\s+(\d)+\s+\[([a-zA-Z]+)\]+`)
 | 
			
		||||
	statsLine := regexp.MustCompile(`^(.*?)\s+?(\d.*?)$`)
 | 
			
		||||
	singleSpacePattern := regexp.MustCompile(`\s+`)
 | 
			
		||||
	removePattern := regexp.MustCompile(`[\[|\]]`)
 | 
			
		||||
 | 
			
		||||
	for scanner.Scan() {
 | 
			
		||||
		readLine := scanner.Text()
 | 
			
		||||
		//fmt.Println(readLine)
 | 
			
		||||
		// Jump few lines, we only want the I/O stats from nodes
 | 
			
		||||
		if !sumLine.MatchString(readLine) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		match := statsLine.FindStringSubmatch(readLine)
 | 
			
		||||
		// nodeName = "Sum:" or would be nodes
 | 
			
		||||
		// nodeName := match[1]
 | 
			
		||||
		//Remove multiple whitespaces
 | 
			
		||||
		dummy := removePattern.ReplaceAllString(match[2], " ")
 | 
			
		||||
		metaStats := strings.TrimSpace(singleSpacePattern.ReplaceAllString(dummy, " "))
 | 
			
		||||
		split := strings.Split(metaStats, " ")
 | 
			
		||||
 | 
			
		||||
		// fill map with values
 | 
			
		||||
		// split[i+1] = mdname
 | 
			
		||||
		// split[i] = amount of operations
 | 
			
		||||
		for i := 0; i <= len(split)-1; i += 2 {
 | 
			
		||||
			if _, ok := m.matches[split[i+1]]; ok {
 | 
			
		||||
				m.matches[split[i+1]] = split[i]
 | 
			
		||||
			} else {
 | 
			
		||||
				f1, _ := strconv.ParseFloat(m.matches["other"], 32)
 | 
			
		||||
				f2, _ := strconv.ParseFloat(split[i], 32)
 | 
			
		||||
				m.matches["other"] = fmt.Sprintf("%f", f1+f2)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for key, data := range m.matches {
 | 
			
		||||
			value, _ := strconv.ParseFloat(data, 32)
 | 
			
		||||
			y, err := lp.New(key, m.tags, m.meta, map[string]interface{}{"value": value}, time.Now())
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				output <- y
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *BeegfsStorageCollector) Close() {
 | 
			
		||||
	m.init = false
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										49
									
								
								collectors/beegfsstorageMetric.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								collectors/beegfsstorageMetric.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
## `BeeGFS on Demand` collector
 | 
			
		||||
This Collector is to collect BeeGFS on Demand (BeeOND) storage stats.
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
  "beegfs_storage": {
 | 
			
		||||
	"beegfs_path": "/usr/bin/beegfs-ctl",
 | 
			
		||||
    "exclude_filesystem": [
 | 
			
		||||
      "/mnt/ignore_me"
 | 
			
		||||
    ],
 | 
			
		||||
    "exclude_metrics": [     
 | 
			
		||||
          "ack",
 | 
			
		||||
		  "storInf",
 | 
			
		||||
		  "unlnk"
 | 
			
		||||
  }
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `BeeGFS On Demand (BeeOND)` collector uses the `beegfs-ctl` command to read performance metrics for BeeGFS filesystems.
 | 
			
		||||
 | 
			
		||||
The reported filesystems can be filtered with the `exclude_filesystem` option
 | 
			
		||||
in the configuration.
 | 
			
		||||
 | 
			
		||||
The path to the `beegfs-ctl` command can be configured with the `beegfs_path` option
 | 
			
		||||
in the configuration.
 | 
			
		||||
 | 
			
		||||
When using the `exclude_metrics` option, the excluded metrics are summed as `other`.
 | 
			
		||||
 | 
			
		||||
Available Metrics:
 | 
			
		||||
 | 
			
		||||
* "sum"
 | 
			
		||||
* "ack"
 | 
			
		||||
* "sChDrct" 
 | 
			
		||||
* "getFSize"
 | 
			
		||||
* "sAttr"
 | 
			
		||||
* "statfs"
 | 
			
		||||
* "trunc"
 | 
			
		||||
* "close"
 | 
			
		||||
* "fsync"
 | 
			
		||||
* "ops-rd"
 | 
			
		||||
* "MiB-rd/s" 
 | 
			
		||||
* "ops-wr"
 | 
			
		||||
* "MiB-wr/s" 
 | 
			
		||||
* "endbg" 
 | 
			
		||||
* "hrtbeat"
 | 
			
		||||
* "remNode"
 | 
			
		||||
* "storInf"
 | 
			
		||||
* "unlnk"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
The collector adds a `filesystem` tag to all metrics
 | 
			
		||||
		Reference in New Issue
	
	Block a user