diff --git a/cmd/ctr/commands/tasks/metrics.go b/cmd/ctr/commands/tasks/metrics.go index c980ced93..eb917ac95 100644 --- a/cmd/ctr/commands/tasks/metrics.go +++ b/cmd/ctr/commands/tasks/metrics.go @@ -152,6 +152,20 @@ func printCgroup2MetricsTable(w *tabwriter.Writer, data *v2.Metrics) { fmt.Fprintf(w, "pids.current\t%v\t\n", data.Pids.Current) fmt.Fprintf(w, "pids.limit\t%v\t\n", data.Pids.Limit) } + if data.CPU != nil { + fmt.Fprintf(w, "cpu.usage_usec\t%v\t\n", data.CPU.UsageUsec) + fmt.Fprintf(w, "cpu.user_usec\t%v\t\n", data.CPU.UserUsec) + fmt.Fprintf(w, "cpu.sys_usec\t%v\t\n", data.CPU.SystemUsec) + fmt.Fprintf(w, "cpu.number_of_periods\t%v\t\n", data.CPU.NrPeriods) + fmt.Fprintf(w, "cpu.number_of_throttled\t%v\t\n", data.CPU.NrThrottled) + fmt.Fprintf(w, "cpu.throttled_usec\t%v\t\n", data.CPU.ThrottledUsec) + } + if data.Memory != nil { + fmt.Fprintf(w, "memory.usage\t%v\t\n", data.Memory.Usage) + fmt.Fprintf(w, "memory.usage_limit\t%v\t\n", data.Memory.UsageLimit) + fmt.Fprintf(w, "memory.swap\t%v\t\n", data.Memory.SwapUsage) + fmt.Fprintf(w, "memory.swap_limit\t%v\t\n", data.Memory.SwapLimit) + } } func printWindowsContainerStatistics(w *tabwriter.Writer, stats *wstats.WindowsContainerStatistics) { diff --git a/metrics/cgroups/v2/cpu.go b/metrics/cgroups/v2/cpu.go new file mode 100644 index 000000000..bd8754b20 --- /dev/null +++ b/metrics/cgroups/v2/cpu.go @@ -0,0 +1,124 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + v2 "github.com/containerd/containerd/metrics/types/v2" + metrics "github.com/docker/go-metrics" + "github.com/prometheus/client_golang/prometheus" +) + +var cpuMetrics = []*metric{ + { + name: "cpu", + help: "Current cpu usage_usec (cgroup v2)", + unit: metrics.Unit("usage_usec"), + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.CPU == nil { + return nil + } + return []value{ + { + v: float64(stats.CPU.UsageUsec), + }, + } + }, + }, + { + name: "cpu", + help: "Current cpu user_usec (cgroup v2)", + unit: metrics.Unit("user_usec"), + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.CPU == nil { + return nil + } + return []value{ + { + v: float64(stats.CPU.UserUsec), + }, + } + }, + }, + { + name: "cpu", + help: "Current cpu system_usec (cgroup v2)", + unit: metrics.Unit("system_usec"), + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.CPU == nil { + return nil + } + return []value{ + { + v: float64(stats.CPU.SystemUsec), + }, + } + }, + }, + { + name: "cpu", + help: "Current cpu nr_periods (only if controller is enabled)", + unit: metrics.Unit("nr_periods"), + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.CPU == nil { + return nil + } + return []value{ + { + v: float64(stats.CPU.NrPeriods), + }, + } + }, + }, + { + name: "cpu", + help: "Current cpu nr_throttled (only if controller is enabled)", + unit: metrics.Unit("nr_throttled"), + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.CPU == nil { + return nil + } + return []value{ + { + v: float64(stats.CPU.NrThrottled), + }, + } + }, + }, + { + name: "cpu", + help: "Current cpu throttled_usec (only if controller is enabled)", + unit: metrics.Unit("throttled_usec"), + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.CPU == nil { + return nil + } + return []value{ + { + v: float64(stats.CPU.ThrottledUsec), + }, + } + }, + }, +} diff --git a/metrics/cgroups/v2/memory.go b/metrics/cgroups/v2/memory.go new file mode 100644 index 000000000..25c221bc0 --- /dev/null +++ b/metrics/cgroups/v2/memory.go @@ -0,0 +1,92 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + v2 "github.com/containerd/containerd/metrics/types/v2" + metrics "github.com/docker/go-metrics" + "github.com/prometheus/client_golang/prometheus" +) + +var memoryMetrics = []*metric{ + { + name: "memory", + help: "Current memory usage (cgroup v2)", + unit: metrics.Unit("usage"), + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Usage), + }, + } + }, + }, + { + name: "memory", + help: "Current memory usage limit (cgroup v2)", + unit: metrics.Unit("limit"), + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.UsageLimit), + }, + } + }, + }, + { + name: "memory", + help: "Current swap usage (cgroup v2)", + unit: metrics.Unit("swap"), + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.SwapUsage), + }, + } + }, + }, + { + name: "memory", + help: "Current swap usage limit (cgroup v2)", + unit: metrics.Unit("swap_limit"), + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.SwapLimit), + }, + } + }, + }, +} diff --git a/metrics/cgroups/v2/metrics.go b/metrics/cgroups/v2/metrics.go index 134af9e62..bfb6f0553 100644 --- a/metrics/cgroups/v2/metrics.go +++ b/metrics/cgroups/v2/metrics.go @@ -43,6 +43,8 @@ func newCollector(ns *metrics.Namespace) *collector { tasks: make(map[string]runtime.Task), } c.metrics = append(c.metrics, pidMetrics...) + c.metrics = append(c.metrics, cpuMetrics...) + c.metrics = append(c.metrics, memoryMetrics...) c.storedMetrics = make(chan prometheus.Metric, 100*len(c.metrics)) ns.Add(c) return c