Skip to content

Commit

Permalink
Add Memory usage info to project state
Browse files Browse the repository at this point in the history
  • Loading branch information
F1bonacc1 committed Dec 8, 2023
1 parent b63fdac commit 5836dc8
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 18 deletions.
5 changes: 4 additions & 1 deletion src/api/pc_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,10 @@ func (api *PcApi) ShutDownProject(c *gin.Context) {
// @Success 200 {object} object "Project State"
// @Router /project/state [get]
func (api *PcApi) GetProjectState(c *gin.Context) {
ports, err := api.project.GetProjectState()
withMemory := c.DefaultQuery("withMemory", "false")
checkMem, _ := strconv.ParseBool(withMemory)
ports, err := api.project.GetProjectState(checkMem)

if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
Expand Down
2 changes: 1 addition & 1 deletion src/app/project_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type IProject interface {
IsRemote() bool
ErrorForSecs() int
GetHostName() (string, error)
GetProjectState() (*types.ProjectState, error)
GetProjectState(checkMem bool) (*types.ProjectState, error)

GetLogLength() int
GetLogsAndSubscribe(name string, observer pclog.LogObserver) error
Expand Down
22 changes: 21 additions & 1 deletion src/app/project_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/f1bonacc1/process-compose/src/types"
"os"
"os/user"
"runtime"
"sync"
"time"

Expand Down Expand Up @@ -270,6 +271,7 @@ func (p *ProjectRunner) StopProcesses(names []string) ([]string, error) {
}

func (p *ProjectRunner) RestartProcess(name string) error {
log.Debug().Msgf("Restarting %s", name)
proc := p.getRunningProcess(name)
if proc != nil {
err := proc.shutDownNoRestart()
Expand Down Expand Up @@ -578,7 +580,7 @@ func (p *ProjectRunner) GetDependenciesOrderNames() ([]string, error) {
return p.project.GetDependenciesOrderNames()
}

func (p *ProjectRunner) GetProjectState() (*types.ProjectState, error) {
func (p *ProjectRunner) GetProjectState(checkMem bool) (*types.ProjectState, error) {
runningProcesses := 0
for name := range p.project.Processes {
state, err := p.GetProcessState(name)
Expand All @@ -591,6 +593,9 @@ func (p *ProjectRunner) GetProjectState() (*types.ProjectState, error) {
}
p.projectState.RunningProcessNum = runningProcesses
p.projectState.UpTime = time.Since(p.projectState.StartTime)
if checkMem {
p.projectState.MemoryState = getMemoryUsage()
}
return p.projectState, nil
}

Expand All @@ -601,6 +606,21 @@ func NewProjectRunner(
mainProcess string,
mainProcessArgs []string,
) (*ProjectRunner, error) {
func getMemoryUsage() *types.MemoryState {
var m runtime.MemStats
runtime.ReadMemStats(&m)
// For info on each, see: https://golang.org/pkg/runtime/#MemStats
return &types.MemoryState{
Allocated: bToMb(m.Alloc),
TotalAllocated: bToMb(m.TotalAlloc),
SystemMemory: bToMb(m.Sys),
GcCycles: m.NumGC,
}
}

func bToMb(b uint64) uint64 {
return b / 1024 / 1024
}

hostname, err := os.Hostname()
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions src/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,6 @@ func (p *PcClient) logError(err error) error {
return err
}

func (p *PcClient) GetProjectState() (*types.ProjectState, error) {
return p.getProjectState()
func (p *PcClient) GetProjectState(withMemory bool) (*types.ProjectState, error) {
return p.getProjectState(withMemory)
}
4 changes: 2 additions & 2 deletions src/client/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ func (p *PcClient) shutDownProject() error {
}
}

func (p *PcClient) getProjectState() (*types.ProjectState, error) {
url := fmt.Sprintf("http://%s:%d/project/state", p.address, p.port)
func (p *PcClient) getProjectState(withMemory bool) (*types.ProjectState, error) {
url := fmt.Sprintf("http://%s:%d/project/state/?withMemory=%v", p.address, p.port, withMemory)
resp, err := http.Get(url)
if err != nil {
return nil, err
Expand Down
35 changes: 24 additions & 11 deletions src/cmd/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,17 @@ import (
"time"
)

var (
withMemoryUsage = false
)

// stateCmd represents the state command
var stateCmd = &cobra.Command{
Use: "state",
Short: "Get Process Compose project state",
Run: func(cmd *cobra.Command, args []string) {
pcClient := client.NewClient(*pcFlags.Address, *pcFlags.PortNum, *pcFlags.LogLength)
state, err := pcClient.GetProjectState()
state, err := pcClient.GetProjectState(withMemoryUsage)
if err != nil {
logFatal(err, "failed to get project state")
}
Expand All @@ -30,29 +34,38 @@ var stateCmd = &cobra.Command{
}

func printState(state *types.ProjectState) {
col := color.New(color.FgGreen)
col.EnableColor()
green := col.SprintFunc()

longestKey := len("Running Processes")
printStateLine("Hostname", state.HostName, longestKey)
printStateLine("User", state.UserName, longestKey)
printStateLine("Version", state.Version, longestKey)
printStateLine("Up Time", state.UpTime.Round(time.Second).String(), longestKey)
printStateLine("Processes", strconv.Itoa(state.ProcessNum), longestKey)
printStateLine("Running Processes", strconv.Itoa(state.RunningProcessNum), longestKey)

green := color.New(color.FgGreen).SprintFunc()
printStateLine("Hostname", state.HostName, longestKey, green)
printStateLine("User", state.UserName, longestKey, green)
printStateLine("Version", state.Version, longestKey, green)
printStateLine("Up Time", state.UpTime.Round(time.Second).String(), longestKey, green)
printStateLine("Processes", strconv.Itoa(state.ProcessNum), longestKey, green)
printStateLine("Running Processes", strconv.Itoa(state.RunningProcessNum), longestKey, green)

fmt.Printf("%s:\n", green("File Names"))
for _, file := range state.FileNames {
fmt.Printf("\t - %s\n", file)
}

if state.MemoryState != nil {
printStateLine("Allocated MB", strconv.FormatUint(state.MemoryState.Allocated, 10), longestKey, green)
printStateLine("Total Alloc MB", strconv.FormatUint(state.MemoryState.TotalAllocated, 10), longestKey, green)
printStateLine("System MB", strconv.FormatUint(state.MemoryState.SystemMemory, 10), longestKey, green)
printStateLine("GC Cycles", strconv.Itoa(int(state.MemoryState.GcCycles)), longestKey, green)
}
}
func printStateLine(key, value string, longestKey int) {
func printStateLine(key, value string, longestKey int, green func(a ...interface{}) string) {
dotPads := longestKey - len(key)
padding := strings.Repeat(" ", dotPads)

green := color.New(color.FgGreen).SprintFunc()
fmt.Printf("%s:%s %s\n", green(key), padding, value)
}

func init() {
projectCmd.AddCommand(stateCmd)
stateCmd.Flags().BoolVar(&withMemoryUsage, "with-memory", false, "check memory usage")
}
8 changes: 8 additions & 0 deletions src/types/project_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,12 @@ type ProjectState struct {
UserName string `json:"userName"`
HostName string `json:"hostName"`
Version string `json:"version"`
MemoryState *MemoryState `json:"memoryState,omitempty"`
}

type MemoryState struct {
Allocated uint64 `json:"allocated"`
TotalAllocated uint64 `json:"totalAllocated"`
SystemMemory uint64 `json:"systemMemory"`
GcCycles uint32 `json:"gcCycles"`
}

0 comments on commit 5836dc8

Please sign in to comment.