From 98848fc91934738d3aa74325256b03ce6a456812 Mon Sep 17 00:00:00 2001 From: Pablo Baeyens Date: Fri, 22 Sep 2023 16:24:04 +0200 Subject: [PATCH 1/2] [receiver/hostmetrics/memory] Add system.memory.limit --- .../scraper/memoryscraper/documentation.md | 8 +++ .../internal/metadata/generated_config.go | 4 ++ .../metadata/generated_config_test.go | 2 + .../internal/metadata/generated_metrics.go | 59 +++++++++++++++++++ .../metadata/generated_metrics_test.go | 17 ++++++ .../internal/metadata/testdata/config.yaml | 4 ++ .../scraper/memoryscraper/memory_scraper.go | 5 ++ .../scraper/memoryscraper/metadata.yaml | 9 +++ 8 files changed, 108 insertions(+) diff --git a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/documentation.md b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/documentation.md index d80365d76593..55a3f6d396d8 100644 --- a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/documentation.md +++ b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/documentation.md @@ -46,6 +46,14 @@ An estimate of how much memory is available for starting new applications, witho | ---- | ----------- | ---------- | ----------------------- | --------- | | By | Sum | Int | Cumulative | false | +### system.memory.limit + +Total bytes of memory available. + +| Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | +| ---- | ----------- | ---------- | ----------------------- | --------- | +| By | Sum | Int | Cumulative | false | + ### system.memory.utilization Percentage of memory bytes in use. diff --git a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/generated_config.go b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/generated_config.go index 83e9309b9dfa..27772de37076 100644 --- a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/generated_config.go +++ b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/generated_config.go @@ -26,6 +26,7 @@ func (ms *MetricConfig) Unmarshal(parser *confmap.Conf) error { // MetricsConfig provides config for hostmetricsreceiver/memory metrics. type MetricsConfig struct { SystemLinuxMemoryAvailable MetricConfig `mapstructure:"system.linux.memory.available"` + SystemMemoryLimit MetricConfig `mapstructure:"system.memory.limit"` SystemMemoryUsage MetricConfig `mapstructure:"system.memory.usage"` SystemMemoryUtilization MetricConfig `mapstructure:"system.memory.utilization"` } @@ -35,6 +36,9 @@ func DefaultMetricsConfig() MetricsConfig { SystemLinuxMemoryAvailable: MetricConfig{ Enabled: false, }, + SystemMemoryLimit: MetricConfig{ + Enabled: false, + }, SystemMemoryUsage: MetricConfig{ Enabled: true, }, diff --git a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/generated_config_test.go b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/generated_config_test.go index 8e966652ec2b..4875f5b7732e 100644 --- a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/generated_config_test.go +++ b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/generated_config_test.go @@ -27,6 +27,7 @@ func TestMetricsBuilderConfig(t *testing.T) { want: MetricsBuilderConfig{ Metrics: MetricsConfig{ SystemLinuxMemoryAvailable: MetricConfig{Enabled: true}, + SystemMemoryLimit: MetricConfig{Enabled: true}, SystemMemoryUsage: MetricConfig{Enabled: true}, SystemMemoryUtilization: MetricConfig{Enabled: true}, }, @@ -37,6 +38,7 @@ func TestMetricsBuilderConfig(t *testing.T) { want: MetricsBuilderConfig{ Metrics: MetricsConfig{ SystemLinuxMemoryAvailable: MetricConfig{Enabled: false}, + SystemMemoryLimit: MetricConfig{Enabled: false}, SystemMemoryUsage: MetricConfig{Enabled: false}, SystemMemoryUtilization: MetricConfig{Enabled: false}, }, diff --git a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/generated_metrics.go b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/generated_metrics.go index d457be578953..1539258e61e6 100644 --- a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/generated_metrics.go +++ b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/generated_metrics.go @@ -109,6 +109,57 @@ func newMetricSystemLinuxMemoryAvailable(cfg MetricConfig) metricSystemLinuxMemo return m } +type metricSystemMemoryLimit 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 system.memory.limit metric with initial data. +func (m *metricSystemMemoryLimit) init() { + m.data.SetName("system.memory.limit") + m.data.SetDescription("Total bytes of memory available.") + m.data.SetUnit("By") + m.data.SetEmptySum() + m.data.Sum().SetIsMonotonic(false) + m.data.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityCumulative) +} + +func (m *metricSystemMemoryLimit) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val int64) { + if !m.config.Enabled { + return + } + dp := m.data.Sum().DataPoints().AppendEmpty() + dp.SetStartTimestamp(start) + dp.SetTimestamp(ts) + dp.SetIntValue(val) +} + +// updateCapacity saves max length of data point slices that will be used for the slice capacity. +func (m *metricSystemMemoryLimit) updateCapacity() { + if m.data.Sum().DataPoints().Len() > m.capacity { + m.capacity = m.data.Sum().DataPoints().Len() + } +} + +// emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. +func (m *metricSystemMemoryLimit) emit(metrics pmetric.MetricSlice) { + if m.config.Enabled && m.data.Sum().DataPoints().Len() > 0 { + m.updateCapacity() + m.data.MoveTo(metrics.AppendEmpty()) + m.init() + } +} + +func newMetricSystemMemoryLimit(cfg MetricConfig) metricSystemMemoryLimit { + m := metricSystemMemoryLimit{config: cfg} + if cfg.Enabled { + m.data = pmetric.NewMetric() + m.init() + } + return m +} + type metricSystemMemoryUsage struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. @@ -222,6 +273,7 @@ type MetricsBuilder struct { metricsBuffer pmetric.Metrics // accumulates metrics data before emitting. buildInfo component.BuildInfo // contains version information. metricSystemLinuxMemoryAvailable metricSystemLinuxMemoryAvailable + metricSystemMemoryLimit metricSystemMemoryLimit metricSystemMemoryUsage metricSystemMemoryUsage metricSystemMemoryUtilization metricSystemMemoryUtilization } @@ -243,6 +295,7 @@ func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.CreateSetting metricsBuffer: pmetric.NewMetrics(), buildInfo: settings.BuildInfo, metricSystemLinuxMemoryAvailable: newMetricSystemLinuxMemoryAvailable(mbc.Metrics.SystemLinuxMemoryAvailable), + metricSystemMemoryLimit: newMetricSystemMemoryLimit(mbc.Metrics.SystemMemoryLimit), metricSystemMemoryUsage: newMetricSystemMemoryUsage(mbc.Metrics.SystemMemoryUsage), metricSystemMemoryUtilization: newMetricSystemMemoryUtilization(mbc.Metrics.SystemMemoryUtilization), } @@ -303,6 +356,7 @@ func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) { ils.Scope().SetVersion(mb.buildInfo.Version) ils.Metrics().EnsureCapacity(mb.metricsCapacity) mb.metricSystemLinuxMemoryAvailable.emit(ils.Metrics()) + mb.metricSystemMemoryLimit.emit(ils.Metrics()) mb.metricSystemMemoryUsage.emit(ils.Metrics()) mb.metricSystemMemoryUtilization.emit(ils.Metrics()) @@ -330,6 +384,11 @@ func (mb *MetricsBuilder) RecordSystemLinuxMemoryAvailableDataPoint(ts pcommon.T mb.metricSystemLinuxMemoryAvailable.recordDataPoint(mb.startTime, ts, val) } +// RecordSystemMemoryLimitDataPoint adds a data point to system.memory.limit metric. +func (mb *MetricsBuilder) RecordSystemMemoryLimitDataPoint(ts pcommon.Timestamp, val int64) { + mb.metricSystemMemoryLimit.recordDataPoint(mb.startTime, ts, val) +} + // RecordSystemMemoryUsageDataPoint adds a data point to system.memory.usage metric. func (mb *MetricsBuilder) RecordSystemMemoryUsageDataPoint(ts pcommon.Timestamp, val int64, stateAttributeValue AttributeState) { mb.metricSystemMemoryUsage.recordDataPoint(mb.startTime, ts, val, stateAttributeValue.String()) diff --git a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/generated_metrics_test.go b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/generated_metrics_test.go index 09f81a68e32b..8438b3ec0618 100644 --- a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/generated_metrics_test.go +++ b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/generated_metrics_test.go @@ -58,6 +58,9 @@ func TestMetricsBuilder(t *testing.T) { allMetricsCount++ mb.RecordSystemLinuxMemoryAvailableDataPoint(ts, 1) + allMetricsCount++ + mb.RecordSystemMemoryLimitDataPoint(ts, 1) + defaultMetricsCount++ allMetricsCount++ mb.RecordSystemMemoryUsageDataPoint(ts, 1, AttributeStateBuffered) @@ -101,6 +104,20 @@ 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 "system.memory.limit": + assert.False(t, validatedMetrics["system.memory.limit"], "Found a duplicate in the metrics slice: system.memory.limit") + validatedMetrics["system.memory.limit"] = true + assert.Equal(t, pmetric.MetricTypeSum, ms.At(i).Type()) + assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) + assert.Equal(t, "Total bytes of memory available.", ms.At(i).Description()) + assert.Equal(t, "By", ms.At(i).Unit()) + assert.Equal(t, false, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) + dp := ms.At(i).Sum().DataPoints().At(0) + assert.Equal(t, start, dp.StartTimestamp()) + assert.Equal(t, ts, dp.Timestamp()) + assert.Equal(t, pmetric.NumberDataPointValueTypeInt, dp.ValueType()) + assert.Equal(t, int64(1), dp.IntValue()) case "system.memory.usage": assert.False(t, validatedMetrics["system.memory.usage"], "Found a duplicate in the metrics slice: system.memory.usage") validatedMetrics["system.memory.usage"] = true diff --git a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/testdata/config.yaml b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/testdata/config.yaml index 5b66777a2c1d..f0fa3f3d0eba 100644 --- a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/testdata/config.yaml +++ b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/testdata/config.yaml @@ -3,6 +3,8 @@ all_set: metrics: system.linux.memory.available: enabled: true + system.memory.limit: + enabled: true system.memory.usage: enabled: true system.memory.utilization: @@ -11,6 +13,8 @@ none_set: metrics: system.linux.memory.available: enabled: false + system.memory.limit: + enabled: false system.memory.usage: enabled: false system.memory.utilization: diff --git a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/memory_scraper.go b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/memory_scraper.go index ff57723774ad..50aa7c2478f0 100644 --- a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/memory_scraper.go +++ b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/memory_scraper.go @@ -53,6 +53,10 @@ func (s *scraper) start(ctx context.Context, _ component.Host) error { return nil } +func (s *scraper) recordMemoryLimitMetric(now pcommon.Timestamp, memInfo *mem.VirtualMemoryStat) { + s.mb.RecordSystemMemoryLimitDataPoint(now, int64(memInfo.Total)) +} + func (s *scraper) scrape(ctx context.Context) (pmetric.Metrics, error) { ctx = context.WithValue(ctx, common.EnvKey, s.envMap) @@ -69,6 +73,7 @@ func (s *scraper) scrape(ctx context.Context) (pmetric.Metrics, error) { memInfo.Total), metricsLen) } s.recordMemoryUtilizationMetric(now, memInfo) + s.recordMemoryLimitMetric(now, memInfo) s.recordSystemSpecificMetrics(now, memInfo) } diff --git a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/metadata.yaml b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/metadata.yaml index a2cb7d41aeaa..d5541994c592 100644 --- a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/metadata.yaml +++ b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/metadata.yaml @@ -11,6 +11,15 @@ attributes: enum: [buffered, cached, inactive, free, slab_reclaimable, slab_unreclaimable, used] metrics: + system.memory.limit: + enabled: false + description: Total bytes of memory available. + unit: By + sum: + value_type: int + aggregation_temporality: cumulative + monotonic: false + system.memory.usage: enabled: true description: Bytes of memory in use. From 2c5e6d9f09da482a2f0805f762b7a014b0376ae5 Mon Sep 17 00:00:00 2001 From: Pablo Baeyens Date: Tue, 26 Sep 2023 14:10:08 +0200 Subject: [PATCH 2/2] Add changelog entry --- .chloggen/mx-psi_system.memory.limit.yaml | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100755 .chloggen/mx-psi_system.memory.limit.yaml diff --git a/.chloggen/mx-psi_system.memory.limit.yaml b/.chloggen/mx-psi_system.memory.limit.yaml new file mode 100755 index 000000000000..d2c33cea95d4 --- /dev/null +++ b/.chloggen/mx-psi_system.memory.limit.yaml @@ -0,0 +1,28 @@ +# 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: hostmetricsreceiver + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: "Add `system.memory.limit` metric reporting the total memory available." + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [30306] + +# (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: | + This metric is opt-in. To enable it, set `scrapers::memory::metrics::system.memory.limit::enabled` to `true` in the hostmetrics config. + +# 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: []