Add CPU and memory metrics to enclave ping response#33
Conversation
18b534b to
f8f108f
Compare
Read from /proc/meminfo and /proc/stat so we can observe resource utilization inside the Nitro Enclave via the existing ping/pong health check. The system info is included as an optional "system" key in the pong JSON; if procfs is unavailable the pong still succeeds without it. Made-with: Cursor
f8f108f to
7ccc27b
Compare
There was a problem hiding this comment.
Pull request overview
This PR extends the enclave ping/pong health response to optionally include basic CPU and memory utilization metrics sourced from procfs, without adding new dependencies.
Changes:
- Add procfs parsing + CPU sampling logic to produce
SystemInfo(mem totals/usage, CPU usage, CPU count). - Include system metrics in the
pongJSON response. - Add unit tests for
/proc/meminfoand/proc/statparsing using temp-file fixtures.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
enclave/sysinfo.go |
Implements procfs parsing and CPU usage sampling to populate SystemInfo. |
enclave/sysinfo_test.go |
Adds fixture-based unit tests for meminfo/stat parsing helpers. |
enclave/server.go |
Adds a system field to the ping/pong response payload. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // parseCPULine parses the aggregate "cpu ..." line from /proc/stat. | ||
| // Fields: user nice system idle iowait irq softirq steal [guest guest_nice] | ||
| func parseCPULine(line string) (*cpuTicks, error) { | ||
| fields := strings.Fields(line) | ||
| if len(fields) < 5 { | ||
| return nil, fmt.Errorf("unexpected cpu line format: %q", line) | ||
| } | ||
|
|
||
| var total, idle uint64 | ||
| for i, f := range fields[1:] { | ||
| v, err := strconv.ParseUint(f, 10, 64) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("parsing field %d of cpu line: %w", i, err) | ||
| } | ||
| total += v | ||
| if i == 3 { // idle is the 4th value (0-indexed field 3) | ||
| idle = v | ||
| } | ||
| } | ||
| return &cpuTicks{total: total, idle: idle}, nil |
There was a problem hiding this comment.
parseCPULine currently sums all numeric fields in the aggregate "cpu" line, including guest and guest_nice when present. In /proc/stat these guest fields are already included in the user/nice times, so adding them again double-counts CPU time and skews CPU usage percentages on kernels that expose guest fields. Consider excluding guest/guest_nice from the total (or subtracting them back out of user/nice) so totals match the kernel accounting model.
## Summary - `parseCPULine` was summing all fields from `/proc/stat` including `guest` and `guest_nice`, which the Linux kernel already includes in `user` and `nice` -- this double-counts CPU time on kernels that report those fields - Now caps parsing at the first 8 fields (user through steal) - Follow-up to #33 ## Test plan - [x] Updated `TestParseCPULine_WithGuestFields` to assert guest fields are excluded from the total - [x] Full test suite passes Made with [Cursor](https://cursor.com)
Summary
/proc/meminfoand/proc/stat"system"key in the pong JSON; if procfs is unavailable the pong still returns healthy without itExample response
{ "type": "pong", "message": "TEE server is healthy", "timestamp": 1709500000, "system": { "mem_total_bytes": 1073741824, "mem_used_bytes": 536870912, "mem_usage_percent": 50.0, "cpu_usage_percent": 23.5, "num_cpus": 2 } }Test plan
go test ./...)Made with Cursor