package docker import ( "context" "encoding/json" "fmt" "github.com/moby/moby/api/types/container" "github.com/moby/moby/client" ) // ContainerStats holds computed CPU and memory usage for a container. type ContainerStats struct { CPUPercent float64 `json:"cpu_percent"` MemoryUsage int64 `json:"memory_usage"` MemoryLimit int64 `json:"memory_limit"` MemoryPercent float64 `json:"memory_percent"` } // GetContainerStats retrieves a one-shot stats snapshot for the given container // and computes CPU and memory percentages. func (c *Client) GetContainerStats(ctx context.Context, containerID string) (ContainerStats, error) { result, err := c.api.ContainerStats(ctx, containerID, client.ContainerStatsOptions{ Stream: false, IncludePreviousSample: true, }) if err != nil { return ContainerStats{}, fmt.Errorf("get container stats %s: %w", containerID, err) } defer result.Body.Close() var stats container.StatsResponse if err := json.NewDecoder(result.Body).Decode(&stats); err != nil { return ContainerStats{}, fmt.Errorf("decode container stats %s: %w", containerID, err) } cpuPercent := calculateCPUPercent(stats) memUsage := int64(stats.MemoryStats.Usage) memLimit := int64(stats.MemoryStats.Limit) var memPercent float64 if memLimit > 0 { memPercent = float64(memUsage) / float64(memLimit) * 100.0 } return ContainerStats{ CPUPercent: cpuPercent, MemoryUsage: memUsage, MemoryLimit: memLimit, MemoryPercent: memPercent, }, nil } // calculateCPUPercent computes CPU usage percentage from a stats response // using the delta between current and previous CPU readings. func calculateCPUPercent(stats container.StatsResponse) float64 { cpuDelta := float64(stats.CPUStats.CPUUsage.TotalUsage) - float64(stats.PreCPUStats.CPUUsage.TotalUsage) systemDelta := float64(stats.CPUStats.SystemUsage) - float64(stats.PreCPUStats.SystemUsage) if systemDelta <= 0 || cpuDelta < 0 { return 0.0 } onlineCPUs := float64(stats.CPUStats.OnlineCPUs) if onlineCPUs == 0 { onlineCPUs = 1 } return (cpuDelta / systemDelta) * onlineCPUs * 100.0 }