Skip to content

Commit 5906c9a

Browse files
committed
added custom inspector, will probably have no chart only output
1 parent e43d61f commit 5906c9a

File tree

5 files changed

+187
-0
lines changed

5 files changed

+187
-0
lines changed

driver/ssh.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package driver
22

33
import (
44
"fmt"
5+
"strings"
56

67
"github.com/melbahja/goph"
78
log "github.com/sirupsen/logrus"
@@ -25,6 +26,8 @@ type SSH struct {
2526
KeyPass string
2627
// Check known hosts (only disable for tests
2728
CheckKnownHosts bool
29+
// set environmental vars for server e.g []string{"DEBUG=1", "FAKE=echo"}
30+
Vars []string
2831
}
2932

3033
func (d *SSH) String() string {
@@ -76,6 +79,11 @@ func (d *SSH) RunCommand(command string) (string, error) {
7679
return ``, err
7780
}
7881
defer client.Close()
82+
if len(d.Vars) != 0 {
83+
// add env variable to command
84+
envline := strings.Join(d.Vars, ";")
85+
command = strings.Join([]string{envline, command}, ";")
86+
}
7987
out, err := client.Run(command)
8088
if err != nil {
8189
return ``, err

inspector/custom.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package inspector
2+
3+
import (
4+
log "github.com/sirupsen/logrus"
5+
)
6+
7+
// CustomMetrics : Metrics used by DF
8+
type CustomMetrics struct {
9+
Output string
10+
}
11+
12+
// Custom : Parsing the `df` output for disk monitoring
13+
type Custom struct {
14+
fields
15+
Values CustomMetrics
16+
}
17+
18+
// Parse : run custom parsing on output of the command
19+
func (i *Custom) Parse(output string) {
20+
log.Debug("Parsing ouput string in Custom inspector")
21+
i.Values = i.createMetric(output)
22+
}
23+
24+
func (i Custom) createMetric(output string) CustomMetrics {
25+
return CustomMetrics{
26+
Output: output,
27+
}
28+
}
29+
30+
// NewCustom : Initialize a new Custom instance
31+
func NewCustom(custom string) *Custom {
32+
return &Custom{
33+
fields: fields{
34+
Type: Command,
35+
Command: custom,
36+
},
37+
}
38+
39+
}

inspector/process.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,93 @@
11
package inspector
2+
3+
import (
4+
log "github.com/sirupsen/logrus"
5+
"strconv"
6+
"strings"
7+
)
8+
9+
// ProcessMetrics : Metrics used by Process
10+
type ProcessMetrics struct {
11+
Command string
12+
User string
13+
Pid int
14+
// Percentage value of CPU used
15+
CPU float64
16+
// Percentage value of memory used
17+
Memory float64
18+
// Number of seconds the process has been running
19+
Time int64
20+
TTY string
21+
}
22+
23+
// Process : Parsing the `ps -A u` output for process monitoring
24+
type Process struct {
25+
fields
26+
// Track this particular PID
27+
TrackPID int
28+
// Values of metrics being read
29+
Values []ProcessMetrics
30+
}
31+
32+
// Parse : run custom parsing on output of the command
33+
func (i *Process) Parse(output string) {
34+
var values []ProcessMetrics
35+
lines := strings.Split(output, "\n")
36+
for index, line := range lines {
37+
// skip title line
38+
if index == 0 {
39+
continue
40+
}
41+
columns := strings.Fields(line)
42+
if len(columns) >= 10 {
43+
pid, err := strconv.Atoi(columns[1])
44+
if err != nil {
45+
log.Fatal("Could not parse pid in Process")
46+
}
47+
// If we are tracking only a particular ID then break loop
48+
if i.TrackPID != 0 && i.TrackPID == pid {
49+
value := i.createMetric(columns, pid)
50+
values = append(values, value)
51+
break
52+
} else if i.TrackPID == 0 {
53+
value := i.createMetric(columns, pid)
54+
values = append(values, value)
55+
}
56+
}
57+
}
58+
i.Values = values
59+
}
60+
61+
func (i Process) createMetric(columns []string, pid int) ProcessMetrics {
62+
var parseErr error
63+
cpu, parseErr := strconv.ParseFloat(columns[2], 64)
64+
mem, parseErr := strconv.ParseFloat(columns[3], 64)
65+
unparsedTime := columns[9]
66+
tty := columns[6]
67+
minutesStr := strings.Split(unparsedTime, ":")
68+
minute, parseErr := strconv.Atoi(minutesStr[0])
69+
second, parseErr := strconv.Atoi(minutesStr[1])
70+
if parseErr != nil {
71+
log.Fatal(parseErr)
72+
}
73+
74+
return ProcessMetrics{
75+
Command: strings.Join(columns[10:], " "),
76+
User: columns[0],
77+
CPU: cpu,
78+
Memory: mem,
79+
Time: int64((minute * 60) + second),
80+
TTY: tty,
81+
}
82+
}
83+
84+
// NewProcess : Initialize a new Process instance
85+
func NewProcess() *Process {
86+
return &Process{
87+
fields: fields{
88+
Type: Command,
89+
Command: `ps -A u`,
90+
},
91+
}
92+
93+
}

integration/integration_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package integration
22

33
import (
44
"fmt"
5+
"strings"
56
"testing"
67

78
"github.com/bisoncorps/saido/driver"
@@ -46,3 +47,31 @@ func TestResponseTimeonWeb(t *testing.T) {
4647
}
4748
fmt.Printf(`%#v`, i.Values)
4849
}
50+
51+
func TestProcessonSSH(t *testing.T) {
52+
d := driver.NewSSHForTest()
53+
i := inspector.NewProcess()
54+
output, err := d.RunCommand(i.String())
55+
if err != nil {
56+
t.Error(err)
57+
}
58+
i.Parse(output)
59+
if len(i.Values) <= 2 {
60+
t.Error(err)
61+
}
62+
}
63+
64+
func TestCustomonSSH(t *testing.T) {
65+
d := driver.NewSSHForTest()
66+
// set vars
67+
d.Vars = []string{"MONKEY=true"}
68+
i := inspector.NewCustom(`echo $MONKEY`)
69+
output, err := d.RunCommand(i.String())
70+
if err != nil {
71+
t.Error(err)
72+
}
73+
i.Parse(output)
74+
if strings.TrimSpace(i.Values.Output) != "true" {
75+
t.Errorf("%s", i.Values.Output)
76+
}
77+
}

integration/integration_unix_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,22 @@ func TestDockerStatsonLocal(t *testing.T) {
5454
}
5555
fmt.Printf(`%#v`, i.Values)
5656
}
57+
58+
func TestProcessonLocal(t *testing.T) {
59+
d := driver.Local{}
60+
i := inspector.NewProcess()
61+
output, err := d.RunCommand(i.String())
62+
if err != nil {
63+
t.Error(err)
64+
}
65+
i.Parse(output)
66+
if len(i.Values) <= 2 {
67+
t.Error(err)
68+
}
69+
// Track just root PID of 1
70+
i.TrackPID = 1
71+
i.Parse(output)
72+
if len(i.Values) != 1 {
73+
t.Error("unexpected size of single PID tracking")
74+
}
75+
}

0 commit comments

Comments
 (0)