-
Notifications
You must be signed in to change notification settings - Fork 5
feat: Add metrics tracking #96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
bdebdc8
8ec8d34
848970b
f42f28e
01f282c
0e76f23
d221075
a22b6ac
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,6 +7,7 @@ import ( | |
| "log" | ||
| "os" | ||
| "os/exec" | ||
| "strconv" | ||
| "strings" | ||
| "syscall" | ||
| "time" | ||
|
|
@@ -18,6 +19,7 @@ type host struct { | |
| log *log.Logger | ||
| spec types.Spec | ||
| types.Task | ||
| pid int | ||
| } | ||
alexec marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| func (h *host) Run(ctx context.Context, stdout, stderr io.Writer) error { | ||
|
|
@@ -48,6 +50,7 @@ func (h *host) Run(ctx context.Context, stdout, stderr io.Writer) error { | |
| // capture pgid straight away because it's not available after the process exits, | ||
| // the process may exit and leave children behind. | ||
| pid := cmd.Process.Pid | ||
| h.pid = pid | ||
| pgid, err := syscall.Getpgid(pid) | ||
| if err != nil { | ||
| return fmt.Errorf("failed get pgid: %w", err) | ||
|
|
@@ -86,4 +89,51 @@ func ignoreProcessFinishedErr(err error) error { | |
| return nil | ||
| } | ||
|
|
||
| var _ Interface = &host{} | ||
| func (h *host) GetMetrics(ctx context.Context) (*types.Metrics, error) { | ||
|
|
||
| // The `ps` command is used to get process information. | ||
| // -o %cpu,%mem specifies the desired output format: CPU and memory percentage. | ||
| // -p filters the output for the given PID. | ||
| cmd := exec.CommandContext(ctx, "ps", "-o", "%cpu,rss", "-p", strconv.Itoa(h.pid)) | ||
|
|
||
| // Execute the command and capture its output. | ||
| output, err := cmd.Output() | ||
| if err != nil { | ||
| // This error typically occurs if the PID does not exist. | ||
| return nil, fmt.Errorf("failed to get process metrics for pid %d: %w", h.pid, err) | ||
| } | ||
|
|
||
| // The output from `ps` includes a header line, so we need to parse the second line. | ||
| // Example output: | ||
| // %CPU %MEM | ||
| // 0.1 0.2 | ||
| lines := strings.Split(strings.TrimSpace(string(output)), "\n") | ||
| if len(lines) < 2 { | ||
| return nil, fmt.Errorf("unexpected ps output for pid %d: %s", h.pid, output) | ||
| } | ||
|
|
||
| // The second line contains the data. We split it by whitespace. | ||
| fields := strings.Fields(lines[1]) | ||
| if len(fields) < 2 { | ||
| return nil, fmt.Errorf("unexpected ps output format for pid %d: %s", h.pid, lines[1]) | ||
| } | ||
|
|
||
| // Parse the CPU usage from the first field. | ||
| cpuPercentage, err := strconv.ParseFloat(fields[0], 64) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("failed to parse CPU usage '%s': %w", fields[0], err) | ||
| } | ||
|
|
||
| cpuMillicores := cpuPercentage * 10 // Convert percentage to millicores (1% = 10 millicores) | ||
|
||
|
|
||
| rssMemoryKB, err := strconv.ParseInt(fields[1], 10, 64) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("failed to parse RSS memory '%s': %w", fields[1], err) | ||
| } | ||
|
|
||
| // Convert RSS memoryBytes from KB to bytes. | ||
| memoryBytes := uint64(rssMemoryKB * 1024) | ||
|
|
||
| return &types.Metrics{CPU: uint64(cpuMillicores), Mem: memoryBytes}, nil | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| package types | ||
|
|
||
| type Metrics struct { | ||
| CPU uint64 `json:"cpu"` // CPU usage in millicores | ||
| Mem uint64 `json:"mem"` // Memory usage in bytes | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.