Skip to content

Commit

Permalink
Update: Implemented source code for tool
Browse files Browse the repository at this point in the history
  • Loading branch information
BinSquare committed Jun 18, 2023
2 parents 47e4dbe + 8b962fa commit 379665f
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 0 deletions.
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Cgroup Stats CLI Tool
This is a tool written in Go that uses the containerd/cgroups library to print out cgroup (control group) statistics for a given cgroup. This package currently only supports cgroupsV1. You can specify the type of stats to print out using command line flags.

### Why not just use systemd_cgtop?
This tool provides more granular and exact information about the stats it returns as compared to systemd_cgtop (which reports cache memory as part of memory causing misleading information about how much active memory is being used). See: https://systemd-devel.freedesktop.narkive.com/WnOE0u0k/systemd-cgtop-memory-utilization-display-not-useful

### Dependencies
This tool requires the containerd/cgroups Go library. You can install it using the following command:
````
go get github.com/containerd/cgroups
````

### Usage
You can run the tool using the go run command. You must provide the cgroup path using the -path flag. You can also specify what kind of stats to print out using the -cpu, -mem, -pids, -blkio, and -hugetlb flags.
```
go run main.go -path=<cgroup_path> [-cpu] [-mem] [-pids] [-blkio] [-hugetlb]
```
For example, the following command will print out the CPU, Memory, and PIDs stats of the specified cgroup:

```
go run main.go -path=/sys/fs/cgroup/unified/system.slice/docker.service -cpu -mem -pids
```

### Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
13 changes: 13 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module github.com/binsquare/cgroup-stats-cli

go 1.20

require (
github.com/containerd/cgroups v1.1.0 // indirect
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/godbus/dbus/v5 v5.0.4 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/opencontainers/runtime-spec v1.0.2 // indirect
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34 // indirect
)
43 changes: 43 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0=
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34 h1:GkvMjFtXUmahfDtashnc1mnrCtuBVcwse5QV2lUk/tI=
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
82 changes: 82 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package main

import (
"flag"
"fmt"
"os"

"github.com/containerd/cgroups"
v1 "github.com/containerd/cgroups/stats/v1"
)

type cliOptions struct {
cgroupPath *string
onlyCPU *bool
onlyMem *bool
onlyPids *bool
onlyBlkio *bool
onlyHugetlb *bool
}

func parseFlags(flags *cliOptions) *cliOptions {
flags.cgroupPath = flag.String("path", "", "The cgroup path to read stats. Path should not include `/sys/fs/cgroup/` prefix, it should start with your own cgroups name")
flags.onlyCPU = flag.Bool("cpu", false, "show cpu stats only")
flags.onlyMem = flag.Bool("mem", false, "show mem stats only")
flags.onlyPids = flag.Bool("pids", false, "show pids stats only")
flags.onlyBlkio = flag.Bool("blkio", false, "show blkio stats only")
flags.onlyHugetlb = flag.Bool("HugeTLB", false, "show hugetlb stats only")

flag.Parse()
return flags
}

func getMetrics(cg cgroups.Cgroup) *v1.Metrics {
metrics, err := cg.Stat(cgroups.IgnoreNotExist)
if err != nil {
fmt.Println("err retrieving cgroup stats:", err)
os.Exit(1)
}

return metrics
}

func printMetrics(metrics *v1.Metrics, flags *cliOptions) {
if *flags.onlyCPU {
fmt.Printf("CPU Metrics: %+v\n", metrics.CPU)
}
if *flags.onlyMem {
fmt.Printf("Memory Metrics: %+v\n", metrics.Memory)
}
if *flags.onlyPids {
fmt.Printf("PIDs Metrics: %+v\n", metrics.Pids)
}
if *flags.onlyBlkio {
fmt.Printf("BlkIO Metrics: %+v\n", metrics.Blkio)
}
if *flags.onlyHugetlb {
fmt.Printf("HugeTLB Metrics: %+v\n", metrics.Hugetlb)
}

if !*flags.onlyCPU && !*flags.onlyMem && !*flags.onlyPids && !*flags.onlyBlkio && !*flags.onlyHugetlb {
fmt.Printf("Cgroup metrics: %+v\n", metrics)
}
}

func main() {
flags := parseFlags(new(cliOptions))

if *flags.cgroupPath == "" {
fmt.Println("Missing cgroup path")
os.Exit(1)
}

cg, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(*flags.cgroupPath))
if err != nil {
fmt.Println("loading cgroup error:", err)
os.Exit(1)
}

metrics := getMetrics(cg)

printMetrics(metrics, flags)
}

0 comments on commit 379665f

Please sign in to comment.