<commit_before>package collector

import (
	"fullerite/config"
	"fullerite/metric"

	"os/exec"
	"strconv"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/prometheus/procfs"
)

// ProcStatus collector type
type ProcStatus struct {
	BaseCollector
	processName string
}

// ProcessName returns ProcStatus collectors process name
func (f ProcStatus) ProcessName() string {
	return f.processName
}

// NewProcStatus creates a new Test collector.
func NewProcStatus() *ProcStatus {
	f := new(ProcStatus)
	f.name = "ProcStatus"
	f.log = logrus.WithFields(logrus.Fields{"app": "fullerite", "pkg": "collector", "collector": "ProcStatus"})
	f.channel = make(chan metric.Metric)
	f.interval = DefaultCollectionInterval
	f.processName = ""
	return f
}

// Configure this takes a dictionary of values with which the handler can configure itself
func (f *ProcStatus) Configure(configMap map[string]interface{}) {
	if interval, exists := configMap["interval"]; exists == true {
		f.interval = config.GetAsInt(interval, DefaultCollectionInterval)
	}
	if processName, exists := configMap["processName"]; exists == true {
		f.processName = processName.(string)
	}
}

// Collect produces some random test metrics.
func (f ProcStatus) Collect() {
	for _, m := range f.procStatusMetrics() {
		f.Channel() <- m
	}
}

func procStatusPoint(name string, value float64, dimensions map[string]string) (m metric.Metric) {
	m = metric.New(name)
	m.Value = value
	m.AddDimension("collector", "fullerite")
	for k, v := range dimensions {
		m.AddDimension(k, v)
	}
	return m
}

func (f ProcStatus) getMetrics(pid string) []metric.Metric {
	i, err := strconv.Atoi(pid)
	if err != nil {
		f.log.Warnf("Error parsing pid %s: %v", pid, err)
		return nil
	}

	proc, err := procfs.NewProc(i)
	if err != nil {
		f.log.Warn("Error creating Proc: ", err)
		return nil
	}

	stat, err := proc.NewStat()
	if err != nil {
		f.log.Warn("Error getting stats: ", err)
		return nil
	}

	dim := map[string]string{
		"processName": stat.Comm,
		"pid":         pid,
	}
	ret := []metric.Metric{}

	m := procStatusPoint("VirtualMemory", float64(stat.VirtualMemory()), dim)
	ret = append(ret, m)

	return ret
}

func (f ProcStatus) procStatusMetrics() []metric.Metric {
	// Get pids
	c := exec.Command("pgrep", f.processName)
	out, err := c.Output()
	if err != nil {
		f.log.Warn("Error while getting process ids: ", err)
		return nil
	}

	ret := []metric.Metric{}

	pids := strings.Split(string(out), "\n")
	for _, pid := range pids {
		if len(pid) == 0 {
			continue
		}

		ret = append(ret, f.getMetrics(pid)...)
	}
	return ret
}<commit_msg>Remove pgrep and use procfs<commit_after>package collector

import (
	"fullerite/config"
	"fullerite/metric"

	"strconv"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/prometheus/procfs"
)

// ProcStatus collector type
type ProcStatus struct {
	BaseCollector
	processName string
}

// ProcessName returns ProcStatus collectors process name
func (f ProcStatus) ProcessName() string {
	return f.processName
}

// NewProcStatus creates a new Test collector.
func NewProcStatus() *ProcStatus {
	f := new(ProcStatus)
	f.name = "ProcStatus"
	f.log = logrus.WithFields(logrus.Fields{"app": "fullerite", "pkg": "collector", "collector": "ProcStatus"})
	f.channel = make(chan metric.Metric)
	f.interval = DefaultCollectionInterval
	f.processName = ""
	return f
}

// Configure this takes a dictionary of values with which the handler can configure itself
func (f *ProcStatus) Configure(configMap map[string]interface{}) {
	if interval, exists := configMap["interval"]; exists == true {
		f.interval = config.GetAsInt(interval, DefaultCollectionInterval)
	}
	if processName, exists := configMap["processName"]; exists == true {
		f.processName = processName.(string)
	}
}

// Collect produces some random test metrics.
func (f ProcStatus) Collect() {
	for _, m := range f.procStatusMetrics() {
		f.Channel() <- m
	}
}

func procStatusPoint(name string, value float64, dimensions map[string]string) (m metric.Metric) {
	m = metric.New(name)
	m.Value = value
	m.AddDimension("collector", "fullerite")
	for k, v := range dimensions {
		m.AddDimension(k, v)
	}
	return m
}

func (f ProcStatus) getMetrics(proc procfs.Proc) []metric.Metric {
	stat, err := proc.NewStat()
	if err != nil {
		f.log.Warn("Error getting stats: ", err)
		return nil
	}

	dim := map[string]string{
		"processName": stat.Comm,
		"pid":         strconv.Itoa(stat.PID),
	}

	ret := []metric.Metric{}

	m := procStatusPoint("VirtualMemory", float64(stat.VirtualMemory()), dim)
	ret = append(ret, m)

	return ret
}

func (f ProcStatus) procStatusMetrics() []metric.Metric {
	procs, err := procfs.AllProcs()
	if err != nil {
		f.log.Warn("Error getting processes: ", err)
		return nil
	}

	ret := []metric.Metric{}

	for _, proc := range procs {
		cmd, err := proc.CmdLine()
		if err != nil {
			f.log.Warn("Error getting command line: ", err)
			continue
		}

		if len(f.processName) == 0 || len(cmd) > 0 && strings.Contains(cmd[0], f.processName) {
			ret = append(ret, f.getMetrics(proc)...)
		}
	}

	return ret
}
{'fraction_non_alphanumeric': 0.14420803782505912, 'fraction_numerical': 0.002364066193853428, 'mean_word_length': 4.117943548387097, 'pattern_counts': {'":': 10, '<': 5, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6703795', 'n_tokens_mistral': 1811, 'n_tokens_neox': 1722, 'n_words': 461}