Skip to content

Commit 391d916

Browse files
scout/usage: add --container flag to src scout usage (#986)
1 parent d9d8ca6 commit 391d916

File tree

2 files changed

+51
-18
lines changed

2 files changed

+51
-18
lines changed

cmd/src/scout_usage.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ func init() {
2929
Check usage for specific pod
3030
$ src scout usage --pod <podname>
3131
32+
Check usage for specific container (docker only)
33+
$ src scout usage --container <containername>
34+
3235
Add namespace if using namespace in a Kubernetes cluster
3336
$ src scout usage --namespace <namespace>
3437
@@ -47,6 +50,7 @@ func init() {
4750
kubeConfig *string
4851
namespace = flagSet.String("namespace", "", "(optional) specify the kubernetes namespace to use")
4952
pod = flagSet.String("pod", "", "(optional) specify a single pod")
53+
container = flagSet.String("container", "", "(optional) specify a single container")
5054
docker = flagSet.Bool("docker", false, "(optional) using docker deployment")
5155
spy = flagSet.Bool("spy", false, "(optional) see resource usage in real time")
5256
)
@@ -92,14 +96,17 @@ func init() {
9296
if *pod != "" {
9397
options = append(options, usage.WithPod(*pod))
9498
}
99+
if *container != "" || *docker {
100+
if *container != "" {
101+
options = append(options, usage.WithContainer(*container))
102+
}
95103

96-
if *docker {
97104
dockerClient, err := client.NewClientWithOpts(client.FromEnv)
98105
if err != nil {
99106
return errors.Wrap(err, "error creating docker client: ")
100107
}
101108

102-
return usage.Docker(context.Background(), *dockerClient)
109+
return usage.Docker(context.Background(), *dockerClient, options...)
103110
}
104111

105112
return usage.K8s(

internal/scout/usage/docker.go

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7+
"os"
78

89
"github.com/charmbracelet/bubbles/table"
10+
"github.com/charmbracelet/lipgloss"
911
"github.com/docker/docker/api/types"
1012
"github.com/docker/docker/client"
1113
"github.com/sourcegraph/sourcegraph/lib/errors"
@@ -51,34 +53,58 @@ func renderDockerUsageTable(ctx context.Context, cfg *Config, containers []types
5153
return errors.Wrap(err, "failed to get container info")
5254
}
5355

54-
stats, err := cfg.dockerClient.ContainerStats(ctx, container.ID, false)
55-
if err != nil {
56-
return errors.Wrap(err, "could not get container stats")
57-
}
58-
defer stats.Body.Close()
59-
60-
var usage types.StatsJSON
61-
if err := json.NewDecoder(stats.Body).Decode(&usage); err != nil {
62-
return errors.Wrap(err, "could not decode container stats")
56+
if cfg.container != "" {
57+
if containerInfo.Name == cfg.container {
58+
row := makeDockerUsageRow(ctx, cfg, containerInfo)
59+
rows = append(rows, row)
60+
break
61+
} else {
62+
continue
63+
}
6364
}
6465

65-
row := makeDockerUsageRow(usage, containerInfo)
66+
row := makeDockerUsageRow(ctx, cfg, containerInfo)
6667
rows = append(rows, row)
6768
}
6869

70+
if len(rows) == 0 {
71+
msg := lipgloss.NewStyle().Foreground(lipgloss.Color("#FFA500"))
72+
if cfg.container == "" {
73+
fmt.Println(msg.Render(`No docker containers are running.`))
74+
os.Exit(1)
75+
}
76+
fmt.Println(msg.Render(
77+
fmt.Sprintf(`No container with name '%s' running.`, cfg.container),
78+
))
79+
os.Exit(1)
80+
}
81+
6982
style.ResourceTable(columns, rows)
7083
return nil
7184
}
7285

7386
// makeDockerUsageRow generates a table row displaying CPU and memory usage for a Docker container.
74-
func makeDockerUsageRow(containerUsage types.StatsJSON, containerInfo types.ContainerJSON) table.Row {
75-
cpuCores := float64(containerInfo.HostConfig.NanoCPUs)
76-
memory := float64(containerInfo.HostConfig.Memory)
77-
cpuUsage := float64(containerUsage.CPUStats.CPUUsage.TotalUsage)
78-
memoryUsage := float64(containerUsage.MemoryStats.Usage)
87+
func makeDockerUsageRow(ctx context.Context, cfg *Config, container types.ContainerJSON) table.Row {
88+
stats, err := cfg.dockerClient.ContainerStats(ctx, container.ID, false)
89+
if err != nil {
90+
errors.Wrap(err, "could not get container stats")
91+
os.Exit(1)
92+
}
93+
defer func() { _ = stats.Body.Close() }()
94+
95+
var usage types.StatsJSON
96+
if err := json.NewDecoder(stats.Body).Decode(&usage); err != nil {
97+
errors.Wrap(err, "could not get container stats")
98+
os.Exit(1)
99+
}
100+
101+
cpuCores := float64(container.HostConfig.NanoCPUs)
102+
memory := float64(container.HostConfig.Memory)
103+
cpuUsage := float64(usage.CPUStats.CPUUsage.TotalUsage)
104+
memoryUsage := float64(usage.MemoryStats.Usage)
79105

80106
return table.Row{
81-
containerInfo.Name,
107+
container.Name,
82108
fmt.Sprintf("%.2f", cpuCores/1_000_000_000),
83109
fmt.Sprintf("%.2f%%", getPercentage(cpuUsage, cpuCores)),
84110
fmt.Sprintf("%.2fG", memory/1_000_000_000),

0 commit comments

Comments
 (0)