Skip to content
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

Fix missing VM metrics #262

Merged
merged 3 commits into from
Dec 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 18 additions & 12 deletions cmd/incus-agent/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,13 @@ func metricsGet(d *Daemon, r *http.Request) response.Response {
return response.SyncResponse(true, &out)
}

func getCPUMetrics(d *Daemon) (map[string]metrics.CPUMetrics, error) {
func getCPUMetrics(d *Daemon) ([]metrics.CPUMetrics, error) {
stats, err := os.ReadFile("/proc/stat")
if err != nil {
return nil, fmt.Errorf("Failed to read /proc/stat: %w", err)
}

out := map[string]metrics.CPUMetrics{}
out := []metrics.CPUMetrics{}
scanner := bufio.NewScanner(bytes.NewReader(stats))

for scanner.Scan() {
Expand Down Expand Up @@ -158,7 +158,8 @@ func getCPUMetrics(d *Daemon) (map[string]metrics.CPUMetrics, error) {

stats.SecondsSteal /= 100

out[fields[0]] = stats
stats.CPU = fields[0]
out = append(out, stats)
}

return out, nil
Expand Down Expand Up @@ -203,13 +204,13 @@ func getTotalProcesses(d *Daemon) (uint64, error) {
return pidCount, nil
}

func getDiskMetrics(d *Daemon) (map[string]metrics.DiskMetrics, error) {
func getDiskMetrics(d *Daemon) ([]metrics.DiskMetrics, error) {
diskStats, err := os.ReadFile("/proc/diskstats")
if err != nil {
return nil, fmt.Errorf("Failed to read /proc/diskstats: %w", err)
}

out := map[string]metrics.DiskMetrics{}
out := []metrics.DiskMetrics{}
scanner := bufio.NewScanner(bytes.NewReader(diskStats))

for scanner.Scan() {
Expand Down Expand Up @@ -250,19 +251,20 @@ func getDiskMetrics(d *Daemon) (map[string]metrics.DiskMetrics, error) {

stats.WrittenBytes = sectorsWritten * 512

out[fields[2]] = stats
stats.Device = fields[2]
out = append(out, stats)
}

return out, nil
}

func getFilesystemMetrics(d *Daemon) (map[string]metrics.FilesystemMetrics, error) {
func getFilesystemMetrics(d *Daemon) ([]metrics.FilesystemMetrics, error) {
mounts, err := os.ReadFile("/proc/mounts")
if err != nil {
return nil, fmt.Errorf("Failed to read /proc/mounts: %w", err)
}

out := map[string]metrics.FilesystemMetrics{}
out := []metrics.FilesystemMetrics{}
scanner := bufio.NewScanner(bytes.NewReader(mounts))

for scanner.Scan() {
Expand Down Expand Up @@ -296,7 +298,9 @@ func getFilesystemMetrics(d *Daemon) (map[string]metrics.FilesystemMetrics, erro
stats.FreeBytes = statfs.Bfree * uint64(statfs.Bsize)
stats.SizeBytes = statfs.Blocks * uint64(statfs.Bsize)

out[fields[0]] = stats
stats.Device = fields[0]

out = append(out, stats)
}

return out, nil
Expand Down Expand Up @@ -375,8 +379,8 @@ func getMemoryMetrics(d *Daemon) (metrics.MemoryMetrics, error) {
return out, nil
}

func getNetworkMetrics(d *Daemon) (map[string]metrics.NetworkMetrics, error) {
out := map[string]metrics.NetworkMetrics{}
func getNetworkMetrics(d *Daemon) ([]metrics.NetworkMetrics, error) {
out := []metrics.NetworkMetrics{}

for dev, state := range networkState() {
stats := metrics.NetworkMetrics{}
Expand All @@ -390,7 +394,9 @@ func getNetworkMetrics(d *Daemon) (map[string]metrics.NetworkMetrics, error) {
stats.TransmitErrors = uint64(state.Counters.ErrorsSent)
stats.TransmitPackets = uint64(state.Counters.PacketsSent)

out[dev] = stats
stats.Device = dev

out = append(out, stats)
}

return out, nil
Expand Down
24 changes: 14 additions & 10 deletions internal/server/instance/drivers/driver_qemu_metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,11 @@ func (d *qemu) getQemuMetrics() (*metrics.MetricSet, error) {
if err != nil {
d.logger.Warn("Failed to get network metrics", logger.Ctx{"err": err})
} else {
out.Network = make(map[string]metrics.NetworkMetrics)
out.Network = make([]metrics.NetworkMetrics, 0, len(networkState))

for name, state := range networkState {
out.Network[name] = metrics.NetworkMetrics{
out.Network = append(out.Network, metrics.NetworkMetrics{
Device: name,
ReceiveBytes: uint64(state.Counters.BytesReceived),
ReceiveDrop: uint64(state.Counters.PacketsDroppedInbound),
ReceiveErrors: uint64(state.Counters.ErrorsReceived),
Expand All @@ -62,7 +63,7 @@ func (d *qemu) getQemuMetrics() (*metrics.MetricSet, error) {
TransmitDrop: uint64(state.Counters.PacketsDroppedOutbound),
TransmitErrors: uint64(state.Counters.ErrorsSent),
TransmitPackets: uint64(state.Counters.PacketsSent),
}
})
}
}

Expand All @@ -74,21 +75,22 @@ func (d *qemu) getQemuMetrics() (*metrics.MetricSet, error) {
return metricSet, nil
}

func (d *qemu) getQemuDiskMetrics(monitor *qmp.Monitor) (map[string]metrics.DiskMetrics, error) {
func (d *qemu) getQemuDiskMetrics(monitor *qmp.Monitor) ([]metrics.DiskMetrics, error) {
stats, err := monitor.GetBlockStats()
if err != nil {
return nil, err
}

out := make(map[string]metrics.DiskMetrics)
out := make([]metrics.DiskMetrics, 0, len(stats))

for dev, stat := range stats {
out[dev] = metrics.DiskMetrics{
out = append(out, metrics.DiskMetrics{
Device: dev,
ReadBytes: uint64(stat.BytesRead),
ReadsCompleted: uint64(stat.ReadsCompleted),
WrittenBytes: uint64(stat.BytesWritten),
WritesCompleted: uint64(stat.WritesCompleted),
}
})
}

return out, nil
Expand Down Expand Up @@ -162,14 +164,14 @@ func (d *qemu) getQemuMemoryMetrics(monitor *qmp.Monitor) (metrics.MemoryMetrics
return out, nil
}

func (d *qemu) getQemuCPUMetrics(monitor *qmp.Monitor) (map[string]metrics.CPUMetrics, error) {
func (d *qemu) getQemuCPUMetrics(monitor *qmp.Monitor) ([]metrics.CPUMetrics, error) {
// Get CPU metrics
threadIDs, err := monitor.GetCPUs()
if err != nil {
return nil, err
}

cpuMetrics := map[string]metrics.CPUMetrics{}
cpuMetrics := make([]metrics.CPUMetrics, 0, len(threadIDs))

for i, threadID := range threadIDs {
pid, err := os.ReadFile(d.pidFilePath())
Expand Down Expand Up @@ -213,7 +215,9 @@ func (d *qemu) getQemuCPUMetrics(monitor *qmp.Monitor) (map[string]metrics.CPUMe

stats.SecondsSystem /= 100

cpuMetrics[fmt.Sprintf("cpu%d", i)] = stats
stats.CPU = fmt.Sprintf("cpu%d", i)

cpuMetrics = append(cpuMetrics, stats)
}

return cpuMetrics, nil
Expand Down
18 changes: 11 additions & 7 deletions internal/server/metrics/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@ package metrics

// Metrics represents instance metrics.
type Metrics struct {
CPU map[string]CPUMetrics `json:"cpu_seconds_total" yaml:"cpu_seconds_total"`
CPUs int `json:"cpus" yaml:"cpus"`
Disk map[string]DiskMetrics `json:"disk" yaml:"disk"`
Filesystem map[string]FilesystemMetrics `json:"filesystem" yaml:"filesystem"`
Memory MemoryMetrics `json:"memory" yaml:"memory"`
Network map[string]NetworkMetrics `json:"network" yaml:"network"`
ProcessesTotal uint64 `json:"procs_total" yaml:"procs_total"`
CPU []CPUMetrics `json:"cpu_seconds_total" yaml:"cpu_seconds_total"`
CPUs int `json:"cpus" yaml:"cpus"`
Disk []DiskMetrics `json:"disk" yaml:"disk"`
Filesystem []FilesystemMetrics `json:"filesystem" yaml:"filesystem"`
Memory MemoryMetrics `json:"memory" yaml:"memory"`
Network []NetworkMetrics `json:"network" yaml:"network"`
ProcessesTotal uint64 `json:"procs_total" yaml:"procs_total"`
}

// CPUMetrics represents CPU metrics for an instance.
type CPUMetrics struct {
CPU string `json:"cpu" yaml:"cpu"`
SecondsUser float64 `json:"cpu_seconds_user" yaml:"cpu_seconds_user"`
SecondsNice float64 `json:"cpu_seconds_nice" yaml:"cpu_seconds_nice"`
SecondsSystem float64 `json:"cpu_seconds_system" yaml:"cpu_seconds_system"`
Expand All @@ -25,6 +26,7 @@ type CPUMetrics struct {

// DiskMetrics represents disk metrics for an instance.
type DiskMetrics struct {
Device string `json:"device" yaml:"device"`
ReadBytes uint64 `json:"disk_read_bytes" yaml:"disk_read_bytes"`
ReadsCompleted uint64 `json:"disk_reads_completed" yaml:"disk_reads_completes"`
WrittenBytes uint64 `json:"disk_written_bytes" yaml:"disk_written_bytes"`
Expand All @@ -33,6 +35,7 @@ type DiskMetrics struct {

// FilesystemMetrics represents filesystem metrics for an instance.
type FilesystemMetrics struct {
Device string `json:"device" yaml:"device"`
Mountpoint string `json:"mountpoint" yaml:"mountpoint"`
FSType string `json:"fstype" yaml:"fstype"`
AvailableBytes uint64 `json:"filesystem_avail_bytes" yaml:"filesystem_avail_bytes"`
Expand Down Expand Up @@ -66,6 +69,7 @@ type MemoryMetrics struct {

// NetworkMetrics represents network metrics for an instance.
type NetworkMetrics struct {
Device string `json:"device" yaml:"device"`
ReceiveBytes uint64 `json:"network_receive_bytes" yaml:"network_receive_bytes"`
ReceiveDrop uint64 `json:"network_receive_drop" yaml:"network_receive_drop"`
ReceiveErrors uint64 `json:"network_receive_errs" yaml:"network_receive_errs"`
Expand Down
18 changes: 9 additions & 9 deletions internal/server/metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,13 @@ func MetricSetFromAPI(metrics *Metrics, labels map[string]string) (*MetricSet, e
set := NewMetricSet(labels)

// CPU stats
for dev, stats := range metrics.CPU {
for _, stats := range metrics.CPU {
getLabels := func(mode string) map[string]string {
labels := map[string]string{"mode": mode}
cpu := ""

if dev != "cpu" {
_, _ = fmt.Sscanf(dev, "cpu%s", &cpu)
if stats.CPU != "cpu" {
_, _ = fmt.Sscanf(stats.CPU, "cpu%s", &cpu)
}

if cpu != "" {
Expand Down Expand Up @@ -223,8 +223,8 @@ func MetricSetFromAPI(metrics *Metrics, labels map[string]string) (*MetricSet, e
set.AddSamples(CPUs, Sample{Value: float64(metrics.CPUs)})

// Disk stats
for dev, stats := range metrics.Disk {
labels := map[string]string{"device": dev}
for _, stats := range metrics.Disk {
labels := map[string]string{"device": stats.Device}

set.AddSamples(DiskReadBytesTotal, Sample{Value: float64(stats.ReadBytes), Labels: labels})
set.AddSamples(DiskReadsCompletedTotal, Sample{Value: float64(stats.ReadsCompleted), Labels: labels})
Expand All @@ -233,8 +233,8 @@ func MetricSetFromAPI(metrics *Metrics, labels map[string]string) (*MetricSet, e
}

// Filesystem stats
for dev, stats := range metrics.Filesystem {
labels := map[string]string{"device": dev, "fstype": stats.FSType, "mountpoint": stats.Mountpoint}
for _, stats := range metrics.Filesystem {
labels := map[string]string{"device": stats.Device, "fstype": stats.FSType, "mountpoint": stats.Mountpoint}

set.AddSamples(FilesystemAvailBytes, Sample{Value: float64(stats.AvailableBytes), Labels: labels})
set.AddSamples(FilesystemFreeBytes, Sample{Value: float64(stats.FreeBytes), Labels: labels})
Expand Down Expand Up @@ -264,8 +264,8 @@ func MetricSetFromAPI(metrics *Metrics, labels map[string]string) (*MetricSet, e
set.AddSamples(MemoryOOMKillsTotal, Sample{Value: float64(metrics.Memory.OOMKills)})

// Network stats
for dev, stats := range metrics.Network {
labels := map[string]string{"device": dev}
for _, stats := range metrics.Network {
labels := map[string]string{"device": stats.Device}

set.AddSamples(NetworkReceiveBytesTotal, Sample{Value: float64(stats.ReceiveBytes), Labels: labels})
set.AddSamples(NetworkReceiveDropTotal, Sample{Value: float64(stats.ReceiveDrop), Labels: labels})
Expand Down
Loading