Skip to content

Commit

Permalink
code refactor and readme
Browse files Browse the repository at this point in the history
  • Loading branch information
pratyush.kumar committed Dec 11, 2024
1 parent 476a3b5 commit 4a52368
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 39 deletions.
54 changes: 42 additions & 12 deletions receiver/hostmetricsreceiver/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,19 @@ hostmetrics:

The available scrapers are:

| Scraper | Supported OSs | Description |
| ------------ | ---------------------------- | ------------------------------------------------------ |
| [cpu] | All except Mac<sup>[1]</sup> | CPU utilization metrics |
| [disk] | All except Mac<sup>[1]</sup> | Disk I/O metrics |
| [load] | All | CPU load metrics |
| [filesystem] | All | File System utilization metrics |
| [memory] | All | Memory utilization metrics |
| [network] | All | Network interface I/O metrics & TCP connection metrics |
| [paging] | All | Paging/Swap space utilization and I/O metrics |
| [processes] | Linux, Mac | Process count metrics |
| [process] | Linux, Windows, Mac | Per process CPU, Memory, and Disk I/O metrics |
| [system] | Linux, Windows, Mac | Miscellaneous system metrics |
| Scraper | Supported OSs | Description |
|----------------| ---------------------------- |--------------------------------------------------------|
| [cpu] | All except Mac<sup>[1]</sup> | CPU utilization metrics |
| [disk] | All except Mac<sup>[1]</sup> | Disk I/O metrics |
| [load] | All | CPU load metrics |
| [filesystem] | All | File System utilization metrics |
| [memory] | All | Memory utilization metrics |
| [network] | All | Network interface I/O metrics & TCP connection metrics |
| [paging] | All | Paging/Swap space utilization and I/O metrics |
| [processes] | Linux, Mac | Process count metrics |
| [process] | Linux, Windows, Mac | Per process CPU, Memory, and Disk I/O metrics |
| [system] | Linux, Windows, Mac | Miscellaneous system metrics |
| [groupprocess] | Linux, Windows, Mac | Per process group CPU, Memory, and Disk I/O metrics |

[cpu]: ./internal/scraper/cpuscraper/documentation.md
[disk]: ./internal/scraper/diskscraper/documentation.md
Expand All @@ -61,6 +62,7 @@ The available scrapers are:
[processes]: ./internal/scraper/processesscraper/documentation.md
[process]: ./internal/scraper/processscraper/documentation.md
[system]: ./internal/scraper/systemscraper/documentation.md
[groupprocess]: ./internal/scraper/groupprocessscraper/documentation.md

### Notes

Expand Down Expand Up @@ -134,6 +136,34 @@ The following settings are optional:
- `mute_process_exe_error` (default: false): mute the error encountered when trying to read the executable path of a process the collector does not have permission to read (Linux only). This flag is ignored when `mute_process_all_errors` is set to true as all errors are muted.
- `mute_process_user_error` (default: false): mute the error encountered when trying to read a uid which doesn't exist on the system, eg. is owned by a user that only exists in a container. This flag is ignored when `mute_process_all_errors` is set to true as all errors are muted.

### GroupProcess
The `groupprocessscraper` collects metrics for groups of processes based on user given regex configurations. This allows for more granular monitoring of specific sets of processes.

```yaml
receivers:
hostmetrics:
collection_interval: 10s
scrapers:
groupprocess:
process_configs:
- group_name: "kube_process"
comm:
names:
- "kube-proxy"
match_type: "strict"
exe:
names:
- "/usr/local/bin/kube-proxy"
match_type: "strict"
cmdline:
names:
- "--config=/var/lib/kube-proxy/config.conf"
match_type: "regexp"
```
In this example, the groupprocessscraper is configured to scrape metrics for processes that match the specified comm, exe, and cmdline criteria. The group_name is used to identify the group of processes being monitored.
For `comm` and `exe`, the list of strings is an `OR`, meaning any process matching any of the strings will be added to the process group.
For `cmdline`, the list of regexes is an `AND`, meaning they all must match.

## Advanced Configuration

### Filtering
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"context"
"errors"
"fmt"
"regexp"
"time"

"github.com/shirou/gopsutil/v4/common"
Expand Down Expand Up @@ -47,7 +48,8 @@ type scraper struct {
ucals map[int32]*ucal.CPUUtilizationCalculator
logicalCores int

matchGroupFS map[string]map[string]filterset.FilterSet
matchGroupFS map[string]map[string]filterset.FilterSet
matchGroupNames map[string][]string

// for mocking
getProcessCreateTime func(p processHandle, ctx context.Context) (int64, error)
Expand All @@ -67,6 +69,7 @@ func newGroupProcessScraper(settings receiver.Settings, cfg *Config) (*scraper,
ucals: make(map[int32]*ucal.CPUUtilizationCalculator),
handleCountManager: handlecount.NewManager(),
matchGroupFS: make(map[string]map[string]filterset.FilterSet), // Initialize the map
matchGroupNames: make(map[string][]string), // Initialize the map for cmdline names
}

var err error
Expand Down Expand Up @@ -99,11 +102,7 @@ func newGroupProcessScraper(settings receiver.Settings, cfg *Config) (*scraper,
}

if len(gc.Cmdline.Names) > 0 {
cmdlineFS, err := filterset.CreateFilterSet(gc.Cmdline.Names, &filterset.Config{MatchType: filterset.MatchType(gc.Cmdline.MatchType)})
if err != nil {
return nil, fmt.Errorf("error creating cmdline filter set: %w", err)
}
scraper.matchGroupFS[gc.ProcessName]["cmdline"] = cmdlineFS
scraper.matchGroupNames[gc.ProcessName] = gc.Cmdline.Names
}
}

Expand Down Expand Up @@ -259,15 +258,33 @@ func (s *scraper) getProcessMetadata() (map[string][]*processMetadata, error) {
errs.AddPartial(0, fmt.Errorf("error reading command for process %q (pid %v): %w", executable.name, pid, err))
}

// Debug log
fmt.Printf("PID: %d, ExecutableName: %s, ExecutablePath %s, Command: %s, CommandLine: %s, CommandLineSlice: %v\n", pid, executable.name, executable.path, command.command, command.commandLine, command.commandLineSlice)

groupConfigName := ""
for _, gc := range s.config.GroupConfig {
if matchesFilterSetString(s.matchGroupFS[gc.ProcessName]["comm"], name) {
groupConfigName = gc.ProcessName
break
} else if matchesFilterSetString(s.matchGroupFS[gc.ProcessName]["exe"], exe) {
groupConfigName = gc.ProcessName
break
} else if matchesFilterSetSlice(s.matchGroupFS[gc.ProcessName]["cmdline"], command.commandLineSlice) {
commMatched := true
exeMatched := true
cmdlineMatched := true

if s.matchGroupFS[gc.ProcessName]["comm"] == nil && s.matchGroupFS[gc.ProcessName]["exe"] == nil && s.matchGroupFS[gc.ProcessName]["cmdline"] == nil {
continue
}

if s.matchGroupFS[gc.ProcessName]["comm"] != nil {
commMatched = matchesFilterSetString(s.matchGroupFS[gc.ProcessName]["comm"], name)
fmt.Printf("commMatched: %v, name: %s\n", commMatched, name)
}
if s.matchGroupFS[gc.ProcessName]["exe"] != nil {
exeMatched = matchesFilterSetString(s.matchGroupFS[gc.ProcessName]["exe"], exe)
fmt.Printf("exeMatched: %v, exe: %s\n", exeMatched, exe)
}
if s.matchGroupFS[gc.ProcessName]["cmdline"] != nil {
cmdlineMatched = matchesFilterSetSlice(s.matchGroupNames[gc.ProcessName], command.commandLineSlice)
fmt.Printf("cmdlineMatched: %v, commandLineSlice: %v\n", cmdlineMatched, command.commandLineSlice)
}

if commMatched && exeMatched && cmdlineMatched {
groupConfigName = gc.ProcessName
break
}
Expand All @@ -277,9 +294,6 @@ func (s *scraper) getProcessMetadata() (map[string][]*processMetadata, error) {
continue
}

// Debug log
fmt.Printf("PID: %d, ExecutableName: %s, ExecutablePath %s, Command: %s, CommandLine: %s, CommandLineSlice: %v\n", pid, executable.name, executable.path, command.command, command.commandLine, command.commandLineSlice)

username, err := handle.UsernameWithContext(ctx)
if err != nil {
if !s.config.MuteProcessUserError {
Expand Down Expand Up @@ -320,20 +334,25 @@ func (s *scraper) getProcessMetadata() (map[string][]*processMetadata, error) {
}

func matchesFilterSetString(fs filterset.FilterSet, value string) bool {
if fs == nil {
return false
}
return fs.Matches(value)
}

func matchesFilterSetSlice(fs filterset.FilterSet, values []string) bool {
if fs == nil {
return false
}
for _, value := range values {
if fs.Matches(value) {
return true
func matchesFilterSetSlice(names []string, values []string) bool {
for _, name := range names {
matched := false
re, err := regexp.Compile(name)
if err != nil {
continue // Skip invalid regex patterns
}
for _, value := range values {
if re.MatchString(value) {
matched = true
break
}
}
if !matched {
return false
}
}
return false
return true
}

0 comments on commit 4a52368

Please sign in to comment.