Compare commits

...

33 commits

Author SHA1 Message Date
Augusto Dwenger J. 381dd4819d
Merge pull request #7 from hamburghammer/docs
Add Docs
2020-11-25 14:06:49 +01:00
Augusto Dwenger 1c9b053ec0 Fix link to the competition details 2020-11-21 16:58:05 +01:00
Augusto Dwenger 874960b897 Add note to the usage section regarding the flags 2020-11-21 16:58:05 +01:00
Augusto Dwenger 7698718458 Replace competition terms with installation, usage etc documentation 2020-11-21 16:58:05 +01:00
Augusto Dwenger e6ab66ad2e Add competition terms in side an own file 2020-11-21 16:57:56 +01:00
Augusto Dwenger J. 676c0ae573
Fix wrong argument descriptions 2020-11-15 20:25:31 +01:00
Augusto Dwenger J. ecd40f940d
Merge pull request #6 from hamburghammer/develop
Change memory representation
2020-11-15 20:08:18 +01:00
Augusto Dwenger fefa87ad52 Fix printing the help message twice 2020-11-10 14:50:31 +01:00
Augusto Dwenger 966735a184 Update CI scripts
Add test coverage output.
Add race detector step.
Disable cgo for the build
2020-11-09 21:36:01 +01:00
Augusto Dwenger 7b1a54d697 Change usage representation of memory field
Changes apply to Disk and Mem. The show the state as an object.
This should improve the readablility.
2020-11-09 21:27:18 +01:00
Augusto Dwenger J. d27183d362 Add go report card badge 2020-10-20 16:47:04 +02:00
Augusto Dwenger J. 8e32c292a5 Fix misspells 2020-10-20 16:44:59 +02:00
Augusto Dwenger 66abdebf3b Fix Copyright section 2020-08-10 20:23:36 +02:00
Augusto Dwenger e62c4853c9 Merge branch 'feature/date' into develop 2020-08-10 20:04:14 +02:00
Augusto Dwenger 0b81a55351 Move Date to the beginning of the JSON 2020-08-10 20:02:24 +02:00
Augusto Dwenger 68eaf1d195 Implement date as command for the json output 2020-08-09 17:52:20 +02:00
Augusto Dwenger 421faacb21 Add name and year to the license 2020-08-07 12:22:13 +02:00
Augusto Dwenger 79db0bb6e5 Merge branch 'develop'
Include:
- Top 10 Process output
- Add CI setup
- Add Testify dependency
2020-08-07 11:53:31 +02:00
Augusto Dwenger fae0bae315 Merge branch 'feature/processes' into develop 2020-08-07 11:46:58 +02:00
Augusto Dwenger ceb197d60f Fix bug if the process list is > 10 2020-08-07 11:45:33 +02:00
Augusto Dwenger e1a70507ec Add test for command.Process testing the internals and externals 2020-08-07 11:45:33 +02:00
Augusto Dwenger 8ccd1e13ce Start replacing custom assert func with stretchr/testify
Add github.com/stretchr/testify with its dependencies.
2020-08-07 11:45:33 +02:00
Augusto Dwenger a72b4e2405 Refactor transforming Process to cpuProcess 2020-08-07 11:44:59 +02:00
Augusto Dwenger d536dce03c Add test file for internal function testing 2020-08-07 11:44:59 +02:00
Augusto Dwenger 57c1bca182 Extract the conversion to cpuProcess to own func 2020-08-07 11:44:59 +02:00
Augusto Dwenger 016a109bb0 Add comments to exported funcs and structs 2020-08-07 11:44:59 +02:00
Augusto Dwenger 2b57fd0b7a Implement process list 2020-08-07 11:44:52 +02:00
Augusto Dwenger 176de4c0d3 Merge branch 'feature/drone-ci' into develop 2020-07-24 23:33:51 +02:00
Augusto Dwenger b3cbf3d6f3 Change badge to point to master branch 2020-07-24 23:26:23 +02:00
Augusto Dwenger f197208947 Modify test job to test for sub packeges and output a cover report 2020-07-24 23:23:13 +02:00
Augusto Dwenger d1e1614737 Add drone build badges 2020-07-24 23:20:11 +02:00
Augusto Dwenger d34bb06879 Add .drone.yml for drone ci pipeline 2020-07-24 23:17:34 +02:00
Augusto Dwenger 78a37d9a86 Add the MIT license file 2020-07-24 23:15:05 +02:00
18 changed files with 574 additions and 65 deletions

32
.drone.yml Normal file
View file

@ -0,0 +1,32 @@
kind: pipeline
name: default
steps:
- name: unit-test
image: golang
volumes:
- name: cache
path: /go
commands:
- go test -coverprofile=coverage.out -covermode=count ./...
- go tool cover -func=coverage.out | grep total
- name: race-test
image: golang
volumes:
- name: cache
path: /go
commands:
- go test -race ./...
- name: build
image: golang
volumes:
- name: deps
path: /go
commands:
- CGO_ENABLED=0 go build
volumes:
- name: cache
temp: {}

19
LICENSE Normal file
View file

@ -0,0 +1,19 @@
MIT License Copyright (c) 2020 Augusto Dwenger J.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,64 +1,51 @@
# gstat
Is a tool to get the system stats in a parsable format.
The tool is part of the competition with [Niklas](https://github.com/nhh).
[![Build Status](https://cloud.drone.io/api/badges/hamburghammer/gstat/status.svg?ref=refs/heads/master)](https://cloud.drone.io/hamburghammer/gstat)
[![Go Report Card](https://goreportcard.com/badge/github.com/hamburghammer/gstat)](https://goreportcard.com/report/github.com/hamburghammer/gstat)
Checkout his solution: [cstat](https://github.com/nhh/cstat)
Is a cli tool to get some system stats in a machine parsable format (JSON). It supports only Linux but might also run on some UNIX based operation systems.
## Terms of the competition
### Allgemein:
This tool is part of a competition with [nhh](https://github.com/nhh) -> [Details](docs/competition.md)
Name des Programms:
- cstat
- gstat
**WIP: expect some changes for the stats gathering**
Das Tool kann mehrere Metriken auf einmal zurückgeben.
## Features
- Easy to use
- Single executable
- Runs on Linux
### Anforderung:
## Installation
For the time there are no binaries provided this means you need to install it through go.
- Aktuelle CPU Auslastung
- Gesamtverbrauch aller CPU Kerne in %
- Die nach cpu sortierten Prozesse als Liste
- Aktueller Speicherplatzverbrauch
-used / free in megabyte
- Aktueller RAM Verbrauch
- used / free in megabyte
- Healthchecks mit Latency
- http / https / *ICMP*
- GET /
- *Aktueller Network IO (optional)*
- *Disk IO (optional)*
- JSON Output
- Datum und Uhrzeit im ISO Format
Requirements:
- Go is installed.
- You have the `$GOPATH` defined.
- The `$GOPATH/bin` directory is in your `$PATH`.
### Kriterien:
Install and update it with `go get -u github.com/hamburghammer/gstat`.
- Single Executable
- Linux
## Usage
```
Usage:
gstat [OPTIONS]
### Bewertungs:
Application Options:
-c, --cpu Include the total CPU consumption.
-m, --mem Include the RAM usage.
-d, --disk Include the Disk usage.
-p, --proc Include the top 10 running processes with the highest CPU consumption.
--health= Make a healthcheck call against the URI.
1. Wie groß ist das Binary
2. Performance von Befehlen
3. Cpu Auslastung
4. Ram Auslastung
Help Options:
-h, --help Show this help message
```
*not all flags a jet supported or fully implemented!
### Kommandozeilenaufrufe:
example output:
Alphabetische Reihenfolge
-c -h -d // --healtheck=http://example.com --disk --format=json
[https://de.wikipedia.org/wiki/Uniform_Resource_Identifier](https://de.wikipedia.org/wiki/Uniform_Resource_Identifier)
`$ cstat/gstat --cpu --format=json`
`$ cstat/gstat --metric=disk`
`$ cstat/gstat --check`
#### Goals:
cstat/gstat -c -d -i -h https://my-server.com > log.json
curl -X POST -d $(cstat/gstat -c -d -i -h https://my-server.com) https://my-logging.com/logs
`gstat -cmd`
```json
{"Date":"2020-11-21T16:32:18+01:00","CPU":3.49999999997029,"mem":{"used":5777,"total":16022},"disk":{"used":90319,"total":224323}}
```

View file

@ -2,6 +2,8 @@ package args
import (
"errors"
"fmt"
"os"
"strings"
"github.com/jessevdk/go-flags"
@ -9,11 +11,11 @@ import (
// Arguments represent the flags given at program start.
type Arguments struct {
CPU bool `short:"c" long:"cpu" description:"Include the total CPU consumption"`
Mem bool `short:"m" long:"mem" description:"Include the total RAM consumption"`
Disk bool `short:"d" long:"disk" description:"Include the total CPU consumption"`
Processes bool `short:"p" long:"proc" description:"Include the top 10 processes"`
Health string `long:"health" description:"Make a healthcheck call against the URI"`
CPU bool `short:"c" long:"cpu" description:"Include the total CPU consumption."`
Mem bool `short:"m" long:"mem" description:"Include the RAM usage."`
Disk bool `short:"d" long:"disk" description:"Include the Disk usage."`
Processes bool `short:"p" long:"proc" description:"Include the top 10 running processes with the highest CPU consumption."`
Health string `long:"health" description:"Make a healthcheck call against the URI."`
rest []string
}
@ -61,7 +63,12 @@ func Parse() Arguments {
_, err := flags.Parse(&args)
if err != nil {
panic(err)
if _, ok := err.(*flags.Error); ok {
os.Exit(1)
} else {
fmt.Println(err)
os.Exit(1)
}
}
return args

31
commands/date.go Normal file
View file

@ -0,0 +1,31 @@
package commands
import (
"encoding/json"
"time"
"github.com/hamburghammer/gstat/args"
)
// Date is a the configuration struct to execute the date command
type Date struct {
// GetTime is the function to get the actual Time in string format.
// It should be use to replace/cusomise the time output.
GetTime func() string
}
// NewDate is a convinice constructor for the Date struct.
// It sets the GetTime function to standard formatting.
func NewDate() Date {
return Date{GetTime: getFormattedTime}
}
// Exec is the implementation of the execution interface for the Date struct.
func (d Date) Exec(args args.Arguments) ([]byte, error) {
data := struct{ Date string }{Date: d.GetTime()}
return json.Marshal(data)
}
func getFormattedTime() string {
return time.Now().Format(time.RFC3339)
}

22
commands/date_test.go Normal file
View file

@ -0,0 +1,22 @@
package commands_test
import (
"testing"
"github.com/hamburghammer/gstat/args"
"github.com/hamburghammer/gstat/commands"
"github.com/stretchr/testify/assert"
)
func TestDate(t *testing.T) {
t.Run("", func(t *testing.T) {
customTime := func() string { return "2020-08-09T17:43:31+02:00" }
date := commands.Date{GetTime: customTime}
got, err := date.Exec(args.Arguments{})
want := "{\"Date\":\"2020-08-09T17:43:31+02:00\"}"
assert.Nil(t, err)
assert.Equal(t, want, string(got))
})
}

View file

@ -2,7 +2,6 @@ package commands
import (
"encoding/json"
"fmt"
"github.com/hamburghammer/gstat/args"
goDisk "github.com/shirou/gopsutil/disk"
@ -29,6 +28,8 @@ func (d Disk) Exec(args args.Arguments) ([]byte, error) {
return []byte{}, err
}
data := struct{ Disk string }{Disk: fmt.Sprintf("%d/%d", bytesToMegaByte(usage.Used), bytesToMegaByte(usage.Total))}
data := struct {
Disk Memory `json:"disk"`
}{Disk: Memory{Used: bytesToMegaByte(usage.Used), Total: bytesToMegaByte(usage.Total)}}
return json.Marshal(data)
}

View file

@ -41,7 +41,7 @@ func TestDiskExec(t *testing.T) {
}}
got, err := disk.Exec(args.Arguments{Disk: true})
want := "{\"Disk\":\"47/95\"}"
want := "{\"disk\":{\"used\":47,\"total\":95}}"
assertNoError(err, t)

View file

@ -2,12 +2,17 @@ package commands
import (
"encoding/json"
"fmt"
"github.com/hamburghammer/gstat/args"
"github.com/shirou/gopsutil/mem"
)
// Memory usage representation.
type Memory struct {
Used uint64 `json:"used"`
Total uint64 `json:"total"`
}
// Mem holds the memory usage for the json transformation
type Mem struct {
ReadVirtualMemoryStat func() (*mem.VirtualMemoryStat, error)
@ -29,8 +34,10 @@ func (m Mem) Exec(args args.Arguments) ([]byte, error) {
return []byte{}, err
}
usage := fmt.Sprintf("%d/%d", bytesToMegaByte(mem.Used), bytesToMegaByte(mem.Total))
data := struct{ Mem string }{usage}
usage := Memory{Used: bytesToMegaByte(mem.Used), Total: bytesToMegaByte(mem.Total)}
data := struct {
Mem Memory `json:"mem"`
}{usage}
return json.Marshal(data)
}

View file

@ -41,7 +41,7 @@ func TestMemExec(t *testing.T) {
}}
got, err := disk.Exec(args.Arguments{Mem: true})
want := "{\"Mem\":\"47/95\"}"
want := "{\"mem\":{\"used\":47,\"total\":95}}"
assertNoError(err, t)

105
commands/processes.go Normal file
View file

@ -0,0 +1,105 @@
package commands
import (
"encoding/json"
"sort"
"github.com/hamburghammer/gstat/args"
"github.com/shirou/gopsutil/process"
)
// Processes holds the function to get the process list
type Processes struct {
ReadProcesses func() ([]*Process, error)
}
// Exec is the implementation of the execution interface to be able to be used as a command
func (p Processes) Exec(args args.Arguments) ([]byte, error) {
if !args.Processes {
return []byte{}, nil
}
processes, err := p.ReadProcesses()
if err != nil {
return []byte{}, err
}
processesWithCPU, err := getProcessesCPUInfos(processes)
if err != nil {
return []byte{}, err
}
sort.Sort(byCPU(processesWithCPU))
data := struct{ Processes []cpuProcess }{Processes: getFirstTenOrLess(processesWithCPU)}
return json.Marshal(data)
}
// NewProcesses is a factory ctor to build a Processes struct
func NewProcesses() Processes {
return Processes{ReadProcesses: getProcesses}
}
// getProcesses maps the process.Process array to a local Process struct
func getProcesses() ([]*Process, error) {
processes, err := process.Processes()
p := make([]*Process, 0, len(processes))
for _, process := range processes {
p = append(p, &Process{Pid: process.Pid, CPUPercent: process.CPUPercent, Name: process.Name})
}
return p, err
}
func getFirstTenOrLess(array []cpuProcess) []cpuProcess {
if len(array) >= 9 {
return array[0:10]
}
return array
}
func getProcessesCPUInfos(processes []*Process) ([]cpuProcess, error) {
processesWithCPU := make([]cpuProcess, 0, len(processes))
for _, process := range processes {
processCPUInfo, err := getProcessCPUInfos(process)
if err != nil {
return processesWithCPU, err
}
processesWithCPU = append(processesWithCPU, *processCPUInfo)
}
return processesWithCPU, nil
}
func getProcessCPUInfos(process *Process) (*cpuProcess, error) {
cpuPercent, err := process.CPUPercent()
if err != nil {
return &cpuProcess{}, err
}
name, err := process.Name()
if err != nil {
return &cpuProcess{}, err
}
return &cpuProcess{Pid: process.Pid, CPU: cpuPercent, Name: name}, nil
}
type cpuProcess struct {
Name string
Pid int32
CPU float64
}
type byCPU []cpuProcess
func (c byCPU) Len() int { return len(c) }
func (c byCPU) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c byCPU) Less(i, j int) bool { return c[i].CPU > c[j].CPU }
// Process is an adapter struct for the external process struct from github.com/shirou/gopsutil/process
type Process struct {
Pid int32
Name func() (string, error)
CPUPercent func() (float64, error)
}

View file

@ -0,0 +1,137 @@
package commands
import (
"errors"
"testing"
"github.com/stretchr/testify/assert"
)
func TestByCPULen(t *testing.T) {
t.Run("three item inside the array", func(t *testing.T) {
array := []cpuProcess{{}, {}, {}}
got := byCPU(array).Len()
want := 3
assert.Equal(t, want, got, "they should be equal")
})
t.Run("one item inside the array", func(t *testing.T) {
array := []cpuProcess{{}}
got := byCPU(array).Len()
want := 1
assert.Equal(t, want, got, "they should be equal")
})
t.Run("empty array", func(t *testing.T) {
array := []cpuProcess{}
got := byCPU(array).Len()
want := 0
assert.Equal(t, want, got, "they should be equal")
})
}
func TestByCPUSwap(t *testing.T) {
t.Run("swap array items", func(t *testing.T) {
unswaped := []cpuProcess{{Name: "foo"}, {Name: "bar"}}
swaped := []cpuProcess{{Name: "bar"}, {Name: "foo"}}
got := byCPU(unswaped)
got.Swap(0, 1)
want := byCPU(swaped)
assert.Equal(t, want, got)
})
}
func TestByCPULess(t *testing.T) {
cpuProcessArray := []cpuProcess{{CPU: 1}, {CPU: 2}}
t.Run("less on cpu field smaller", func(t *testing.T) {
got := byCPU(cpuProcessArray).Less(0, 1)
want := false
assert.Equal(t, want, got)
})
t.Run("less on cpu field bigger", func(t *testing.T) {
got := byCPU(cpuProcessArray).Less(1, 0)
want := true
assert.Equal(t, want, got)
})
}
func TestGetProcessCPUInfos(t *testing.T) {
t.Run("transform Process to cpuProcess", func(t *testing.T) {
nameFunc := func() (string, error) { return "foo", nil }
cpuProcessFunc := func() (float64, error) { return 0, nil }
process := Process{Pid: 1, Name: nameFunc, CPUPercent: cpuProcessFunc}
got, err := getProcessCPUInfos(&process)
want := &cpuProcess{Name: "foo", Pid: 1, CPU: 0}
assert.Nil(t, err, "No error expected")
assert.Equal(t, want, got)
})
t.Run("calling name function returns error", func(t *testing.T) {
wantErr := errors.New("error")
nameFunc := func() (string, error) { return "", wantErr }
cpuProcessFunc := func() (float64, error) { return 0, nil }
process := Process{Pid: 1, Name: nameFunc, CPUPercent: cpuProcessFunc}
_, gotErr := getProcessCPUInfos(&process)
assert.NotNil(t, gotErr, "An error was expected")
assert.Equal(t, wantErr, gotErr)
})
t.Run("calling cpuProcess function returns error", func(t *testing.T) {
wantErr := errors.New("error")
nameFunc := func() (string, error) { return "", nil }
cpuProcessFunc := func() (float64, error) { return 0, wantErr }
process := Process{Pid: 1, Name: nameFunc, CPUPercent: cpuProcessFunc}
_, gotErr := getProcessCPUInfos(&process)
assert.NotNil(t, gotErr, "An error was expected")
assert.Equal(t, wantErr, gotErr)
})
}
func TestGetProcessesCPUInfos(t *testing.T) {
err := errors.New("error")
nameFunc := func() (string, error) { return "foo", nil }
nameErrFunc := func() (string, error) { return "foo", err }
cpuProcessFunc := func() (float64, error) { return 0, nil }
t.Run("transform array of process into an array of cpuProcess", func(t *testing.T) {
processes := []*Process{{Pid: 2, Name: nameFunc, CPUPercent: cpuProcessFunc}, {Pid: 1, Name: nameFunc, CPUPercent: cpuProcessFunc}}
got, gotErr := getProcessesCPUInfos(processes)
want := []cpuProcess{{Name: "foo", CPU: 0, Pid: 2}, {Name: "foo", CPU: 0, Pid: 1}}
assert.Nil(t, gotErr, "No error expected")
assert.Equal(t, want, got)
})
t.Run("return error directly if one happens", func(t *testing.T) {
processes := []*Process{{Pid: 2, Name: nameFunc, CPUPercent: cpuProcessFunc}, {Pid: 1, Name: nameErrFunc, CPUPercent: cpuProcessFunc}}
got, gotErr := getProcessesCPUInfos(processes)
want := []cpuProcess{{Name: "foo", CPU: 0, Pid: 2}}
wantErr := err
assert.NotNil(t, gotErr, "an error was expected")
assert.Equal(t, wantErr, gotErr)
assert.Equal(t, want, got)
})
}

View file

@ -0,0 +1,80 @@
package commands_test
import (
"errors"
"testing"
"github.com/hamburghammer/gstat/args"
"github.com/hamburghammer/gstat/commands"
"github.com/stretchr/testify/assert"
)
func TestProcessExec(t *testing.T) {
t.Run("should test for the Argument for Process", func(t *testing.T) {
arguments := args.Arguments{Processes: false}
got, err := commands.Processes{}.Exec(arguments)
assert.Nil(t, err, "no error expected")
assert.Equal(t, 0, len(got))
})
t.Run("should exit if the getting the process data returns an error", func(t *testing.T) {
wantErr := errors.New("getting data error")
arguments := args.Arguments{Processes: true}
mockProcessData := func() ([]*commands.Process, error) { return nil, wantErr }
_, err := commands.Processes{ReadProcesses: mockProcessData}.Exec(arguments)
assert.NotNil(t, err, "an error was expected")
assert.Equal(t, wantErr, err)
})
t.Run("should pass errors from getting cpu infos to output", func(t *testing.T) {
wantErr := errors.New("getting data error")
arguments := args.Arguments{Processes: true}
nameFunc := func() (string, error) { return "", nil }
cpuErrorProcessFunc := func() (float64, error) { return 0, wantErr }
process := commands.Process{Pid: 1, Name: nameFunc, CPUPercent: cpuErrorProcessFunc}
mockProcessData := func() ([]*commands.Process, error) { return []*commands.Process{&process}, nil }
_, gotErr := commands.Processes{ReadProcesses: mockProcessData}.Exec(arguments)
assert.Equal(t, wantErr, gotErr)
})
t.Run("should sort per cpu value", func(t *testing.T) {
arguments := args.Arguments{Processes: true}
nameFunc := func() (string, error) { return "", nil }
cpuProcessFunc1 := func() (float64, error) { return 0, nil }
cpuProcessFunc2 := func() (float64, error) { return 1, nil }
process1 := commands.Process{Pid: 1, Name: nameFunc, CPUPercent: cpuProcessFunc1}
process2 := commands.Process{Pid: 2, Name: nameFunc, CPUPercent: cpuProcessFunc2}
mockProcessData := func() ([]*commands.Process, error) { return []*commands.Process{&process1, &process2}, nil }
got, err := commands.Processes{ReadProcesses: mockProcessData}.Exec(arguments)
want := "{\"Processes\":[{\"Name\":\"\",\"Pid\":2,\"CPU\":1},{\"Name\":\"\",\"Pid\":1,\"CPU\":0}]}"
assert.Nil(t, err)
assert.Equal(t, want, string(got))
})
t.Run("should return max 10 entries", func(t *testing.T) {
arguments := args.Arguments{Processes: true}
nameFunc := func() (string, error) { return "", nil }
cpuProcessFunc := func() (float64, error) { return 0, nil }
processes := make([]*commands.Process, 12)
for i := 0; i <= 11; i++ {
processes[i] = &commands.Process{Pid: int32(i), Name: nameFunc, CPUPercent: cpuProcessFunc}
}
mockProcessData := func() ([]*commands.Process, error) { return processes, nil }
got, err := commands.Processes{ReadProcesses: mockProcessData}.Exec(arguments)
want := "{\"Processes\":[{\"Name\":\"\",\"Pid\":0,\"CPU\":0},{\"Name\":\"\",\"Pid\":1,\"CPU\":0},{\"Name\":\"\",\"Pid\":2,\"CPU\":0},{\"Name\":\"\",\"Pid\":3,\"CPU\":0},{\"Name\":\"\",\"Pid\":4,\"CPU\":0},{\"Name\":\"\",\"Pid\":5,\"CPU\":0},{\"Name\":\"\",\"Pid\":6,\"CPU\":0},{\"Name\":\"\",\"Pid\":7,\"CPU\":0},{\"Name\":\"\",\"Pid\":8,\"CPU\":0},{\"Name\":\"\",\"Pid\":9,\"CPU\":0}]}"
assert.Nil(t, err)
assert.Equal(t, want, string(got))
})
}

View file

@ -45,7 +45,7 @@ func TestResultEquals(t *testing.T) {
}
func TestExecCommands(t *testing.T) {
t.Run("should return string array without opening and closeing brackets", func(t *testing.T) {
t.Run("should return string array without opening and closing brackets", func(t *testing.T) {
arguments := args.Arguments{}
result := commands.NewResult(arguments)

56
docs/competition.md Normal file
View file

@ -0,0 +1,56 @@
# Competition
The tool is part of the competition with [Niklas](https://github.com/nhh).
Checkout his solution: [cstat](https://github.com/nhh/cstat)
## Terms of the competition
### Allgemein:
Name des Programms:
- cstat
- gstat
Das Tool kann mehrere Metriken auf einmal zurückgeben.
### Anforderung:
- Aktuelle CPU Auslastung
- Gesamtverbrauch aller CPU Kerne in %
- Die nach cpu sortierten Prozesse als Liste
- Aktueller Speicherplatzverbrauch
-used / free in megabyte
- Aktueller RAM Verbrauch
- used / free in megabyte
- Healthchecks mit Latency
- http / https / *ICMP*
- GET /
- *Aktueller Network IO (optional)*
- *Disk IO (optional)*
- JSON Output
- Datum und Uhrzeit im ISO Format
### Kriterien:
- Single Executable
- Linux
### Bewertungs:
1. Wie groß ist das Binary
2. Performance von Befehlen
3. Cpu Auslastung
4. Ram Auslastung
### Kommandozeilenaufrufe:
Alphabetische Reihenfolge
-c -h -d // --healtheck=http://example.com --disk --format=json
[https://de.wikipedia.org/wiki/Uniform_Resource_Identifier](https://de.wikipedia.org/wiki/Uniform_Resource_Identifier)
`$ cstat/gstat --cpu --format=json`
`$ cstat/gstat --metric=disk`
`$ cstat/gstat --check`
#### Goals:
cstat/gstat -c -d -i -h https://my-server.com > log.json
curl -X POST -d $(cstat/gstat -c -d -i -h https://my-server.com) https://my-logging.com/logs

7
go.mod
View file

@ -3,7 +3,10 @@ module github.com/hamburghammer/gstat
go 1.14
require (
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
github.com/go-ole/go-ole v1.2.4 // indirect
github.com/jessevdk/go-flags v1.4.0
github.com/shirou/gopsutil v2.20.4+incompatible
golang.org/x/sys v0.0.0-20200610111108-226ff32320da // indirect
github.com/shirou/gopsutil v2.20.6+incompatible
github.com/stretchr/testify v1.6.1
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642 // indirect
)

16
go.sum
View file

@ -1,6 +1,22 @@
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/shirou/gopsutil v2.20.4+incompatible h1:cMT4rxS55zx9NVUnCkrmXCsEB/RNfG9SwHY9evtX8Ng=
github.com/shirou/gopsutil v2.20.4+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/gopsutil v2.20.6+incompatible h1:P37G9YH8M4vqkKcwBosp+URN5O8Tay67D2MbR361ioY=
github.com/shirou/gopsutil v2.20.6+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/sys v0.0.0-20200610111108-226ff32320da h1:bGb80FudwxpeucJUjPYJXuJ8Hk91vNtfvrymzwiei38=
golang.org/x/sys v0.0.0-20200610111108-226ff32320da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642 h1:B6caxRw+hozq68X2MY7jEpZh/cr4/aHLv9xU8Kkadrw=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View file

@ -11,7 +11,13 @@ func main() {
args := args.Parse()
result := commands.NewResult(args)
executs := []commands.Executor{commands.NewCPU(), commands.NewMem(), commands.NewDisk()}
executs := []commands.Executor{
commands.NewDate(),
commands.NewCPU(),
commands.NewMem(),
commands.NewDisk(),
commands.NewProcesses(),
}
output := result.ExecCommands(executs)
fmt.Println(formatToJSON(output.Collection.Results))