From b0ecf2f67985fa4f947814c8cf616fbe670b1d27 Mon Sep 17 00:00:00 2001 From: Tyler Helmuth <12352919+TylerHelmuth@users.noreply.github.com> Date: Fri, 29 Sep 2023 11:23:20 -0600 Subject: [PATCH] [receiver/kubeletstats] Add new memory utilization metrics (#25894) **Description:** Adds new `k8s.pod.memory.utilization` and `container.memory.utilization` metrics that represent the ratio of memory used vs limits set. The metrics are only emitted for pods/containers that have defined resource limits. It takes advantage of the pod metadata to acquire the container limits. A pod limit is computed as the sum of all the container limits and if any container limit is zero or undefined the pod limit is also considered undefined. **Link to tracking Issue:** Related to https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/24905 **Testing:** Unit tests and local testing --- .../kubeletstats-memory-utilization.yaml | 27 ++ .../kubeletstats-percentage-metrics.yaml | 27 ++ .../kubeletstatsreceiver/documentation.md | 32 ++ .../internal/kubelet/accumulator.go | 6 +- .../internal/kubelet/accumulator_test.go | 8 +- .../internal/kubelet/mem.go | 11 +- .../internal/metadata/generated_config.go | 106 +++-- .../metadata/generated_config_test.go | 188 ++++---- .../internal/metadata/generated_metrics.go | 426 ++++++++++++++---- .../metadata/generated_metrics_test.go | 60 +++ .../internal/metadata/metrics.go | 47 +- .../internal/metadata/testdata/config.yaml | 16 + receiver/kubeletstatsreceiver/metadata.yaml | 28 ++ receiver/kubeletstatsreceiver/scraper.go | 8 +- receiver/kubeletstatsreceiver/scraper_test.go | 177 ++++++++ .../kubeletstatsreceiver/testdata/pods.json | 17 + 16 files changed, 920 insertions(+), 264 deletions(-) create mode 100755 .chloggen/kubeletstats-memory-utilization.yaml create mode 100755 .chloggen/kubeletstats-percentage-metrics.yaml diff --git a/.chloggen/kubeletstats-memory-utilization.yaml b/.chloggen/kubeletstats-memory-utilization.yaml new file mode 100755 index 000000000000..89e9788dce28 --- /dev/null +++ b/.chloggen/kubeletstats-memory-utilization.yaml @@ -0,0 +1,27 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: kubeletstatsreceiver + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Adds new `k8s.pod.memory.utilization` and `container.memory.utilization` metrics that represent the ratio of memory used vs limits set. + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [25894] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# If your change doesn't affect end users or the exported elements of any package, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [] diff --git a/.chloggen/kubeletstats-percentage-metrics.yaml b/.chloggen/kubeletstats-percentage-metrics.yaml new file mode 100755 index 000000000000..7b8f846878ab --- /dev/null +++ b/.chloggen/kubeletstats-percentage-metrics.yaml @@ -0,0 +1,27 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: kubeletstatsreceiver + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Add new metrics for representing pod and memory consumption of pods and containers as a percentage of the defined resource limits. + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [25835] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: These metrics represent how much of your resource limits a container or pod is consuming. + +# If your change doesn't affect end users or the exported elements of any package, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [] diff --git a/receiver/kubeletstatsreceiver/documentation.md b/receiver/kubeletstatsreceiver/documentation.md index 97f5c83f90e4..bd2aede3283f 100644 --- a/receiver/kubeletstatsreceiver/documentation.md +++ b/receiver/kubeletstatsreceiver/documentation.md @@ -394,6 +394,22 @@ The time since the container started | ---- | ----------- | ---------- | ----------------------- | --------- | | s | Sum | Int | Cumulative | true | +### k8s.container.memory_limit_utilization + +Container memory utilization as a ratio of the container's limits + +| Unit | Metric Type | Value Type | +| ---- | ----------- | ---------- | +| 1 | Gauge | Double | + +### k8s.container.memory_request_utilization + +Container memory utilization as a ratio of the container's requests + +| Unit | Metric Type | Value Type | +| ---- | ----------- | ---------- | +| 1 | Gauge | Double | + ### k8s.node.uptime The time since the node started @@ -402,6 +418,22 @@ The time since the node started | ---- | ----------- | ---------- | ----------------------- | --------- | | s | Sum | Int | Cumulative | true | +### k8s.pod.memory_limit_utilization + +Pod memory utilization as a ratio of the pod's total container limits. If any container is missing a limit the metric is not emitted. + +| Unit | Metric Type | Value Type | +| ---- | ----------- | ---------- | +| 1 | Gauge | Double | + +### k8s.pod.memory_request_utilization + +Pod memory utilization as a ratio of the pod's total container requests. If any container is missing a request the metric is not emitted. + +| Unit | Metric Type | Value Type | +| ---- | ----------- | ---------- | +| 1 | Gauge | Double | + ### k8s.pod.uptime The time since the pod started diff --git a/receiver/kubeletstatsreceiver/internal/kubelet/accumulator.go b/receiver/kubeletstatsreceiver/internal/kubelet/accumulator.go index 858b969900cc..53d206b73710 100644 --- a/receiver/kubeletstatsreceiver/internal/kubelet/accumulator.go +++ b/receiver/kubeletstatsreceiver/internal/kubelet/accumulator.go @@ -57,7 +57,7 @@ func (a *metricDataAccumulator) nodeStats(s stats.NodeStats) { currentTime := pcommon.NewTimestampFromTime(a.time) addUptimeMetric(a.mbs.NodeMetricsBuilder, metadata.NodeUptimeMetrics.Uptime, s.StartTime, currentTime) addCPUMetrics(a.mbs.NodeMetricsBuilder, metadata.NodeCPUMetrics, s.CPU, currentTime) - addMemoryMetrics(a.mbs.NodeMetricsBuilder, metadata.NodeMemoryMetrics, s.Memory, currentTime) + addMemoryMetrics(a.mbs.NodeMetricsBuilder, metadata.NodeMemoryMetrics, s.Memory, currentTime, resources{}) addFilesystemMetrics(a.mbs.NodeMetricsBuilder, metadata.NodeFilesystemMetrics, s.Fs, currentTime) addNetworkMetrics(a.mbs.NodeMetricsBuilder, metadata.NodeNetworkMetrics, s.Network, currentTime) // todo s.Runtime.ImageFs @@ -77,7 +77,7 @@ func (a *metricDataAccumulator) podStats(s stats.PodStats) { currentTime := pcommon.NewTimestampFromTime(a.time) addUptimeMetric(a.mbs.PodMetricsBuilder, metadata.PodUptimeMetrics.Uptime, s.StartTime, currentTime) addCPUMetrics(a.mbs.PodMetricsBuilder, metadata.PodCPUMetrics, s.CPU, currentTime) - addMemoryMetrics(a.mbs.PodMetricsBuilder, metadata.PodMemoryMetrics, s.Memory, currentTime) + addMemoryMetrics(a.mbs.PodMetricsBuilder, metadata.PodMemoryMetrics, s.Memory, currentTime, a.metadata.podResources[s.PodRef.UID]) addFilesystemMetrics(a.mbs.PodMetricsBuilder, metadata.PodFilesystemMetrics, s.EphemeralStorage, currentTime) addNetworkMetrics(a.mbs.PodMetricsBuilder, metadata.PodNetworkMetrics, s.Network, currentTime) @@ -110,7 +110,7 @@ func (a *metricDataAccumulator) containerStats(sPod stats.PodStats, s stats.Cont currentTime := pcommon.NewTimestampFromTime(a.time) addUptimeMetric(a.mbs.ContainerMetricsBuilder, metadata.ContainerUptimeMetrics.Uptime, s.StartTime, currentTime) addCPUMetrics(a.mbs.ContainerMetricsBuilder, metadata.ContainerCPUMetrics, s.CPU, currentTime) - addMemoryMetrics(a.mbs.ContainerMetricsBuilder, metadata.ContainerMemoryMetrics, s.Memory, currentTime) + addMemoryMetrics(a.mbs.ContainerMetricsBuilder, metadata.ContainerMemoryMetrics, s.Memory, currentTime, a.metadata.containerResources[sPod.PodRef.UID+s.Name]) addFilesystemMetrics(a.mbs.ContainerMetricsBuilder, metadata.ContainerFilesystemMetrics, s.Rootfs, currentTime) a.m = append(a.m, a.mbs.ContainerMetricsBuilder.Emit( diff --git a/receiver/kubeletstatsreceiver/internal/kubelet/accumulator_test.go b/receiver/kubeletstatsreceiver/internal/kubelet/accumulator_test.go index 5068e0f23ffa..fd18bfd27096 100644 --- a/receiver/kubeletstatsreceiver/internal/kubelet/accumulator_test.go +++ b/receiver/kubeletstatsreceiver/internal/kubelet/accumulator_test.go @@ -44,12 +44,10 @@ func TestMetadataErrorCases(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ UID: "pod-uid-123", }, - Status: v1.PodStatus{ - ContainerStatuses: []v1.ContainerStatus{ + Spec: v1.PodSpec{ + Containers: []v1.Container{ { - // different container name - Name: "container2", - ContainerID: "test-container", + Name: "container2", }, }, }, diff --git a/receiver/kubeletstatsreceiver/internal/kubelet/mem.go b/receiver/kubeletstatsreceiver/internal/kubelet/mem.go index 977f21b8bb8f..85713e5234c0 100644 --- a/receiver/kubeletstatsreceiver/internal/kubelet/mem.go +++ b/receiver/kubeletstatsreceiver/internal/kubelet/mem.go @@ -10,7 +10,7 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/kubeletstatsreceiver/internal/metadata" ) -func addMemoryMetrics(mb *metadata.MetricsBuilder, memoryMetrics metadata.MemoryMetrics, s *stats.MemoryStats, currentTime pcommon.Timestamp) { +func addMemoryMetrics(mb *metadata.MetricsBuilder, memoryMetrics metadata.MemoryMetrics, s *stats.MemoryStats, currentTime pcommon.Timestamp, r resources) { if s == nil { return } @@ -21,4 +21,13 @@ func addMemoryMetrics(mb *metadata.MetricsBuilder, memoryMetrics metadata.Memory recordIntDataPoint(mb, memoryMetrics.WorkingSet, s.WorkingSetBytes, currentTime) recordIntDataPoint(mb, memoryMetrics.PageFaults, s.PageFaults, currentTime) recordIntDataPoint(mb, memoryMetrics.MajorPageFaults, s.MajorPageFaults, currentTime) + + if s.UsageBytes != nil { + if r.memoryLimit > 0 { + memoryMetrics.LimitUtilization(mb, currentTime, float64(*s.UsageBytes)/float64(r.memoryLimit)) + } + if r.memoryRequest > 0 { + memoryMetrics.RequestUtilization(mb, currentTime, float64(*s.UsageBytes)/float64(r.memoryRequest)) + } + } } diff --git a/receiver/kubeletstatsreceiver/internal/metadata/generated_config.go b/receiver/kubeletstatsreceiver/internal/metadata/generated_config.go index 5ee2e99b88ce..f8c68b4cee49 100644 --- a/receiver/kubeletstatsreceiver/internal/metadata/generated_config.go +++ b/receiver/kubeletstatsreceiver/internal/metadata/generated_config.go @@ -25,51 +25,55 @@ func (ms *MetricConfig) Unmarshal(parser *confmap.Conf) error { // MetricsConfig provides config for kubeletstats metrics. type MetricsConfig struct { - ContainerCPUTime MetricConfig `mapstructure:"container.cpu.time"` - ContainerCPUUtilization MetricConfig `mapstructure:"container.cpu.utilization"` - ContainerFilesystemAvailable MetricConfig `mapstructure:"container.filesystem.available"` - ContainerFilesystemCapacity MetricConfig `mapstructure:"container.filesystem.capacity"` - ContainerFilesystemUsage MetricConfig `mapstructure:"container.filesystem.usage"` - ContainerMemoryAvailable MetricConfig `mapstructure:"container.memory.available"` - ContainerMemoryMajorPageFaults MetricConfig `mapstructure:"container.memory.major_page_faults"` - ContainerMemoryPageFaults MetricConfig `mapstructure:"container.memory.page_faults"` - ContainerMemoryRss MetricConfig `mapstructure:"container.memory.rss"` - ContainerMemoryUsage MetricConfig `mapstructure:"container.memory.usage"` - ContainerMemoryWorkingSet MetricConfig `mapstructure:"container.memory.working_set"` - ContainerUptime MetricConfig `mapstructure:"container.uptime"` - K8sNodeCPUTime MetricConfig `mapstructure:"k8s.node.cpu.time"` - K8sNodeCPUUtilization MetricConfig `mapstructure:"k8s.node.cpu.utilization"` - K8sNodeFilesystemAvailable MetricConfig `mapstructure:"k8s.node.filesystem.available"` - K8sNodeFilesystemCapacity MetricConfig `mapstructure:"k8s.node.filesystem.capacity"` - K8sNodeFilesystemUsage MetricConfig `mapstructure:"k8s.node.filesystem.usage"` - K8sNodeMemoryAvailable MetricConfig `mapstructure:"k8s.node.memory.available"` - K8sNodeMemoryMajorPageFaults MetricConfig `mapstructure:"k8s.node.memory.major_page_faults"` - K8sNodeMemoryPageFaults MetricConfig `mapstructure:"k8s.node.memory.page_faults"` - K8sNodeMemoryRss MetricConfig `mapstructure:"k8s.node.memory.rss"` - K8sNodeMemoryUsage MetricConfig `mapstructure:"k8s.node.memory.usage"` - K8sNodeMemoryWorkingSet MetricConfig `mapstructure:"k8s.node.memory.working_set"` - K8sNodeNetworkErrors MetricConfig `mapstructure:"k8s.node.network.errors"` - K8sNodeNetworkIo MetricConfig `mapstructure:"k8s.node.network.io"` - K8sNodeUptime MetricConfig `mapstructure:"k8s.node.uptime"` - K8sPodCPUTime MetricConfig `mapstructure:"k8s.pod.cpu.time"` - K8sPodCPUUtilization MetricConfig `mapstructure:"k8s.pod.cpu.utilization"` - K8sPodFilesystemAvailable MetricConfig `mapstructure:"k8s.pod.filesystem.available"` - K8sPodFilesystemCapacity MetricConfig `mapstructure:"k8s.pod.filesystem.capacity"` - K8sPodFilesystemUsage MetricConfig `mapstructure:"k8s.pod.filesystem.usage"` - K8sPodMemoryAvailable MetricConfig `mapstructure:"k8s.pod.memory.available"` - K8sPodMemoryMajorPageFaults MetricConfig `mapstructure:"k8s.pod.memory.major_page_faults"` - K8sPodMemoryPageFaults MetricConfig `mapstructure:"k8s.pod.memory.page_faults"` - K8sPodMemoryRss MetricConfig `mapstructure:"k8s.pod.memory.rss"` - K8sPodMemoryUsage MetricConfig `mapstructure:"k8s.pod.memory.usage"` - K8sPodMemoryWorkingSet MetricConfig `mapstructure:"k8s.pod.memory.working_set"` - K8sPodNetworkErrors MetricConfig `mapstructure:"k8s.pod.network.errors"` - K8sPodNetworkIo MetricConfig `mapstructure:"k8s.pod.network.io"` - K8sPodUptime MetricConfig `mapstructure:"k8s.pod.uptime"` - K8sVolumeAvailable MetricConfig `mapstructure:"k8s.volume.available"` - K8sVolumeCapacity MetricConfig `mapstructure:"k8s.volume.capacity"` - K8sVolumeInodes MetricConfig `mapstructure:"k8s.volume.inodes"` - K8sVolumeInodesFree MetricConfig `mapstructure:"k8s.volume.inodes.free"` - K8sVolumeInodesUsed MetricConfig `mapstructure:"k8s.volume.inodes.used"` + ContainerCPUTime MetricConfig `mapstructure:"container.cpu.time"` + ContainerCPUUtilization MetricConfig `mapstructure:"container.cpu.utilization"` + ContainerFilesystemAvailable MetricConfig `mapstructure:"container.filesystem.available"` + ContainerFilesystemCapacity MetricConfig `mapstructure:"container.filesystem.capacity"` + ContainerFilesystemUsage MetricConfig `mapstructure:"container.filesystem.usage"` + ContainerMemoryAvailable MetricConfig `mapstructure:"container.memory.available"` + ContainerMemoryMajorPageFaults MetricConfig `mapstructure:"container.memory.major_page_faults"` + ContainerMemoryPageFaults MetricConfig `mapstructure:"container.memory.page_faults"` + ContainerMemoryRss MetricConfig `mapstructure:"container.memory.rss"` + ContainerMemoryUsage MetricConfig `mapstructure:"container.memory.usage"` + ContainerMemoryWorkingSet MetricConfig `mapstructure:"container.memory.working_set"` + ContainerUptime MetricConfig `mapstructure:"container.uptime"` + K8sContainerMemoryLimitUtilization MetricConfig `mapstructure:"k8s.container.memory_limit_utilization"` + K8sContainerMemoryRequestUtilization MetricConfig `mapstructure:"k8s.container.memory_request_utilization"` + K8sNodeCPUTime MetricConfig `mapstructure:"k8s.node.cpu.time"` + K8sNodeCPUUtilization MetricConfig `mapstructure:"k8s.node.cpu.utilization"` + K8sNodeFilesystemAvailable MetricConfig `mapstructure:"k8s.node.filesystem.available"` + K8sNodeFilesystemCapacity MetricConfig `mapstructure:"k8s.node.filesystem.capacity"` + K8sNodeFilesystemUsage MetricConfig `mapstructure:"k8s.node.filesystem.usage"` + K8sNodeMemoryAvailable MetricConfig `mapstructure:"k8s.node.memory.available"` + K8sNodeMemoryMajorPageFaults MetricConfig `mapstructure:"k8s.node.memory.major_page_faults"` + K8sNodeMemoryPageFaults MetricConfig `mapstructure:"k8s.node.memory.page_faults"` + K8sNodeMemoryRss MetricConfig `mapstructure:"k8s.node.memory.rss"` + K8sNodeMemoryUsage MetricConfig `mapstructure:"k8s.node.memory.usage"` + K8sNodeMemoryWorkingSet MetricConfig `mapstructure:"k8s.node.memory.working_set"` + K8sNodeNetworkErrors MetricConfig `mapstructure:"k8s.node.network.errors"` + K8sNodeNetworkIo MetricConfig `mapstructure:"k8s.node.network.io"` + K8sNodeUptime MetricConfig `mapstructure:"k8s.node.uptime"` + K8sPodCPUTime MetricConfig `mapstructure:"k8s.pod.cpu.time"` + K8sPodCPUUtilization MetricConfig `mapstructure:"k8s.pod.cpu.utilization"` + K8sPodFilesystemAvailable MetricConfig `mapstructure:"k8s.pod.filesystem.available"` + K8sPodFilesystemCapacity MetricConfig `mapstructure:"k8s.pod.filesystem.capacity"` + K8sPodFilesystemUsage MetricConfig `mapstructure:"k8s.pod.filesystem.usage"` + K8sPodMemoryAvailable MetricConfig `mapstructure:"k8s.pod.memory.available"` + K8sPodMemoryMajorPageFaults MetricConfig `mapstructure:"k8s.pod.memory.major_page_faults"` + K8sPodMemoryPageFaults MetricConfig `mapstructure:"k8s.pod.memory.page_faults"` + K8sPodMemoryRss MetricConfig `mapstructure:"k8s.pod.memory.rss"` + K8sPodMemoryUsage MetricConfig `mapstructure:"k8s.pod.memory.usage"` + K8sPodMemoryWorkingSet MetricConfig `mapstructure:"k8s.pod.memory.working_set"` + K8sPodMemoryLimitUtilization MetricConfig `mapstructure:"k8s.pod.memory_limit_utilization"` + K8sPodMemoryRequestUtilization MetricConfig `mapstructure:"k8s.pod.memory_request_utilization"` + K8sPodNetworkErrors MetricConfig `mapstructure:"k8s.pod.network.errors"` + K8sPodNetworkIo MetricConfig `mapstructure:"k8s.pod.network.io"` + K8sPodUptime MetricConfig `mapstructure:"k8s.pod.uptime"` + K8sVolumeAvailable MetricConfig `mapstructure:"k8s.volume.available"` + K8sVolumeCapacity MetricConfig `mapstructure:"k8s.volume.capacity"` + K8sVolumeInodes MetricConfig `mapstructure:"k8s.volume.inodes"` + K8sVolumeInodesFree MetricConfig `mapstructure:"k8s.volume.inodes.free"` + K8sVolumeInodesUsed MetricConfig `mapstructure:"k8s.volume.inodes.used"` } func DefaultMetricsConfig() MetricsConfig { @@ -110,6 +114,12 @@ func DefaultMetricsConfig() MetricsConfig { ContainerUptime: MetricConfig{ Enabled: false, }, + K8sContainerMemoryLimitUtilization: MetricConfig{ + Enabled: false, + }, + K8sContainerMemoryRequestUtilization: MetricConfig{ + Enabled: false, + }, K8sNodeCPUTime: MetricConfig{ Enabled: true, }, @@ -185,6 +195,12 @@ func DefaultMetricsConfig() MetricsConfig { K8sPodMemoryWorkingSet: MetricConfig{ Enabled: true, }, + K8sPodMemoryLimitUtilization: MetricConfig{ + Enabled: false, + }, + K8sPodMemoryRequestUtilization: MetricConfig{ + Enabled: false, + }, K8sPodNetworkErrors: MetricConfig{ Enabled: true, }, diff --git a/receiver/kubeletstatsreceiver/internal/metadata/generated_config_test.go b/receiver/kubeletstatsreceiver/internal/metadata/generated_config_test.go index c54a8f787935..149c19b8adcf 100644 --- a/receiver/kubeletstatsreceiver/internal/metadata/generated_config_test.go +++ b/receiver/kubeletstatsreceiver/internal/metadata/generated_config_test.go @@ -26,51 +26,55 @@ func TestMetricsBuilderConfig(t *testing.T) { name: "all_set", want: MetricsBuilderConfig{ Metrics: MetricsConfig{ - ContainerCPUTime: MetricConfig{Enabled: true}, - ContainerCPUUtilization: MetricConfig{Enabled: true}, - ContainerFilesystemAvailable: MetricConfig{Enabled: true}, - ContainerFilesystemCapacity: MetricConfig{Enabled: true}, - ContainerFilesystemUsage: MetricConfig{Enabled: true}, - ContainerMemoryAvailable: MetricConfig{Enabled: true}, - ContainerMemoryMajorPageFaults: MetricConfig{Enabled: true}, - ContainerMemoryPageFaults: MetricConfig{Enabled: true}, - ContainerMemoryRss: MetricConfig{Enabled: true}, - ContainerMemoryUsage: MetricConfig{Enabled: true}, - ContainerMemoryWorkingSet: MetricConfig{Enabled: true}, - ContainerUptime: MetricConfig{Enabled: true}, - K8sNodeCPUTime: MetricConfig{Enabled: true}, - K8sNodeCPUUtilization: MetricConfig{Enabled: true}, - K8sNodeFilesystemAvailable: MetricConfig{Enabled: true}, - K8sNodeFilesystemCapacity: MetricConfig{Enabled: true}, - K8sNodeFilesystemUsage: MetricConfig{Enabled: true}, - K8sNodeMemoryAvailable: MetricConfig{Enabled: true}, - K8sNodeMemoryMajorPageFaults: MetricConfig{Enabled: true}, - K8sNodeMemoryPageFaults: MetricConfig{Enabled: true}, - K8sNodeMemoryRss: MetricConfig{Enabled: true}, - K8sNodeMemoryUsage: MetricConfig{Enabled: true}, - K8sNodeMemoryWorkingSet: MetricConfig{Enabled: true}, - K8sNodeNetworkErrors: MetricConfig{Enabled: true}, - K8sNodeNetworkIo: MetricConfig{Enabled: true}, - K8sNodeUptime: MetricConfig{Enabled: true}, - K8sPodCPUTime: MetricConfig{Enabled: true}, - K8sPodCPUUtilization: MetricConfig{Enabled: true}, - K8sPodFilesystemAvailable: MetricConfig{Enabled: true}, - K8sPodFilesystemCapacity: MetricConfig{Enabled: true}, - K8sPodFilesystemUsage: MetricConfig{Enabled: true}, - K8sPodMemoryAvailable: MetricConfig{Enabled: true}, - K8sPodMemoryMajorPageFaults: MetricConfig{Enabled: true}, - K8sPodMemoryPageFaults: MetricConfig{Enabled: true}, - K8sPodMemoryRss: MetricConfig{Enabled: true}, - K8sPodMemoryUsage: MetricConfig{Enabled: true}, - K8sPodMemoryWorkingSet: MetricConfig{Enabled: true}, - K8sPodNetworkErrors: MetricConfig{Enabled: true}, - K8sPodNetworkIo: MetricConfig{Enabled: true}, - K8sPodUptime: MetricConfig{Enabled: true}, - K8sVolumeAvailable: MetricConfig{Enabled: true}, - K8sVolumeCapacity: MetricConfig{Enabled: true}, - K8sVolumeInodes: MetricConfig{Enabled: true}, - K8sVolumeInodesFree: MetricConfig{Enabled: true}, - K8sVolumeInodesUsed: MetricConfig{Enabled: true}, + ContainerCPUTime: MetricConfig{Enabled: true}, + ContainerCPUUtilization: MetricConfig{Enabled: true}, + ContainerFilesystemAvailable: MetricConfig{Enabled: true}, + ContainerFilesystemCapacity: MetricConfig{Enabled: true}, + ContainerFilesystemUsage: MetricConfig{Enabled: true}, + ContainerMemoryAvailable: MetricConfig{Enabled: true}, + ContainerMemoryMajorPageFaults: MetricConfig{Enabled: true}, + ContainerMemoryPageFaults: MetricConfig{Enabled: true}, + ContainerMemoryRss: MetricConfig{Enabled: true}, + ContainerMemoryUsage: MetricConfig{Enabled: true}, + ContainerMemoryWorkingSet: MetricConfig{Enabled: true}, + ContainerUptime: MetricConfig{Enabled: true}, + K8sContainerMemoryLimitUtilization: MetricConfig{Enabled: true}, + K8sContainerMemoryRequestUtilization: MetricConfig{Enabled: true}, + K8sNodeCPUTime: MetricConfig{Enabled: true}, + K8sNodeCPUUtilization: MetricConfig{Enabled: true}, + K8sNodeFilesystemAvailable: MetricConfig{Enabled: true}, + K8sNodeFilesystemCapacity: MetricConfig{Enabled: true}, + K8sNodeFilesystemUsage: MetricConfig{Enabled: true}, + K8sNodeMemoryAvailable: MetricConfig{Enabled: true}, + K8sNodeMemoryMajorPageFaults: MetricConfig{Enabled: true}, + K8sNodeMemoryPageFaults: MetricConfig{Enabled: true}, + K8sNodeMemoryRss: MetricConfig{Enabled: true}, + K8sNodeMemoryUsage: MetricConfig{Enabled: true}, + K8sNodeMemoryWorkingSet: MetricConfig{Enabled: true}, + K8sNodeNetworkErrors: MetricConfig{Enabled: true}, + K8sNodeNetworkIo: MetricConfig{Enabled: true}, + K8sNodeUptime: MetricConfig{Enabled: true}, + K8sPodCPUTime: MetricConfig{Enabled: true}, + K8sPodCPUUtilization: MetricConfig{Enabled: true}, + K8sPodFilesystemAvailable: MetricConfig{Enabled: true}, + K8sPodFilesystemCapacity: MetricConfig{Enabled: true}, + K8sPodFilesystemUsage: MetricConfig{Enabled: true}, + K8sPodMemoryAvailable: MetricConfig{Enabled: true}, + K8sPodMemoryMajorPageFaults: MetricConfig{Enabled: true}, + K8sPodMemoryPageFaults: MetricConfig{Enabled: true}, + K8sPodMemoryRss: MetricConfig{Enabled: true}, + K8sPodMemoryUsage: MetricConfig{Enabled: true}, + K8sPodMemoryWorkingSet: MetricConfig{Enabled: true}, + K8sPodMemoryLimitUtilization: MetricConfig{Enabled: true}, + K8sPodMemoryRequestUtilization: MetricConfig{Enabled: true}, + K8sPodNetworkErrors: MetricConfig{Enabled: true}, + K8sPodNetworkIo: MetricConfig{Enabled: true}, + K8sPodUptime: MetricConfig{Enabled: true}, + K8sVolumeAvailable: MetricConfig{Enabled: true}, + K8sVolumeCapacity: MetricConfig{Enabled: true}, + K8sVolumeInodes: MetricConfig{Enabled: true}, + K8sVolumeInodesFree: MetricConfig{Enabled: true}, + K8sVolumeInodesUsed: MetricConfig{Enabled: true}, }, ResourceAttributes: ResourceAttributesConfig{ AwsVolumeID: ResourceAttributeConfig{Enabled: true}, @@ -95,51 +99,55 @@ func TestMetricsBuilderConfig(t *testing.T) { name: "none_set", want: MetricsBuilderConfig{ Metrics: MetricsConfig{ - ContainerCPUTime: MetricConfig{Enabled: false}, - ContainerCPUUtilization: MetricConfig{Enabled: false}, - ContainerFilesystemAvailable: MetricConfig{Enabled: false}, - ContainerFilesystemCapacity: MetricConfig{Enabled: false}, - ContainerFilesystemUsage: MetricConfig{Enabled: false}, - ContainerMemoryAvailable: MetricConfig{Enabled: false}, - ContainerMemoryMajorPageFaults: MetricConfig{Enabled: false}, - ContainerMemoryPageFaults: MetricConfig{Enabled: false}, - ContainerMemoryRss: MetricConfig{Enabled: false}, - ContainerMemoryUsage: MetricConfig{Enabled: false}, - ContainerMemoryWorkingSet: MetricConfig{Enabled: false}, - ContainerUptime: MetricConfig{Enabled: false}, - K8sNodeCPUTime: MetricConfig{Enabled: false}, - K8sNodeCPUUtilization: MetricConfig{Enabled: false}, - K8sNodeFilesystemAvailable: MetricConfig{Enabled: false}, - K8sNodeFilesystemCapacity: MetricConfig{Enabled: false}, - K8sNodeFilesystemUsage: MetricConfig{Enabled: false}, - K8sNodeMemoryAvailable: MetricConfig{Enabled: false}, - K8sNodeMemoryMajorPageFaults: MetricConfig{Enabled: false}, - K8sNodeMemoryPageFaults: MetricConfig{Enabled: false}, - K8sNodeMemoryRss: MetricConfig{Enabled: false}, - K8sNodeMemoryUsage: MetricConfig{Enabled: false}, - K8sNodeMemoryWorkingSet: MetricConfig{Enabled: false}, - K8sNodeNetworkErrors: MetricConfig{Enabled: false}, - K8sNodeNetworkIo: MetricConfig{Enabled: false}, - K8sNodeUptime: MetricConfig{Enabled: false}, - K8sPodCPUTime: MetricConfig{Enabled: false}, - K8sPodCPUUtilization: MetricConfig{Enabled: false}, - K8sPodFilesystemAvailable: MetricConfig{Enabled: false}, - K8sPodFilesystemCapacity: MetricConfig{Enabled: false}, - K8sPodFilesystemUsage: MetricConfig{Enabled: false}, - K8sPodMemoryAvailable: MetricConfig{Enabled: false}, - K8sPodMemoryMajorPageFaults: MetricConfig{Enabled: false}, - K8sPodMemoryPageFaults: MetricConfig{Enabled: false}, - K8sPodMemoryRss: MetricConfig{Enabled: false}, - K8sPodMemoryUsage: MetricConfig{Enabled: false}, - K8sPodMemoryWorkingSet: MetricConfig{Enabled: false}, - K8sPodNetworkErrors: MetricConfig{Enabled: false}, - K8sPodNetworkIo: MetricConfig{Enabled: false}, - K8sPodUptime: MetricConfig{Enabled: false}, - K8sVolumeAvailable: MetricConfig{Enabled: false}, - K8sVolumeCapacity: MetricConfig{Enabled: false}, - K8sVolumeInodes: MetricConfig{Enabled: false}, - K8sVolumeInodesFree: MetricConfig{Enabled: false}, - K8sVolumeInodesUsed: MetricConfig{Enabled: false}, + ContainerCPUTime: MetricConfig{Enabled: false}, + ContainerCPUUtilization: MetricConfig{Enabled: false}, + ContainerFilesystemAvailable: MetricConfig{Enabled: false}, + ContainerFilesystemCapacity: MetricConfig{Enabled: false}, + ContainerFilesystemUsage: MetricConfig{Enabled: false}, + ContainerMemoryAvailable: MetricConfig{Enabled: false}, + ContainerMemoryMajorPageFaults: MetricConfig{Enabled: false}, + ContainerMemoryPageFaults: MetricConfig{Enabled: false}, + ContainerMemoryRss: MetricConfig{Enabled: false}, + ContainerMemoryUsage: MetricConfig{Enabled: false}, + ContainerMemoryWorkingSet: MetricConfig{Enabled: false}, + ContainerUptime: MetricConfig{Enabled: false}, + K8sContainerMemoryLimitUtilization: MetricConfig{Enabled: false}, + K8sContainerMemoryRequestUtilization: MetricConfig{Enabled: false}, + K8sNodeCPUTime: MetricConfig{Enabled: false}, + K8sNodeCPUUtilization: MetricConfig{Enabled: false}, + K8sNodeFilesystemAvailable: MetricConfig{Enabled: false}, + K8sNodeFilesystemCapacity: MetricConfig{Enabled: false}, + K8sNodeFilesystemUsage: MetricConfig{Enabled: false}, + K8sNodeMemoryAvailable: MetricConfig{Enabled: false}, + K8sNodeMemoryMajorPageFaults: MetricConfig{Enabled: false}, + K8sNodeMemoryPageFaults: MetricConfig{Enabled: false}, + K8sNodeMemoryRss: MetricConfig{Enabled: false}, + K8sNodeMemoryUsage: MetricConfig{Enabled: false}, + K8sNodeMemoryWorkingSet: MetricConfig{Enabled: false}, + K8sNodeNetworkErrors: MetricConfig{Enabled: false}, + K8sNodeNetworkIo: MetricConfig{Enabled: false}, + K8sNodeUptime: MetricConfig{Enabled: false}, + K8sPodCPUTime: MetricConfig{Enabled: false}, + K8sPodCPUUtilization: MetricConfig{Enabled: false}, + K8sPodFilesystemAvailable: MetricConfig{Enabled: false}, + K8sPodFilesystemCapacity: MetricConfig{Enabled: false}, + K8sPodFilesystemUsage: MetricConfig{Enabled: false}, + K8sPodMemoryAvailable: MetricConfig{Enabled: false}, + K8sPodMemoryMajorPageFaults: MetricConfig{Enabled: false}, + K8sPodMemoryPageFaults: MetricConfig{Enabled: false}, + K8sPodMemoryRss: MetricConfig{Enabled: false}, + K8sPodMemoryUsage: MetricConfig{Enabled: false}, + K8sPodMemoryWorkingSet: MetricConfig{Enabled: false}, + K8sPodMemoryLimitUtilization: MetricConfig{Enabled: false}, + K8sPodMemoryRequestUtilization: MetricConfig{Enabled: false}, + K8sPodNetworkErrors: MetricConfig{Enabled: false}, + K8sPodNetworkIo: MetricConfig{Enabled: false}, + K8sPodUptime: MetricConfig{Enabled: false}, + K8sVolumeAvailable: MetricConfig{Enabled: false}, + K8sVolumeCapacity: MetricConfig{Enabled: false}, + K8sVolumeInodes: MetricConfig{Enabled: false}, + K8sVolumeInodesFree: MetricConfig{Enabled: false}, + K8sVolumeInodesUsed: MetricConfig{Enabled: false}, }, ResourceAttributes: ResourceAttributesConfig{ AwsVolumeID: ResourceAttributeConfig{Enabled: false}, diff --git a/receiver/kubeletstatsreceiver/internal/metadata/generated_metrics.go b/receiver/kubeletstatsreceiver/internal/metadata/generated_metrics.go index 1c5511b47c62..aa72c769e7d3 100644 --- a/receiver/kubeletstatsreceiver/internal/metadata/generated_metrics.go +++ b/receiver/kubeletstatsreceiver/internal/metadata/generated_metrics.go @@ -629,6 +629,104 @@ func newMetricContainerUptime(cfg MetricConfig) metricContainerUptime { return m } +type metricK8sContainerMemoryLimitUtilization struct { + data pmetric.Metric // data buffer for generated metric. + config MetricConfig // metric config provided by user. + capacity int // max observed number of data points added to the metric. +} + +// init fills k8s.container.memory_limit_utilization metric with initial data. +func (m *metricK8sContainerMemoryLimitUtilization) init() { + m.data.SetName("k8s.container.memory_limit_utilization") + m.data.SetDescription("Container memory utilization as a ratio of the container's limits") + m.data.SetUnit("1") + m.data.SetEmptyGauge() +} + +func (m *metricK8sContainerMemoryLimitUtilization) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val float64) { + if !m.config.Enabled { + return + } + dp := m.data.Gauge().DataPoints().AppendEmpty() + dp.SetStartTimestamp(start) + dp.SetTimestamp(ts) + dp.SetDoubleValue(val) +} + +// updateCapacity saves max length of data point slices that will be used for the slice capacity. +func (m *metricK8sContainerMemoryLimitUtilization) updateCapacity() { + if m.data.Gauge().DataPoints().Len() > m.capacity { + m.capacity = m.data.Gauge().DataPoints().Len() + } +} + +// emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. +func (m *metricK8sContainerMemoryLimitUtilization) emit(metrics pmetric.MetricSlice) { + if m.config.Enabled && m.data.Gauge().DataPoints().Len() > 0 { + m.updateCapacity() + m.data.MoveTo(metrics.AppendEmpty()) + m.init() + } +} + +func newMetricK8sContainerMemoryLimitUtilization(cfg MetricConfig) metricK8sContainerMemoryLimitUtilization { + m := metricK8sContainerMemoryLimitUtilization{config: cfg} + if cfg.Enabled { + m.data = pmetric.NewMetric() + m.init() + } + return m +} + +type metricK8sContainerMemoryRequestUtilization struct { + data pmetric.Metric // data buffer for generated metric. + config MetricConfig // metric config provided by user. + capacity int // max observed number of data points added to the metric. +} + +// init fills k8s.container.memory_request_utilization metric with initial data. +func (m *metricK8sContainerMemoryRequestUtilization) init() { + m.data.SetName("k8s.container.memory_request_utilization") + m.data.SetDescription("Container memory utilization as a ratio of the container's requests") + m.data.SetUnit("1") + m.data.SetEmptyGauge() +} + +func (m *metricK8sContainerMemoryRequestUtilization) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val float64) { + if !m.config.Enabled { + return + } + dp := m.data.Gauge().DataPoints().AppendEmpty() + dp.SetStartTimestamp(start) + dp.SetTimestamp(ts) + dp.SetDoubleValue(val) +} + +// updateCapacity saves max length of data point slices that will be used for the slice capacity. +func (m *metricK8sContainerMemoryRequestUtilization) updateCapacity() { + if m.data.Gauge().DataPoints().Len() > m.capacity { + m.capacity = m.data.Gauge().DataPoints().Len() + } +} + +// emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. +func (m *metricK8sContainerMemoryRequestUtilization) emit(metrics pmetric.MetricSlice) { + if m.config.Enabled && m.data.Gauge().DataPoints().Len() > 0 { + m.updateCapacity() + m.data.MoveTo(metrics.AppendEmpty()) + m.init() + } +} + +func newMetricK8sContainerMemoryRequestUtilization(cfg MetricConfig) metricK8sContainerMemoryRequestUtilization { + m := metricK8sContainerMemoryRequestUtilization{config: cfg} + if cfg.Enabled { + m.data = pmetric.NewMetric() + m.init() + } + return m +} + type metricK8sNodeCPUTime struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. @@ -1870,6 +1968,104 @@ func newMetricK8sPodMemoryWorkingSet(cfg MetricConfig) metricK8sPodMemoryWorking return m } +type metricK8sPodMemoryLimitUtilization struct { + data pmetric.Metric // data buffer for generated metric. + config MetricConfig // metric config provided by user. + capacity int // max observed number of data points added to the metric. +} + +// init fills k8s.pod.memory_limit_utilization metric with initial data. +func (m *metricK8sPodMemoryLimitUtilization) init() { + m.data.SetName("k8s.pod.memory_limit_utilization") + m.data.SetDescription("Pod memory utilization as a ratio of the pod's total container limits. If any container is missing a limit the metric is not emitted.") + m.data.SetUnit("1") + m.data.SetEmptyGauge() +} + +func (m *metricK8sPodMemoryLimitUtilization) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val float64) { + if !m.config.Enabled { + return + } + dp := m.data.Gauge().DataPoints().AppendEmpty() + dp.SetStartTimestamp(start) + dp.SetTimestamp(ts) + dp.SetDoubleValue(val) +} + +// updateCapacity saves max length of data point slices that will be used for the slice capacity. +func (m *metricK8sPodMemoryLimitUtilization) updateCapacity() { + if m.data.Gauge().DataPoints().Len() > m.capacity { + m.capacity = m.data.Gauge().DataPoints().Len() + } +} + +// emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. +func (m *metricK8sPodMemoryLimitUtilization) emit(metrics pmetric.MetricSlice) { + if m.config.Enabled && m.data.Gauge().DataPoints().Len() > 0 { + m.updateCapacity() + m.data.MoveTo(metrics.AppendEmpty()) + m.init() + } +} + +func newMetricK8sPodMemoryLimitUtilization(cfg MetricConfig) metricK8sPodMemoryLimitUtilization { + m := metricK8sPodMemoryLimitUtilization{config: cfg} + if cfg.Enabled { + m.data = pmetric.NewMetric() + m.init() + } + return m +} + +type metricK8sPodMemoryRequestUtilization struct { + data pmetric.Metric // data buffer for generated metric. + config MetricConfig // metric config provided by user. + capacity int // max observed number of data points added to the metric. +} + +// init fills k8s.pod.memory_request_utilization metric with initial data. +func (m *metricK8sPodMemoryRequestUtilization) init() { + m.data.SetName("k8s.pod.memory_request_utilization") + m.data.SetDescription("Pod memory utilization as a ratio of the pod's total container requests. If any container is missing a request the metric is not emitted.") + m.data.SetUnit("1") + m.data.SetEmptyGauge() +} + +func (m *metricK8sPodMemoryRequestUtilization) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val float64) { + if !m.config.Enabled { + return + } + dp := m.data.Gauge().DataPoints().AppendEmpty() + dp.SetStartTimestamp(start) + dp.SetTimestamp(ts) + dp.SetDoubleValue(val) +} + +// updateCapacity saves max length of data point slices that will be used for the slice capacity. +func (m *metricK8sPodMemoryRequestUtilization) updateCapacity() { + if m.data.Gauge().DataPoints().Len() > m.capacity { + m.capacity = m.data.Gauge().DataPoints().Len() + } +} + +// emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. +func (m *metricK8sPodMemoryRequestUtilization) emit(metrics pmetric.MetricSlice) { + if m.config.Enabled && m.data.Gauge().DataPoints().Len() > 0 { + m.updateCapacity() + m.data.MoveTo(metrics.AppendEmpty()) + m.init() + } +} + +func newMetricK8sPodMemoryRequestUtilization(cfg MetricConfig) metricK8sPodMemoryRequestUtilization { + m := metricK8sPodMemoryRequestUtilization{config: cfg} + if cfg.Enabled { + m.data = pmetric.NewMetric() + m.init() + } + return m +} + type metricK8sPodNetworkErrors struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. @@ -2277,56 +2473,60 @@ func newMetricK8sVolumeInodesUsed(cfg MetricConfig) metricK8sVolumeInodesUsed { // MetricsBuilder provides an interface for scrapers to report metrics while taking care of all the transformations // required to produce metric representation defined in metadata and user config. type MetricsBuilder struct { - config MetricsBuilderConfig // config of the metrics builder. - startTime pcommon.Timestamp // start time that will be applied to all recorded data points. - metricsCapacity int // maximum observed number of metrics per resource. - metricsBuffer pmetric.Metrics // accumulates metrics data before emitting. - buildInfo component.BuildInfo // contains version information. - metricContainerCPUTime metricContainerCPUTime - metricContainerCPUUtilization metricContainerCPUUtilization - metricContainerFilesystemAvailable metricContainerFilesystemAvailable - metricContainerFilesystemCapacity metricContainerFilesystemCapacity - metricContainerFilesystemUsage metricContainerFilesystemUsage - metricContainerMemoryAvailable metricContainerMemoryAvailable - metricContainerMemoryMajorPageFaults metricContainerMemoryMajorPageFaults - metricContainerMemoryPageFaults metricContainerMemoryPageFaults - metricContainerMemoryRss metricContainerMemoryRss - metricContainerMemoryUsage metricContainerMemoryUsage - metricContainerMemoryWorkingSet metricContainerMemoryWorkingSet - metricContainerUptime metricContainerUptime - metricK8sNodeCPUTime metricK8sNodeCPUTime - metricK8sNodeCPUUtilization metricK8sNodeCPUUtilization - metricK8sNodeFilesystemAvailable metricK8sNodeFilesystemAvailable - metricK8sNodeFilesystemCapacity metricK8sNodeFilesystemCapacity - metricK8sNodeFilesystemUsage metricK8sNodeFilesystemUsage - metricK8sNodeMemoryAvailable metricK8sNodeMemoryAvailable - metricK8sNodeMemoryMajorPageFaults metricK8sNodeMemoryMajorPageFaults - metricK8sNodeMemoryPageFaults metricK8sNodeMemoryPageFaults - metricK8sNodeMemoryRss metricK8sNodeMemoryRss - metricK8sNodeMemoryUsage metricK8sNodeMemoryUsage - metricK8sNodeMemoryWorkingSet metricK8sNodeMemoryWorkingSet - metricK8sNodeNetworkErrors metricK8sNodeNetworkErrors - metricK8sNodeNetworkIo metricK8sNodeNetworkIo - metricK8sNodeUptime metricK8sNodeUptime - metricK8sPodCPUTime metricK8sPodCPUTime - metricK8sPodCPUUtilization metricK8sPodCPUUtilization - metricK8sPodFilesystemAvailable metricK8sPodFilesystemAvailable - metricK8sPodFilesystemCapacity metricK8sPodFilesystemCapacity - metricK8sPodFilesystemUsage metricK8sPodFilesystemUsage - metricK8sPodMemoryAvailable metricK8sPodMemoryAvailable - metricK8sPodMemoryMajorPageFaults metricK8sPodMemoryMajorPageFaults - metricK8sPodMemoryPageFaults metricK8sPodMemoryPageFaults - metricK8sPodMemoryRss metricK8sPodMemoryRss - metricK8sPodMemoryUsage metricK8sPodMemoryUsage - metricK8sPodMemoryWorkingSet metricK8sPodMemoryWorkingSet - metricK8sPodNetworkErrors metricK8sPodNetworkErrors - metricK8sPodNetworkIo metricK8sPodNetworkIo - metricK8sPodUptime metricK8sPodUptime - metricK8sVolumeAvailable metricK8sVolumeAvailable - metricK8sVolumeCapacity metricK8sVolumeCapacity - metricK8sVolumeInodes metricK8sVolumeInodes - metricK8sVolumeInodesFree metricK8sVolumeInodesFree - metricK8sVolumeInodesUsed metricK8sVolumeInodesUsed + config MetricsBuilderConfig // config of the metrics builder. + startTime pcommon.Timestamp // start time that will be applied to all recorded data points. + metricsCapacity int // maximum observed number of metrics per resource. + metricsBuffer pmetric.Metrics // accumulates metrics data before emitting. + buildInfo component.BuildInfo // contains version information. + metricContainerCPUTime metricContainerCPUTime + metricContainerCPUUtilization metricContainerCPUUtilization + metricContainerFilesystemAvailable metricContainerFilesystemAvailable + metricContainerFilesystemCapacity metricContainerFilesystemCapacity + metricContainerFilesystemUsage metricContainerFilesystemUsage + metricContainerMemoryAvailable metricContainerMemoryAvailable + metricContainerMemoryMajorPageFaults metricContainerMemoryMajorPageFaults + metricContainerMemoryPageFaults metricContainerMemoryPageFaults + metricContainerMemoryRss metricContainerMemoryRss + metricContainerMemoryUsage metricContainerMemoryUsage + metricContainerMemoryWorkingSet metricContainerMemoryWorkingSet + metricContainerUptime metricContainerUptime + metricK8sContainerMemoryLimitUtilization metricK8sContainerMemoryLimitUtilization + metricK8sContainerMemoryRequestUtilization metricK8sContainerMemoryRequestUtilization + metricK8sNodeCPUTime metricK8sNodeCPUTime + metricK8sNodeCPUUtilization metricK8sNodeCPUUtilization + metricK8sNodeFilesystemAvailable metricK8sNodeFilesystemAvailable + metricK8sNodeFilesystemCapacity metricK8sNodeFilesystemCapacity + metricK8sNodeFilesystemUsage metricK8sNodeFilesystemUsage + metricK8sNodeMemoryAvailable metricK8sNodeMemoryAvailable + metricK8sNodeMemoryMajorPageFaults metricK8sNodeMemoryMajorPageFaults + metricK8sNodeMemoryPageFaults metricK8sNodeMemoryPageFaults + metricK8sNodeMemoryRss metricK8sNodeMemoryRss + metricK8sNodeMemoryUsage metricK8sNodeMemoryUsage + metricK8sNodeMemoryWorkingSet metricK8sNodeMemoryWorkingSet + metricK8sNodeNetworkErrors metricK8sNodeNetworkErrors + metricK8sNodeNetworkIo metricK8sNodeNetworkIo + metricK8sNodeUptime metricK8sNodeUptime + metricK8sPodCPUTime metricK8sPodCPUTime + metricK8sPodCPUUtilization metricK8sPodCPUUtilization + metricK8sPodFilesystemAvailable metricK8sPodFilesystemAvailable + metricK8sPodFilesystemCapacity metricK8sPodFilesystemCapacity + metricK8sPodFilesystemUsage metricK8sPodFilesystemUsage + metricK8sPodMemoryAvailable metricK8sPodMemoryAvailable + metricK8sPodMemoryMajorPageFaults metricK8sPodMemoryMajorPageFaults + metricK8sPodMemoryPageFaults metricK8sPodMemoryPageFaults + metricK8sPodMemoryRss metricK8sPodMemoryRss + metricK8sPodMemoryUsage metricK8sPodMemoryUsage + metricK8sPodMemoryWorkingSet metricK8sPodMemoryWorkingSet + metricK8sPodMemoryLimitUtilization metricK8sPodMemoryLimitUtilization + metricK8sPodMemoryRequestUtilization metricK8sPodMemoryRequestUtilization + metricK8sPodNetworkErrors metricK8sPodNetworkErrors + metricK8sPodNetworkIo metricK8sPodNetworkIo + metricK8sPodUptime metricK8sPodUptime + metricK8sVolumeAvailable metricK8sVolumeAvailable + metricK8sVolumeCapacity metricK8sVolumeCapacity + metricK8sVolumeInodes metricK8sVolumeInodes + metricK8sVolumeInodesFree metricK8sVolumeInodesFree + metricK8sVolumeInodesUsed metricK8sVolumeInodesUsed } // metricBuilderOption applies changes to default metrics builder. @@ -2341,55 +2541,59 @@ func WithStartTime(startTime pcommon.Timestamp) metricBuilderOption { func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.CreateSettings, options ...metricBuilderOption) *MetricsBuilder { mb := &MetricsBuilder{ - config: mbc, - startTime: pcommon.NewTimestampFromTime(time.Now()), - metricsBuffer: pmetric.NewMetrics(), - buildInfo: settings.BuildInfo, - metricContainerCPUTime: newMetricContainerCPUTime(mbc.Metrics.ContainerCPUTime), - metricContainerCPUUtilization: newMetricContainerCPUUtilization(mbc.Metrics.ContainerCPUUtilization), - metricContainerFilesystemAvailable: newMetricContainerFilesystemAvailable(mbc.Metrics.ContainerFilesystemAvailable), - metricContainerFilesystemCapacity: newMetricContainerFilesystemCapacity(mbc.Metrics.ContainerFilesystemCapacity), - metricContainerFilesystemUsage: newMetricContainerFilesystemUsage(mbc.Metrics.ContainerFilesystemUsage), - metricContainerMemoryAvailable: newMetricContainerMemoryAvailable(mbc.Metrics.ContainerMemoryAvailable), - metricContainerMemoryMajorPageFaults: newMetricContainerMemoryMajorPageFaults(mbc.Metrics.ContainerMemoryMajorPageFaults), - metricContainerMemoryPageFaults: newMetricContainerMemoryPageFaults(mbc.Metrics.ContainerMemoryPageFaults), - metricContainerMemoryRss: newMetricContainerMemoryRss(mbc.Metrics.ContainerMemoryRss), - metricContainerMemoryUsage: newMetricContainerMemoryUsage(mbc.Metrics.ContainerMemoryUsage), - metricContainerMemoryWorkingSet: newMetricContainerMemoryWorkingSet(mbc.Metrics.ContainerMemoryWorkingSet), - metricContainerUptime: newMetricContainerUptime(mbc.Metrics.ContainerUptime), - metricK8sNodeCPUTime: newMetricK8sNodeCPUTime(mbc.Metrics.K8sNodeCPUTime), - metricK8sNodeCPUUtilization: newMetricK8sNodeCPUUtilization(mbc.Metrics.K8sNodeCPUUtilization), - metricK8sNodeFilesystemAvailable: newMetricK8sNodeFilesystemAvailable(mbc.Metrics.K8sNodeFilesystemAvailable), - metricK8sNodeFilesystemCapacity: newMetricK8sNodeFilesystemCapacity(mbc.Metrics.K8sNodeFilesystemCapacity), - metricK8sNodeFilesystemUsage: newMetricK8sNodeFilesystemUsage(mbc.Metrics.K8sNodeFilesystemUsage), - metricK8sNodeMemoryAvailable: newMetricK8sNodeMemoryAvailable(mbc.Metrics.K8sNodeMemoryAvailable), - metricK8sNodeMemoryMajorPageFaults: newMetricK8sNodeMemoryMajorPageFaults(mbc.Metrics.K8sNodeMemoryMajorPageFaults), - metricK8sNodeMemoryPageFaults: newMetricK8sNodeMemoryPageFaults(mbc.Metrics.K8sNodeMemoryPageFaults), - metricK8sNodeMemoryRss: newMetricK8sNodeMemoryRss(mbc.Metrics.K8sNodeMemoryRss), - metricK8sNodeMemoryUsage: newMetricK8sNodeMemoryUsage(mbc.Metrics.K8sNodeMemoryUsage), - metricK8sNodeMemoryWorkingSet: newMetricK8sNodeMemoryWorkingSet(mbc.Metrics.K8sNodeMemoryWorkingSet), - metricK8sNodeNetworkErrors: newMetricK8sNodeNetworkErrors(mbc.Metrics.K8sNodeNetworkErrors), - metricK8sNodeNetworkIo: newMetricK8sNodeNetworkIo(mbc.Metrics.K8sNodeNetworkIo), - metricK8sNodeUptime: newMetricK8sNodeUptime(mbc.Metrics.K8sNodeUptime), - metricK8sPodCPUTime: newMetricK8sPodCPUTime(mbc.Metrics.K8sPodCPUTime), - metricK8sPodCPUUtilization: newMetricK8sPodCPUUtilization(mbc.Metrics.K8sPodCPUUtilization), - metricK8sPodFilesystemAvailable: newMetricK8sPodFilesystemAvailable(mbc.Metrics.K8sPodFilesystemAvailable), - metricK8sPodFilesystemCapacity: newMetricK8sPodFilesystemCapacity(mbc.Metrics.K8sPodFilesystemCapacity), - metricK8sPodFilesystemUsage: newMetricK8sPodFilesystemUsage(mbc.Metrics.K8sPodFilesystemUsage), - metricK8sPodMemoryAvailable: newMetricK8sPodMemoryAvailable(mbc.Metrics.K8sPodMemoryAvailable), - metricK8sPodMemoryMajorPageFaults: newMetricK8sPodMemoryMajorPageFaults(mbc.Metrics.K8sPodMemoryMajorPageFaults), - metricK8sPodMemoryPageFaults: newMetricK8sPodMemoryPageFaults(mbc.Metrics.K8sPodMemoryPageFaults), - metricK8sPodMemoryRss: newMetricK8sPodMemoryRss(mbc.Metrics.K8sPodMemoryRss), - metricK8sPodMemoryUsage: newMetricK8sPodMemoryUsage(mbc.Metrics.K8sPodMemoryUsage), - metricK8sPodMemoryWorkingSet: newMetricK8sPodMemoryWorkingSet(mbc.Metrics.K8sPodMemoryWorkingSet), - metricK8sPodNetworkErrors: newMetricK8sPodNetworkErrors(mbc.Metrics.K8sPodNetworkErrors), - metricK8sPodNetworkIo: newMetricK8sPodNetworkIo(mbc.Metrics.K8sPodNetworkIo), - metricK8sPodUptime: newMetricK8sPodUptime(mbc.Metrics.K8sPodUptime), - metricK8sVolumeAvailable: newMetricK8sVolumeAvailable(mbc.Metrics.K8sVolumeAvailable), - metricK8sVolumeCapacity: newMetricK8sVolumeCapacity(mbc.Metrics.K8sVolumeCapacity), - metricK8sVolumeInodes: newMetricK8sVolumeInodes(mbc.Metrics.K8sVolumeInodes), - metricK8sVolumeInodesFree: newMetricK8sVolumeInodesFree(mbc.Metrics.K8sVolumeInodesFree), - metricK8sVolumeInodesUsed: newMetricK8sVolumeInodesUsed(mbc.Metrics.K8sVolumeInodesUsed), + config: mbc, + startTime: pcommon.NewTimestampFromTime(time.Now()), + metricsBuffer: pmetric.NewMetrics(), + buildInfo: settings.BuildInfo, + metricContainerCPUTime: newMetricContainerCPUTime(mbc.Metrics.ContainerCPUTime), + metricContainerCPUUtilization: newMetricContainerCPUUtilization(mbc.Metrics.ContainerCPUUtilization), + metricContainerFilesystemAvailable: newMetricContainerFilesystemAvailable(mbc.Metrics.ContainerFilesystemAvailable), + metricContainerFilesystemCapacity: newMetricContainerFilesystemCapacity(mbc.Metrics.ContainerFilesystemCapacity), + metricContainerFilesystemUsage: newMetricContainerFilesystemUsage(mbc.Metrics.ContainerFilesystemUsage), + metricContainerMemoryAvailable: newMetricContainerMemoryAvailable(mbc.Metrics.ContainerMemoryAvailable), + metricContainerMemoryMajorPageFaults: newMetricContainerMemoryMajorPageFaults(mbc.Metrics.ContainerMemoryMajorPageFaults), + metricContainerMemoryPageFaults: newMetricContainerMemoryPageFaults(mbc.Metrics.ContainerMemoryPageFaults), + metricContainerMemoryRss: newMetricContainerMemoryRss(mbc.Metrics.ContainerMemoryRss), + metricContainerMemoryUsage: newMetricContainerMemoryUsage(mbc.Metrics.ContainerMemoryUsage), + metricContainerMemoryWorkingSet: newMetricContainerMemoryWorkingSet(mbc.Metrics.ContainerMemoryWorkingSet), + metricContainerUptime: newMetricContainerUptime(mbc.Metrics.ContainerUptime), + metricK8sContainerMemoryLimitUtilization: newMetricK8sContainerMemoryLimitUtilization(mbc.Metrics.K8sContainerMemoryLimitUtilization), + metricK8sContainerMemoryRequestUtilization: newMetricK8sContainerMemoryRequestUtilization(mbc.Metrics.K8sContainerMemoryRequestUtilization), + metricK8sNodeCPUTime: newMetricK8sNodeCPUTime(mbc.Metrics.K8sNodeCPUTime), + metricK8sNodeCPUUtilization: newMetricK8sNodeCPUUtilization(mbc.Metrics.K8sNodeCPUUtilization), + metricK8sNodeFilesystemAvailable: newMetricK8sNodeFilesystemAvailable(mbc.Metrics.K8sNodeFilesystemAvailable), + metricK8sNodeFilesystemCapacity: newMetricK8sNodeFilesystemCapacity(mbc.Metrics.K8sNodeFilesystemCapacity), + metricK8sNodeFilesystemUsage: newMetricK8sNodeFilesystemUsage(mbc.Metrics.K8sNodeFilesystemUsage), + metricK8sNodeMemoryAvailable: newMetricK8sNodeMemoryAvailable(mbc.Metrics.K8sNodeMemoryAvailable), + metricK8sNodeMemoryMajorPageFaults: newMetricK8sNodeMemoryMajorPageFaults(mbc.Metrics.K8sNodeMemoryMajorPageFaults), + metricK8sNodeMemoryPageFaults: newMetricK8sNodeMemoryPageFaults(mbc.Metrics.K8sNodeMemoryPageFaults), + metricK8sNodeMemoryRss: newMetricK8sNodeMemoryRss(mbc.Metrics.K8sNodeMemoryRss), + metricK8sNodeMemoryUsage: newMetricK8sNodeMemoryUsage(mbc.Metrics.K8sNodeMemoryUsage), + metricK8sNodeMemoryWorkingSet: newMetricK8sNodeMemoryWorkingSet(mbc.Metrics.K8sNodeMemoryWorkingSet), + metricK8sNodeNetworkErrors: newMetricK8sNodeNetworkErrors(mbc.Metrics.K8sNodeNetworkErrors), + metricK8sNodeNetworkIo: newMetricK8sNodeNetworkIo(mbc.Metrics.K8sNodeNetworkIo), + metricK8sNodeUptime: newMetricK8sNodeUptime(mbc.Metrics.K8sNodeUptime), + metricK8sPodCPUTime: newMetricK8sPodCPUTime(mbc.Metrics.K8sPodCPUTime), + metricK8sPodCPUUtilization: newMetricK8sPodCPUUtilization(mbc.Metrics.K8sPodCPUUtilization), + metricK8sPodFilesystemAvailable: newMetricK8sPodFilesystemAvailable(mbc.Metrics.K8sPodFilesystemAvailable), + metricK8sPodFilesystemCapacity: newMetricK8sPodFilesystemCapacity(mbc.Metrics.K8sPodFilesystemCapacity), + metricK8sPodFilesystemUsage: newMetricK8sPodFilesystemUsage(mbc.Metrics.K8sPodFilesystemUsage), + metricK8sPodMemoryAvailable: newMetricK8sPodMemoryAvailable(mbc.Metrics.K8sPodMemoryAvailable), + metricK8sPodMemoryMajorPageFaults: newMetricK8sPodMemoryMajorPageFaults(mbc.Metrics.K8sPodMemoryMajorPageFaults), + metricK8sPodMemoryPageFaults: newMetricK8sPodMemoryPageFaults(mbc.Metrics.K8sPodMemoryPageFaults), + metricK8sPodMemoryRss: newMetricK8sPodMemoryRss(mbc.Metrics.K8sPodMemoryRss), + metricK8sPodMemoryUsage: newMetricK8sPodMemoryUsage(mbc.Metrics.K8sPodMemoryUsage), + metricK8sPodMemoryWorkingSet: newMetricK8sPodMemoryWorkingSet(mbc.Metrics.K8sPodMemoryWorkingSet), + metricK8sPodMemoryLimitUtilization: newMetricK8sPodMemoryLimitUtilization(mbc.Metrics.K8sPodMemoryLimitUtilization), + metricK8sPodMemoryRequestUtilization: newMetricK8sPodMemoryRequestUtilization(mbc.Metrics.K8sPodMemoryRequestUtilization), + metricK8sPodNetworkErrors: newMetricK8sPodNetworkErrors(mbc.Metrics.K8sPodNetworkErrors), + metricK8sPodNetworkIo: newMetricK8sPodNetworkIo(mbc.Metrics.K8sPodNetworkIo), + metricK8sPodUptime: newMetricK8sPodUptime(mbc.Metrics.K8sPodUptime), + metricK8sVolumeAvailable: newMetricK8sVolumeAvailable(mbc.Metrics.K8sVolumeAvailable), + metricK8sVolumeCapacity: newMetricK8sVolumeCapacity(mbc.Metrics.K8sVolumeCapacity), + metricK8sVolumeInodes: newMetricK8sVolumeInodes(mbc.Metrics.K8sVolumeInodes), + metricK8sVolumeInodesFree: newMetricK8sVolumeInodesFree(mbc.Metrics.K8sVolumeInodesFree), + metricK8sVolumeInodesUsed: newMetricK8sVolumeInodesUsed(mbc.Metrics.K8sVolumeInodesUsed), } for _, op := range options { op(mb) @@ -2463,6 +2667,8 @@ func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) { mb.metricContainerMemoryUsage.emit(ils.Metrics()) mb.metricContainerMemoryWorkingSet.emit(ils.Metrics()) mb.metricContainerUptime.emit(ils.Metrics()) + mb.metricK8sContainerMemoryLimitUtilization.emit(ils.Metrics()) + mb.metricK8sContainerMemoryRequestUtilization.emit(ils.Metrics()) mb.metricK8sNodeCPUTime.emit(ils.Metrics()) mb.metricK8sNodeCPUUtilization.emit(ils.Metrics()) mb.metricK8sNodeFilesystemAvailable.emit(ils.Metrics()) @@ -2488,6 +2694,8 @@ func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) { mb.metricK8sPodMemoryRss.emit(ils.Metrics()) mb.metricK8sPodMemoryUsage.emit(ils.Metrics()) mb.metricK8sPodMemoryWorkingSet.emit(ils.Metrics()) + mb.metricK8sPodMemoryLimitUtilization.emit(ils.Metrics()) + mb.metricK8sPodMemoryRequestUtilization.emit(ils.Metrics()) mb.metricK8sPodNetworkErrors.emit(ils.Metrics()) mb.metricK8sPodNetworkIo.emit(ils.Metrics()) mb.metricK8sPodUptime.emit(ils.Metrics()) @@ -2576,6 +2784,16 @@ func (mb *MetricsBuilder) RecordContainerUptimeDataPoint(ts pcommon.Timestamp, v mb.metricContainerUptime.recordDataPoint(mb.startTime, ts, val) } +// RecordK8sContainerMemoryLimitUtilizationDataPoint adds a data point to k8s.container.memory_limit_utilization metric. +func (mb *MetricsBuilder) RecordK8sContainerMemoryLimitUtilizationDataPoint(ts pcommon.Timestamp, val float64) { + mb.metricK8sContainerMemoryLimitUtilization.recordDataPoint(mb.startTime, ts, val) +} + +// RecordK8sContainerMemoryRequestUtilizationDataPoint adds a data point to k8s.container.memory_request_utilization metric. +func (mb *MetricsBuilder) RecordK8sContainerMemoryRequestUtilizationDataPoint(ts pcommon.Timestamp, val float64) { + mb.metricK8sContainerMemoryRequestUtilization.recordDataPoint(mb.startTime, ts, val) +} + // RecordK8sNodeCPUTimeDataPoint adds a data point to k8s.node.cpu.time metric. func (mb *MetricsBuilder) RecordK8sNodeCPUTimeDataPoint(ts pcommon.Timestamp, val float64) { mb.metricK8sNodeCPUTime.recordDataPoint(mb.startTime, ts, val) @@ -2701,6 +2919,16 @@ func (mb *MetricsBuilder) RecordK8sPodMemoryWorkingSetDataPoint(ts pcommon.Times mb.metricK8sPodMemoryWorkingSet.recordDataPoint(mb.startTime, ts, val) } +// RecordK8sPodMemoryLimitUtilizationDataPoint adds a data point to k8s.pod.memory_limit_utilization metric. +func (mb *MetricsBuilder) RecordK8sPodMemoryLimitUtilizationDataPoint(ts pcommon.Timestamp, val float64) { + mb.metricK8sPodMemoryLimitUtilization.recordDataPoint(mb.startTime, ts, val) +} + +// RecordK8sPodMemoryRequestUtilizationDataPoint adds a data point to k8s.pod.memory_request_utilization metric. +func (mb *MetricsBuilder) RecordK8sPodMemoryRequestUtilizationDataPoint(ts pcommon.Timestamp, val float64) { + mb.metricK8sPodMemoryRequestUtilization.recordDataPoint(mb.startTime, ts, val) +} + // RecordK8sPodNetworkErrorsDataPoint adds a data point to k8s.pod.network.errors metric. func (mb *MetricsBuilder) RecordK8sPodNetworkErrorsDataPoint(ts pcommon.Timestamp, val int64, interfaceAttributeValue string, directionAttributeValue AttributeDirection) { mb.metricK8sPodNetworkErrors.recordDataPoint(mb.startTime, ts, val, interfaceAttributeValue, directionAttributeValue.String()) diff --git a/receiver/kubeletstatsreceiver/internal/metadata/generated_metrics_test.go b/receiver/kubeletstatsreceiver/internal/metadata/generated_metrics_test.go index 9dc39efa019b..11cb737ec6d2 100644 --- a/receiver/kubeletstatsreceiver/internal/metadata/generated_metrics_test.go +++ b/receiver/kubeletstatsreceiver/internal/metadata/generated_metrics_test.go @@ -101,6 +101,12 @@ func TestMetricsBuilder(t *testing.T) { allMetricsCount++ mb.RecordContainerUptimeDataPoint(ts, 1) + allMetricsCount++ + mb.RecordK8sContainerMemoryLimitUtilizationDataPoint(ts, 1) + + allMetricsCount++ + mb.RecordK8sContainerMemoryRequestUtilizationDataPoint(ts, 1) + defaultMetricsCount++ allMetricsCount++ mb.RecordK8sNodeCPUTimeDataPoint(ts, 1) @@ -200,6 +206,12 @@ func TestMetricsBuilder(t *testing.T) { allMetricsCount++ mb.RecordK8sPodMemoryWorkingSetDataPoint(ts, 1) + allMetricsCount++ + mb.RecordK8sPodMemoryLimitUtilizationDataPoint(ts, 1) + + allMetricsCount++ + mb.RecordK8sPodMemoryRequestUtilizationDataPoint(ts, 1) + defaultMetricsCount++ allMetricsCount++ mb.RecordK8sPodNetworkErrorsDataPoint(ts, 1, "interface-val", AttributeDirectionReceive) @@ -417,6 +429,30 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeInt, dp.ValueType()) assert.Equal(t, int64(1), dp.IntValue()) + case "k8s.container.memory_limit_utilization": + assert.False(t, validatedMetrics["k8s.container.memory_limit_utilization"], "Found a duplicate in the metrics slice: k8s.container.memory_limit_utilization") + validatedMetrics["k8s.container.memory_limit_utilization"] = true + assert.Equal(t, pmetric.MetricTypeGauge, ms.At(i).Type()) + assert.Equal(t, 1, ms.At(i).Gauge().DataPoints().Len()) + assert.Equal(t, "Container memory utilization as a ratio of the container's limits", ms.At(i).Description()) + assert.Equal(t, "1", ms.At(i).Unit()) + dp := ms.At(i).Gauge().DataPoints().At(0) + assert.Equal(t, start, dp.StartTimestamp()) + assert.Equal(t, ts, dp.Timestamp()) + assert.Equal(t, pmetric.NumberDataPointValueTypeDouble, dp.ValueType()) + assert.Equal(t, float64(1), dp.DoubleValue()) + case "k8s.container.memory_request_utilization": + assert.False(t, validatedMetrics["k8s.container.memory_request_utilization"], "Found a duplicate in the metrics slice: k8s.container.memory_request_utilization") + validatedMetrics["k8s.container.memory_request_utilization"] = true + assert.Equal(t, pmetric.MetricTypeGauge, ms.At(i).Type()) + assert.Equal(t, 1, ms.At(i).Gauge().DataPoints().Len()) + assert.Equal(t, "Container memory utilization as a ratio of the container's requests", ms.At(i).Description()) + assert.Equal(t, "1", ms.At(i).Unit()) + dp := ms.At(i).Gauge().DataPoints().At(0) + assert.Equal(t, start, dp.StartTimestamp()) + assert.Equal(t, ts, dp.Timestamp()) + assert.Equal(t, pmetric.NumberDataPointValueTypeDouble, dp.ValueType()) + assert.Equal(t, float64(1), dp.DoubleValue()) case "k8s.node.cpu.time": assert.False(t, validatedMetrics["k8s.node.cpu.time"], "Found a duplicate in the metrics slice: k8s.node.cpu.time") validatedMetrics["k8s.node.cpu.time"] = true @@ -739,6 +775,30 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeInt, dp.ValueType()) assert.Equal(t, int64(1), dp.IntValue()) + case "k8s.pod.memory_limit_utilization": + assert.False(t, validatedMetrics["k8s.pod.memory_limit_utilization"], "Found a duplicate in the metrics slice: k8s.pod.memory_limit_utilization") + validatedMetrics["k8s.pod.memory_limit_utilization"] = true + assert.Equal(t, pmetric.MetricTypeGauge, ms.At(i).Type()) + assert.Equal(t, 1, ms.At(i).Gauge().DataPoints().Len()) + assert.Equal(t, "Pod memory utilization as a ratio of the pod's total container limits. If any container is missing a limit the metric is not emitted.", ms.At(i).Description()) + assert.Equal(t, "1", ms.At(i).Unit()) + dp := ms.At(i).Gauge().DataPoints().At(0) + assert.Equal(t, start, dp.StartTimestamp()) + assert.Equal(t, ts, dp.Timestamp()) + assert.Equal(t, pmetric.NumberDataPointValueTypeDouble, dp.ValueType()) + assert.Equal(t, float64(1), dp.DoubleValue()) + case "k8s.pod.memory_request_utilization": + assert.False(t, validatedMetrics["k8s.pod.memory_request_utilization"], "Found a duplicate in the metrics slice: k8s.pod.memory_request_utilization") + validatedMetrics["k8s.pod.memory_request_utilization"] = true + assert.Equal(t, pmetric.MetricTypeGauge, ms.At(i).Type()) + assert.Equal(t, 1, ms.At(i).Gauge().DataPoints().Len()) + assert.Equal(t, "Pod memory utilization as a ratio of the pod's total container requests. If any container is missing a request the metric is not emitted.", ms.At(i).Description()) + assert.Equal(t, "1", ms.At(i).Unit()) + dp := ms.At(i).Gauge().DataPoints().At(0) + assert.Equal(t, start, dp.StartTimestamp()) + assert.Equal(t, ts, dp.Timestamp()) + assert.Equal(t, pmetric.NumberDataPointValueTypeDouble, dp.ValueType()) + assert.Equal(t, float64(1), dp.DoubleValue()) case "k8s.pod.network.errors": assert.False(t, validatedMetrics["k8s.pod.network.errors"], "Found a duplicate in the metrics slice: k8s.pod.network.errors") validatedMetrics["k8s.pod.network.errors"] = true diff --git a/receiver/kubeletstatsreceiver/internal/metadata/metrics.go b/receiver/kubeletstatsreceiver/internal/metadata/metrics.go index 838a53efd3ba..196accd9411d 100644 --- a/receiver/kubeletstatsreceiver/internal/metadata/metrics.go +++ b/receiver/kubeletstatsreceiver/internal/metadata/metrics.go @@ -19,8 +19,9 @@ type MetricsBuilders struct { } type CPUMetrics struct { - Time RecordDoubleDataPointFunc - Utilization RecordDoubleDataPointFunc + Time RecordDoubleDataPointFunc + Utilization RecordDoubleDataPointFunc + UsagePercent RecordDoubleDataPointFunc } var NodeCPUMetrics = CPUMetrics{ @@ -39,12 +40,14 @@ var ContainerCPUMetrics = CPUMetrics{ } type MemoryMetrics struct { - Available RecordIntDataPointFunc - Usage RecordIntDataPointFunc - Rss RecordIntDataPointFunc - WorkingSet RecordIntDataPointFunc - PageFaults RecordIntDataPointFunc - MajorPageFaults RecordIntDataPointFunc + Available RecordIntDataPointFunc + Usage RecordIntDataPointFunc + LimitUtilization RecordDoubleDataPointFunc + RequestUtilization RecordDoubleDataPointFunc + Rss RecordIntDataPointFunc + WorkingSet RecordIntDataPointFunc + PageFaults RecordIntDataPointFunc + MajorPageFaults RecordIntDataPointFunc } var NodeMemoryMetrics = MemoryMetrics{ @@ -57,21 +60,25 @@ var NodeMemoryMetrics = MemoryMetrics{ } var PodMemoryMetrics = MemoryMetrics{ - Available: (*MetricsBuilder).RecordK8sPodMemoryAvailableDataPoint, - Usage: (*MetricsBuilder).RecordK8sPodMemoryUsageDataPoint, - Rss: (*MetricsBuilder).RecordK8sPodMemoryRssDataPoint, - WorkingSet: (*MetricsBuilder).RecordK8sPodMemoryWorkingSetDataPoint, - PageFaults: (*MetricsBuilder).RecordK8sPodMemoryPageFaultsDataPoint, - MajorPageFaults: (*MetricsBuilder).RecordK8sPodMemoryMajorPageFaultsDataPoint, + Available: (*MetricsBuilder).RecordK8sPodMemoryAvailableDataPoint, + Usage: (*MetricsBuilder).RecordK8sPodMemoryUsageDataPoint, + LimitUtilization: (*MetricsBuilder).RecordK8sPodMemoryLimitUtilizationDataPoint, + RequestUtilization: (*MetricsBuilder).RecordK8sPodMemoryRequestUtilizationDataPoint, + Rss: (*MetricsBuilder).RecordK8sPodMemoryRssDataPoint, + WorkingSet: (*MetricsBuilder).RecordK8sPodMemoryWorkingSetDataPoint, + PageFaults: (*MetricsBuilder).RecordK8sPodMemoryPageFaultsDataPoint, + MajorPageFaults: (*MetricsBuilder).RecordK8sPodMemoryMajorPageFaultsDataPoint, } var ContainerMemoryMetrics = MemoryMetrics{ - Available: (*MetricsBuilder).RecordContainerMemoryAvailableDataPoint, - Usage: (*MetricsBuilder).RecordContainerMemoryUsageDataPoint, - Rss: (*MetricsBuilder).RecordContainerMemoryRssDataPoint, - WorkingSet: (*MetricsBuilder).RecordContainerMemoryWorkingSetDataPoint, - PageFaults: (*MetricsBuilder).RecordContainerMemoryPageFaultsDataPoint, - MajorPageFaults: (*MetricsBuilder).RecordContainerMemoryMajorPageFaultsDataPoint, + Available: (*MetricsBuilder).RecordContainerMemoryAvailableDataPoint, + Usage: (*MetricsBuilder).RecordContainerMemoryUsageDataPoint, + LimitUtilization: (*MetricsBuilder).RecordK8sContainerMemoryLimitUtilizationDataPoint, + RequestUtilization: (*MetricsBuilder).RecordK8sContainerMemoryRequestUtilizationDataPoint, + Rss: (*MetricsBuilder).RecordContainerMemoryRssDataPoint, + WorkingSet: (*MetricsBuilder).RecordContainerMemoryWorkingSetDataPoint, + PageFaults: (*MetricsBuilder).RecordContainerMemoryPageFaultsDataPoint, + MajorPageFaults: (*MetricsBuilder).RecordContainerMemoryMajorPageFaultsDataPoint, } type FilesystemMetrics struct { diff --git a/receiver/kubeletstatsreceiver/internal/metadata/testdata/config.yaml b/receiver/kubeletstatsreceiver/internal/metadata/testdata/config.yaml index e79fe3db7171..35c5011d0d9b 100644 --- a/receiver/kubeletstatsreceiver/internal/metadata/testdata/config.yaml +++ b/receiver/kubeletstatsreceiver/internal/metadata/testdata/config.yaml @@ -25,6 +25,10 @@ all_set: enabled: true container.uptime: enabled: true + k8s.container.memory_limit_utilization: + enabled: true + k8s.container.memory_request_utilization: + enabled: true k8s.node.cpu.time: enabled: true k8s.node.cpu.utilization: @@ -75,6 +79,10 @@ all_set: enabled: true k8s.pod.memory.working_set: enabled: true + k8s.pod.memory_limit_utilization: + enabled: true + k8s.pod.memory_request_utilization: + enabled: true k8s.pod.network.errors: enabled: true k8s.pod.network.io: @@ -148,6 +156,10 @@ none_set: enabled: false container.uptime: enabled: false + k8s.container.memory_limit_utilization: + enabled: false + k8s.container.memory_request_utilization: + enabled: false k8s.node.cpu.time: enabled: false k8s.node.cpu.utilization: @@ -198,6 +210,10 @@ none_set: enabled: false k8s.pod.memory.working_set: enabled: false + k8s.pod.memory_limit_utilization: + enabled: false + k8s.pod.memory_request_utilization: + enabled: false k8s.pod.network.errors: enabled: false k8s.pod.network.io: diff --git a/receiver/kubeletstatsreceiver/metadata.yaml b/receiver/kubeletstatsreceiver/metadata.yaml index 19169c2d465c..56fc76893419 100644 --- a/receiver/kubeletstatsreceiver/metadata.yaml +++ b/receiver/kubeletstatsreceiver/metadata.yaml @@ -217,6 +217,20 @@ metrics: gauge: value_type: int attributes: [] + k8s.pod.memory_limit_utilization: + enabled: false + description: "Pod memory utilization as a ratio of the pod's total container limits. If any container is missing a limit the metric is not emitted." + unit: 1 + gauge: + value_type: double + attributes: [ ] + k8s.pod.memory_request_utilization: + enabled: false + description: "Pod memory utilization as a ratio of the pod's total container requests. If any container is missing a request the metric is not emitted." + unit: 1 + gauge: + value_type: double + attributes: [ ] k8s.pod.memory.rss: enabled: true description: "Pod memory rss" @@ -323,6 +337,20 @@ metrics: gauge: value_type: int attributes: [] + k8s.container.memory_limit_utilization: + enabled: false + description: "Container memory utilization as a ratio of the container's limits" + unit: 1 + gauge: + value_type: double + attributes: [ ] + k8s.container.memory_request_utilization: + enabled: false + description: "Container memory utilization as a ratio of the container's requests" + unit: 1 + gauge: + value_type: double + attributes: [ ] container.memory.rss: enabled: true description: "Container memory rss" diff --git a/receiver/kubeletstatsreceiver/scraper.go b/receiver/kubeletstatsreceiver/scraper.go index 1c386ea18d86..580bac72fa00 100644 --- a/receiver/kubeletstatsreceiver/scraper.go +++ b/receiver/kubeletstatsreceiver/scraper.go @@ -36,6 +36,7 @@ type kubletScraper struct { k8sAPIClient kubernetes.Interface cachedVolumeSource map[string]v1.PersistentVolumeSource mbs *metadata.MetricsBuilders + needsResources bool } func newKubletScraper( @@ -58,6 +59,10 @@ func newKubletScraper( ContainerMetricsBuilder: metadata.NewMetricsBuilder(metricsConfig, set), OtherMetricsBuilder: metadata.NewMetricsBuilder(metricsConfig, set), }, + needsResources: metricsConfig.Metrics.K8sPodMemoryLimitUtilization.Enabled || + metricsConfig.Metrics.K8sPodMemoryRequestUtilization.Enabled || + metricsConfig.Metrics.K8sContainerMemoryLimitUtilization.Enabled || + metricsConfig.Metrics.K8sContainerMemoryRequestUtilization.Enabled, } return scraperhelper.NewScraper(metadata.Type, ks.scrape) } @@ -71,7 +76,7 @@ func (r *kubletScraper) scrape(context.Context) (pmetric.Metrics, error) { var podsMetadata *v1.PodList // fetch metadata only when extra metadata labels are needed - if len(r.extraMetadataLabels) > 0 { + if len(r.extraMetadataLabels) > 0 || r.needsResources { podsMetadata, err = r.metadataProvider.Pods() if err != nil { r.logger.Error("call to /pods endpoint failed", zap.Error(err)) @@ -80,6 +85,7 @@ func (r *kubletScraper) scrape(context.Context) (pmetric.Metrics, error) { } metadata := kubelet.NewMetadata(r.extraMetadataLabels, podsMetadata, r.detailedPVCLabelsSetter()) + mds := kubelet.MetricsData(r.logger, summary, metadata, r.metricGroupsToCollect, r.mbs) md := pmetric.NewMetrics() for i := range mds { diff --git a/receiver/kubeletstatsreceiver/scraper_test.go b/receiver/kubeletstatsreceiver/scraper_test.go index d8a9307665f2..06f3c5fc720d 100644 --- a/receiver/kubeletstatsreceiver/scraper_test.go +++ b/receiver/kubeletstatsreceiver/scraper_test.go @@ -10,6 +10,7 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/receiver/receivertest" @@ -130,6 +131,182 @@ func TestScraperWithMetadata(t *testing.T) { } } +func TestScraperWithPercentMetrics(t *testing.T) { + options := &scraperOptions{ + metricGroupsToCollect: map[kubelet.MetricGroup]bool{ + kubelet.ContainerMetricGroup: true, + kubelet.PodMetricGroup: true, + }, + } + metricsConfig := metadata.MetricsBuilderConfig{ + Metrics: metadata.MetricsConfig{ + ContainerCPUTime: metadata.MetricConfig{ + Enabled: false, + }, + ContainerCPUUtilization: metadata.MetricConfig{ + Enabled: false, + }, + ContainerFilesystemAvailable: metadata.MetricConfig{ + Enabled: false, + }, + ContainerFilesystemCapacity: metadata.MetricConfig{ + Enabled: false, + }, + ContainerFilesystemUsage: metadata.MetricConfig{ + Enabled: false, + }, + ContainerMemoryAvailable: metadata.MetricConfig{ + Enabled: false, + }, + ContainerMemoryMajorPageFaults: metadata.MetricConfig{ + Enabled: false, + }, + ContainerMemoryPageFaults: metadata.MetricConfig{ + Enabled: false, + }, + ContainerMemoryRss: metadata.MetricConfig{ + Enabled: false, + }, + ContainerMemoryUsage: metadata.MetricConfig{ + Enabled: false, + }, + K8sContainerMemoryLimitUtilization: metadata.MetricConfig{ + Enabled: true, + }, + K8sContainerMemoryRequestUtilization: metadata.MetricConfig{ + Enabled: true, + }, + ContainerMemoryWorkingSet: metadata.MetricConfig{ + Enabled: false, + }, + K8sNodeCPUTime: metadata.MetricConfig{ + Enabled: false, + }, + K8sNodeCPUUtilization: metadata.MetricConfig{ + Enabled: false, + }, + K8sNodeFilesystemAvailable: metadata.MetricConfig{ + Enabled: false, + }, + K8sNodeFilesystemCapacity: metadata.MetricConfig{ + Enabled: false, + }, + K8sNodeFilesystemUsage: metadata.MetricConfig{ + Enabled: false, + }, + K8sNodeMemoryAvailable: metadata.MetricConfig{ + Enabled: false, + }, + K8sNodeMemoryMajorPageFaults: metadata.MetricConfig{ + Enabled: false, + }, + K8sNodeMemoryPageFaults: metadata.MetricConfig{ + Enabled: false, + }, + K8sNodeMemoryRss: metadata.MetricConfig{ + Enabled: false, + }, + K8sNodeMemoryUsage: metadata.MetricConfig{ + Enabled: false, + }, + K8sNodeMemoryWorkingSet: metadata.MetricConfig{ + Enabled: false, + }, + K8sNodeNetworkErrors: metadata.MetricConfig{ + Enabled: false, + }, + K8sNodeNetworkIo: metadata.MetricConfig{ + Enabled: false, + }, + K8sPodCPUTime: metadata.MetricConfig{ + Enabled: false, + }, + K8sPodCPUUtilization: metadata.MetricConfig{ + Enabled: false, + }, + K8sPodFilesystemAvailable: metadata.MetricConfig{ + Enabled: false, + }, + K8sPodFilesystemCapacity: metadata.MetricConfig{ + Enabled: false, + }, + K8sPodFilesystemUsage: metadata.MetricConfig{ + Enabled: false, + }, + K8sPodMemoryAvailable: metadata.MetricConfig{ + Enabled: false, + }, + K8sPodMemoryMajorPageFaults: metadata.MetricConfig{ + Enabled: false, + }, + K8sPodMemoryPageFaults: metadata.MetricConfig{ + Enabled: false, + }, + K8sPodMemoryRss: metadata.MetricConfig{ + Enabled: false, + }, + K8sPodMemoryUsage: metadata.MetricConfig{ + Enabled: false, + }, + K8sPodMemoryLimitUtilization: metadata.MetricConfig{ + Enabled: true, + }, + K8sPodMemoryRequestUtilization: metadata.MetricConfig{ + Enabled: true, + }, + K8sPodMemoryWorkingSet: metadata.MetricConfig{ + Enabled: false, + }, + K8sPodNetworkErrors: metadata.MetricConfig{ + Enabled: false, + }, + K8sPodNetworkIo: metadata.MetricConfig{ + Enabled: false, + }, + K8sVolumeAvailable: metadata.MetricConfig{ + Enabled: false, + }, + K8sVolumeCapacity: metadata.MetricConfig{ + Enabled: false, + }, + K8sVolumeInodes: metadata.MetricConfig{ + Enabled: false, + }, + K8sVolumeInodesFree: metadata.MetricConfig{ + Enabled: false, + }, + K8sVolumeInodesUsed: metadata.MetricConfig{ + Enabled: false, + }, + }, + ResourceAttributes: metadata.DefaultResourceAttributesConfig(), + } + r, err := newKubletScraper( + &fakeRestClient{}, + receivertest.NewNopCreateSettings(), + options, + metricsConfig, + ) + require.NoError(t, err) + + md, err := r.Scrape(context.Background()) + require.NoError(t, err) + require.Equal(t, 4, md.DataPointCount()) + + assert.Equal(t, "k8s.pod.memory_limit_utilization", md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0).Name()) + assert.True(t, md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0).Gauge().DataPoints().At(0).DoubleValue() <= 1) + assert.True(t, md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0).Gauge().DataPoints().At(0).DoubleValue() >= 0) + assert.Equal(t, "k8s.pod.memory_request_utilization", md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(1).Name()) + assert.True(t, md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(1).Gauge().DataPoints().At(0).DoubleValue() > 1) + + assert.Equal(t, "k8s.container.memory_limit_utilization", md.ResourceMetrics().At(1).ScopeMetrics().At(0).Metrics().At(0).Name()) + assert.True(t, md.ResourceMetrics().At(1).ScopeMetrics().At(0).Metrics().At(0).Gauge().DataPoints().At(0).DoubleValue() <= 1) + assert.True(t, md.ResourceMetrics().At(1).ScopeMetrics().At(0).Metrics().At(0).Gauge().DataPoints().At(0).DoubleValue() >= 0) + assert.Equal(t, "k8s.container.memory_request_utilization", md.ResourceMetrics().At(1).ScopeMetrics().At(0).Metrics().At(1).Name()) + assert.True(t, md.ResourceMetrics().At(1).ScopeMetrics().At(0).Metrics().At(1).Gauge().DataPoints().At(0).DoubleValue() > 1) + +} + func TestScraperWithMetricGroups(t *testing.T) { tests := []struct { name string diff --git a/receiver/kubeletstatsreceiver/testdata/pods.json b/receiver/kubeletstatsreceiver/testdata/pods.json index 30153050316d..070f8146b370 100644 --- a/receiver/kubeletstatsreceiver/testdata/pods.json +++ b/receiver/kubeletstatsreceiver/testdata/pods.json @@ -5,6 +5,23 @@ "name": "kube-scheduler-minikube", "uid": "5795d0c442cb997ff93c49feeb9f6386" }, + "spec": { + "containers": [ + { + "name":"kube-scheduler", + "resources": { + "requests": { + "cpu": "50m", + "memory": "10M" + }, + "limits": { + "cpu": "100m", + "memory": "100M" + } + } + } + ] + }, "status": { "containerStatuses": [ {