Skip to content

Commit

Permalink
Stats
Browse files Browse the repository at this point in the history
  • Loading branch information
devemlight authored and devemio committed Feb 9, 2024
1 parent 81da40a commit 4e2de42
Show file tree
Hide file tree
Showing 15 changed files with 246 additions and 39 deletions.
2 changes: 1 addition & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ linters-settings:
- default
- prefix(github.com/devemio/docker-color-output)
varnamelen:
ignore-names: [ i, in, j, m, sb, tt, v ]
ignore-names: [ fn, i, in, j, m, sb, tt, v ]
depguard:
rules:
main:
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,15 @@ docker compose ps | docker-color-output
```

![docker compose ps](https://user-images.githubusercontent.com/5787193/93630916-7267dd00-f9f3-11ea-9521-e69152fa86f1.png)

#### 💡 docker stats

```bash
ds # alias
```

```bash
docker stats [--no-stream] | docker-color-output
```

![docker stats](https://github.com/devemio/docker-color-output/assets/5787193/a3134ae9-707b-4ad7-a5ea-765150d535e8)
4 changes: 4 additions & 0 deletions bash/aliases.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ dps() {
dcps() {
docker compose ps "$@" | docker-color-output
}

ds() {
docker stats "$@" | docker-color-output
}
27 changes: 12 additions & 15 deletions cmd/cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,16 @@ func run() error {

color.SetPalette(color.Palette(cfg.Colors))

in, err := stdin.Get()
if err != nil {
return err //nolint:wrapcheck
}

rows, err := app.Run(in)
if err != nil {
return err //nolint:wrapcheck
}

for _, row := range rows {
stdout.Println(row)
}

return nil
return stdin.Get(func(rows []string) error { //nolint:wrapcheck
rows, err = app.Run(rows)
if err != nil {
return fmt.Errorf("app: %w", err)
}

for _, row := range rows {
stdout.Println(row)
}

return nil
})
}
3 changes: 2 additions & 1 deletion internal/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package app

import (
"errors"
"fmt"
"strings"

"github.com/devemio/docker-color-output/internal/cmd"
Expand Down Expand Up @@ -29,7 +30,7 @@ func Run(in []string) ([]string, error) {

command, err := cmd.Parse(header)
if err != nil {
return nil, err //nolint:wrapcheck
return nil, fmt.Errorf("cmd: parse: %w", err)
}

res := make([]string, len(in))
Expand Down
1 change: 1 addition & 0 deletions internal/app/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ func TestRun(t *testing.T) {
"docker_images": {in: "docker_images.out", want: "docker_images.out"},
"docker_compose_ps": {in: "docker_compose_ps.out", want: "docker_compose_ps.out"},
"docker_compose_ps_1": {in: "docker_compose_ps_1.out", want: "docker_compose_ps_1.out"},
"docker_stats": {in: "docker_stats.out", want: "docker_stats.out"},
}

for name, tt := range tests {
Expand Down
2 changes: 1 addition & 1 deletion internal/app/const.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package app

const (
Ver = "2.4.0"
Ver = "2.5.0"
Name = "docker-color-output"
)
17 changes: 8 additions & 9 deletions internal/app/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,18 @@
package app

import (
"fmt"

"github.com/devemio/docker-color-output/internal/stdout"
"github.com/devemio/docker-color-output/pkg/color"
)

const indent = " "

//nolint:forbidigo
func Usage(err error) {
fmt.Println(color.LightRed("💡 Error: " + err.Error()))
fmt.Println("💥 Version: " + color.Green(Ver))
fmt.Println("👌 Usage:")
fmt.Println(indent + color.Green("docker compose ps") + " [-a] | " + color.Brown(Name))
fmt.Println(indent + color.Green("docker images") + " [--format] | " + color.Brown(Name))
fmt.Println(indent + color.Green("docker ps") + " [-a] [--format] | " + color.Brown(Name))
stdout.Println(color.LightRed("💡 Error: " + err.Error()))
stdout.Println("💥 Version: " + color.Green(Ver))
stdout.Println("👌 Usage:")
stdout.Println(indent + color.Green("docker compose ps") + " [-a] | " + color.Brown(Name))
stdout.Println(indent + color.Green("docker images") + " [--format] | " + color.Brown(Name))
stdout.Println(indent + color.Green("docker ps") + " [-a] [--format] | " + color.Brown(Name))
stdout.Println(indent + color.Green("docker stats") + " [--no-stream] | " + color.Brown(Name))
}
154 changes: 154 additions & 0 deletions internal/cmd/docker_stats.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package cmd

import (
"strings"

"github.com/devemio/docker-color-output/internal/layout"
"github.com/devemio/docker-color-output/pkg/color"
"github.com/devemio/docker-color-output/pkg/util/number"
)

const (
DockerStatsContainerID = "CONTAINER ID"
DockerStatsName = "NAME"
DockerStatsCPUPercent = "CPU %"
DockerStatsMemUsage = "MEM USAGE / LIMIT"
DockerStatsMemPercent = "MEM %"
DockerStatsNetIO = "NET I/O"
DockerStatsBlockIO = "BLOCK I/O"
DockerStatsPIDs = "PIDS"
)

const (
cpuPercentThresholdMedium = 50
cpuPercentThresholdHigh = 90

memPercentThresholdMedium = 50
memPercentThresholdHigh = 90

netIOThresholdHigh = 10

blockIOThresholdHigh = 10

pidsThresholdHigh = 100
)

type DockerStats struct{}

func (c *DockerStats) Columns() []string {
return []string{
DockerStatsContainerID, //
DockerStatsName, //
DockerStatsCPUPercent, //
DockerStatsMemUsage, //
DockerStatsMemPercent, //
DockerStatsNetIO, //
DockerStatsBlockIO, //
DockerStatsPIDs, //
}
}

func (c *DockerStats) Format(rows layout.Row, col layout.Column) string {
v := string(rows[col])

switch col {
case DockerStatsContainerID:
return c.ContainerID(v)
case DockerStatsName:
return c.Name(v)
case DockerStatsCPUPercent:
return c.CPUPercent(v)
case DockerStatsMemUsage:
return c.MemUsage(v)
case DockerStatsMemPercent:
return c.MemPercent(v)
case DockerStatsNetIO:
return c.NetIO(v)
case DockerStatsBlockIO:
return c.BlockIO(v)
case DockerStatsPIDs:
return c.PIDs(v)
default:
return v
}
}

func (*DockerStats) ContainerID(v string) string {
return color.DarkGray(v)
}

func (c *DockerStats) Name(v string) string {
return color.White(v)
}

func (c *DockerStats) CPUPercent(v string) string {
percent := number.ParseFloat(v)

switch {
case percent >= cpuPercentThresholdHigh:
return color.Red(v)
case percent >= cpuPercentThresholdMedium:
return color.Brown(v)
default:
return v
}
}

func (c *DockerStats) MemUsage(v string) string {
parts := strings.Split(v, "/")

return parts[0] + color.DarkGray("/"+parts[1])
}

func (c *DockerStats) MemPercent(v string) string {
percent := number.ParseFloat(v)

switch {
case percent >= memPercentThresholdHigh:
return color.Red(v)
case percent >= memPercentThresholdMedium:
return color.Brown(v)
default:
return v
}
}

func (*DockerStats) NetIO(v string) string {
parts := strings.Split(v, "/")

for i := range parts {
if strings.Contains(parts[i], "GB") {
if number.ParseFloat(parts[i]) >= netIOThresholdHigh {
parts[i] = color.Red(parts[i])
} else {
parts[i] = color.Brown(parts[i])
}
}
}

return parts[0] + color.DarkGray("/") + parts[1]
}

func (*DockerStats) BlockIO(v string) string {
parts := strings.Split(v, "/")

for i := range parts {
if strings.Contains(parts[i], "GB") {
if number.ParseFloat(parts[i]) >= blockIOThresholdHigh {
parts[i] = color.Red(parts[i])
} else {
parts[i] = color.Brown(parts[i])
}
}
}

return parts[0] + color.DarkGray("/") + parts[1]
}

func (*DockerStats) PIDs(v string) string {
if number.ParseFloat(v) >= pidsThresholdHigh {
return color.Red(v)
}

return color.LightCyan(v)
}
5 changes: 5 additions & 0 deletions internal/cmd/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,10 @@ func Parse(header layout.Header) (Command, error) { //nolint:ireturn
return composePs, nil
}

stats := &DockerStats{}
if util.Intersect(columns, stats.Columns()) {
return stats, nil
}

return nil, ErrInvalidFirstLine
}
2 changes: 1 addition & 1 deletion internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func Get() (Config, error) {
if *cfgPath != "" {
data, err := os.ReadFile(*cfgPath)
if err != nil {
return Config{}, fmt.Errorf("read file: %w", err)
return Config{}, fmt.Errorf("read: %w", err)
}

if err = json.Unmarshal(data, &cfg); err != nil {
Expand Down
48 changes: 37 additions & 11 deletions internal/stdin/stdin.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,58 @@ package stdin

import (
"bufio"
"bytes"
"errors"
"fmt"
"os"

"github.com/devemio/docker-color-output/internal/stdout"
)

var ErrNoStdin = errors.New("no stdin")
var ErrEmpty = errors.New("empty")

const rowsCap = 20

// clsBytes contains bytes to clear
// the screen for nix systems.
var clsBytes = []byte("\033[2J\033[H") //nolint:gochecknoglobals

func Get() ([]string, error) {
func Get(fn func(rows []string) error) error {
fi, err := os.Stdin.Stat()
if err != nil {
return nil, err //nolint:wrapcheck
return fmt.Errorf("stdin: %w", err)
}

if fi.Mode()&os.ModeNamedPipe == 0 && fi.Size() <= 0 {
return nil, ErrNoStdin
return fmt.Errorf("stdin: %w", ErrEmpty)
}

var res []string
rows := make([]string, 0, rowsCap)

scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
row, found := scanner.Bytes(), false //nolint:wastedassign

if row, found = bytes.CutPrefix(row, clsBytes); found && len(rows) > 0 {
stdout.Print(string(clsBytes))

if err = fn(rows); err != nil {
return err
}

rows = rows[:0]
}

rows = append(rows, string(row))
}

s := bufio.NewScanner(os.Stdin)
for s.Scan() {
res = append(res, s.Text())
if err = scanner.Err(); err != nil {
return fmt.Errorf("stdin: scan: %w", err)
}

if err = s.Err(); err != nil {
return nil, err //nolint:wrapcheck
if err = fn(rows); err != nil {
return err
}

return res, nil
return nil
}
4 changes: 4 additions & 0 deletions internal/stdout/stdout.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import (
"fmt"
)

func Print(in string) {
fmt.Print(in) //nolint:forbidigo
}

func Println(in string) {
fmt.Println(in) //nolint:forbidigo
}
2 changes: 2 additions & 0 deletions test/data/in/docker_stats.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
e39ba801c0e1 nginx 90.00% 13.53MiB / 7.657GiB 50.17% 10.8MB / 42.1GB 0B / 12.3kB 17
2 changes: 2 additions & 0 deletions test/data/out/docker_stats.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
e39ba801c0e1 nginx 90.00% 13.53MiB / 7.657GiB 50.17% 10.8MB / 42.1GB 0B / 12.3kB 17

0 comments on commit 4e2de42

Please sign in to comment.