7c57c740b4
Add container monitoring and notification system: - Docker Stats API: real-time CPU/memory for running containers - Webhook notifications for errors (deploy failures, stale, proxy unhealthy) - Event log auto-pruning (daily, 30-day retention) - ContainerStats component with auto-polling progress bars - SystemHealthCard dashboard widget with running/proxy/error counts - Full EN/RU i18n for stats and system health
70 lines
2.1 KiB
Go
70 lines
2.1 KiB
Go
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
|
|
}
|