diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bceb2d1e827..5656b2e7d1b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - `postgresreceiver`: Update to mdatagen v2 (#7503) - `nginxreceiver`: Update to mdatagen v2 (#7549) - `datadogexporter`: Fix traces exporter's initialization log (#7564) +- `hostreceiver/memoryscraper`: Migrate the scraper to the mdatagen metrics builder (#7421) ## 🛑 Breaking changes 🛑 diff --git a/receiver/hostmetricsreceiver/config_test.go b/receiver/hostmetricsreceiver/config_test.go index 2f2c0f7d9cdc..78326450c288 100644 --- a/receiver/hostmetricsreceiver/config_test.go +++ b/receiver/hostmetricsreceiver/config_test.go @@ -75,7 +75,7 @@ func TestLoadConfig(t *testing.T) { return cfg })(), filesystemscraper.TypeStr: &filesystemscraper.Config{}, - memoryscraper.TypeStr: &memoryscraper.Config{}, + memoryscraper.TypeStr: (&memoryscraper.Factory{}).CreateDefaultConfig(), networkscraper.TypeStr: (func() internal.Config { cfg := (&networkscraper.Factory{}).CreateDefaultConfig() cfg.(*networkscraper.Config).Include = networkscraper.MatchConfig{ diff --git a/receiver/hostmetricsreceiver/hostmetrics_receiver_test.go b/receiver/hostmetricsreceiver/hostmetrics_receiver_test.go index 04ed0ce1f6d2..23d478a0ebc7 100644 --- a/receiver/hostmetricsreceiver/hostmetrics_receiver_test.go +++ b/receiver/hostmetricsreceiver/hostmetrics_receiver_test.go @@ -109,7 +109,7 @@ func TestGatherMetrics_EndToEnd(t *testing.T) { diskscraper.TypeStr: scraperFactories[diskscraper.TypeStr].CreateDefaultConfig(), filesystemscraper.TypeStr: &filesystemscraper.Config{}, loadscraper.TypeStr: scraperFactories[loadscraper.TypeStr].CreateDefaultConfig(), - memoryscraper.TypeStr: &memoryscraper.Config{}, + memoryscraper.TypeStr: scraperFactories[memoryscraper.TypeStr].CreateDefaultConfig(), networkscraper.TypeStr: scraperFactories[networkscraper.TypeStr].CreateDefaultConfig(), pagingscraper.TypeStr: &pagingscraper.Config{}, processesscraper.TypeStr: &processesscraper.Config{}, diff --git a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/config.go b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/config.go index c5f754f78d77..1f219e8efd74 100644 --- a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/config.go +++ b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/config.go @@ -14,9 +14,15 @@ package memoryscraper // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver/internal/scraper/memoryscraper" -import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver/internal" +import ( + "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver/internal" + "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata" +) // Config relating to Memory Metric Scraper. type Config struct { internal.ConfigSettings `mapstructure:",squash"` // squash ensures fields are correctly decoded in embedded struct + + // Metrics allows to customize scraped metrics representation. + Metrics metadata.MetricsSettings `mapstructure:"metrics"` } diff --git a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/doc.go b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/doc.go index 1e2a50ea0133..788398aad8f4 100644 --- a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/doc.go +++ b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/doc.go @@ -15,6 +15,6 @@ //go:build !windows // +build !windows -//go:generate mdatagen metadata.yaml +//go:generate mdatagen --experimental-gen metadata.yaml package memoryscraper // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver/internal/scraper/memoryscraper" diff --git a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/factory.go b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/factory.go index a865edb4bb50..7f687ebcfa96 100644 --- a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/factory.go +++ b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/factory.go @@ -21,6 +21,7 @@ import ( "go.uber.org/zap" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver/internal" + "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata" ) // This file implements Factory for Memory scraper. @@ -36,7 +37,9 @@ type Factory struct { // CreateDefaultConfig creates the default configuration for the Scraper. func (f *Factory) CreateDefaultConfig() internal.Config { - return &Config{} + return &Config{ + Metrics: metadata.DefaultMetricsSettings(), + } } // CreateMetricsScraper creates a scraper based on provided config. @@ -48,5 +51,8 @@ func (f *Factory) CreateMetricsScraper( cfg := config.(*Config) s := newMemoryScraper(ctx, cfg) - return scraperhelper.NewScraper(TypeStr, s.Scrape) + return scraperhelper.NewScraper(TypeStr, + s.scrape, + scraperhelper.WithStart(s.start), + ) } diff --git a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/generated_metrics.go b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/generated_metrics.go deleted file mode 100644 index 3ec08c3c1358..000000000000 --- a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/generated_metrics.go +++ /dev/null @@ -1,110 +0,0 @@ -// Code generated by mdatagen. DO NOT EDIT. - -package metadata - -import ( - "go.opentelemetry.io/collector/config" - "go.opentelemetry.io/collector/model/pdata" -) - -// Type is the component type name. -const Type config.Type = "memory" - -// MetricIntf is an interface to generically interact with generated metric. -type MetricIntf interface { - Name() string - New() pdata.Metric - Init(metric pdata.Metric) -} - -// Intentionally not exposing this so that it is opaque and can change freely. -type metricImpl struct { - name string - initFunc func(pdata.Metric) -} - -// Name returns the metric name. -func (m *metricImpl) Name() string { - return m.name -} - -// New creates a metric object preinitialized. -func (m *metricImpl) New() pdata.Metric { - metric := pdata.NewMetric() - m.Init(metric) - return metric -} - -// Init initializes the provided metric object. -func (m *metricImpl) Init(metric pdata.Metric) { - m.initFunc(metric) -} - -type metricStruct struct { - SystemMemoryUsage MetricIntf -} - -// Names returns a list of all the metric name strings. -func (m *metricStruct) Names() []string { - return []string{ - "system.memory.usage", - } -} - -var metricsByName = map[string]MetricIntf{ - "system.memory.usage": Metrics.SystemMemoryUsage, -} - -func (m *metricStruct) ByName(n string) MetricIntf { - return metricsByName[n] -} - -// Metrics contains a set of methods for each metric that help with -// manipulating those metrics. -var Metrics = &metricStruct{ - &metricImpl{ - "system.memory.usage", - func(metric pdata.Metric) { - metric.SetName("system.memory.usage") - metric.SetDescription("Bytes of memory in use.") - metric.SetUnit("By") - metric.SetDataType(pdata.MetricDataTypeSum) - metric.Sum().SetIsMonotonic(false) - metric.Sum().SetAggregationTemporality(pdata.MetricAggregationTemporalityCumulative) - }, - }, -} - -// M contains a set of methods for each metric that help with -// manipulating those metrics. M is an alias for Metrics -var M = Metrics - -// Attributes contains the possible metric attributes that can be used. -var Attributes = struct { - // State (Breakdown of memory usage by type.) - State string -}{ - "state", -} - -// A is an alias for Attributes. -var A = Attributes - -// AttributeState are the possible values that the attribute "state" can have. -var AttributeState = struct { - Buffered string - Cached string - Inactive string - Free string - SlabReclaimable string - SlabUnreclaimable string - Used string -}{ - "buffered", - "cached", - "inactive", - "free", - "slab_reclaimable", - "slab_unreclaimable", - "used", -} diff --git a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/generated_metrics_v2.go b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/generated_metrics_v2.go new file mode 100644 index 000000000000..cff6fc1a418f --- /dev/null +++ b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata/generated_metrics_v2.go @@ -0,0 +1,159 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package metadata + +import ( + "time" + + "go.opentelemetry.io/collector/model/pdata" +) + +// MetricSettings provides common settings for a particular metric. +type MetricSettings struct { + Enabled bool `mapstructure:"enabled"` +} + +// MetricsSettings provides settings for memory metrics. +type MetricsSettings struct { + SystemMemoryUsage MetricSettings `mapstructure:"system.memory.usage"` +} + +func DefaultMetricsSettings() MetricsSettings { + return MetricsSettings{ + SystemMemoryUsage: MetricSettings{ + Enabled: true, + }, + } +} + +type metricSystemMemoryUsage struct { + data pdata.Metric // data buffer for generated metric. + settings MetricSettings // metric settings provided by user. + capacity int // max observed number of data points added to the metric. +} + +// init fills system.memory.usage metric with initial data. +func (m *metricSystemMemoryUsage) init() { + m.data.SetName("system.memory.usage") + m.data.SetDescription("Bytes of memory in use.") + m.data.SetUnit("By") + m.data.SetDataType(pdata.MetricDataTypeSum) + m.data.Sum().SetIsMonotonic(false) + m.data.Sum().SetAggregationTemporality(pdata.MetricAggregationTemporalityCumulative) + m.data.Sum().DataPoints().EnsureCapacity(m.capacity) +} + +func (m *metricSystemMemoryUsage) recordDataPoint(start pdata.Timestamp, ts pdata.Timestamp, val int64, stateAttributeValue string) { + if !m.settings.Enabled { + return + } + dp := m.data.Sum().DataPoints().AppendEmpty() + dp.SetStartTimestamp(start) + dp.SetTimestamp(ts) + dp.SetIntVal(val) + dp.Attributes().Insert(A.State, pdata.NewAttributeValueString(stateAttributeValue)) +} + +// updateCapacity saves max length of data point slices that will be used for the slice capacity. +func (m *metricSystemMemoryUsage) 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 *metricSystemMemoryUsage) emit(metrics pdata.MetricSlice) { + if m.settings.Enabled && m.data.Sum().DataPoints().Len() > 0 { + m.updateCapacity() + m.data.MoveTo(metrics.AppendEmpty()) + m.init() + } +} + +func newMetricSystemMemoryUsage(settings MetricSettings) metricSystemMemoryUsage { + m := metricSystemMemoryUsage{settings: settings} + if settings.Enabled { + m.data = pdata.NewMetric() + m.init() + } + return m +} + +// 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 settings. +type MetricsBuilder struct { + startTime pdata.Timestamp + metricSystemMemoryUsage metricSystemMemoryUsage +} + +// metricBuilderOption applies changes to default metrics builder. +type metricBuilderOption func(*MetricsBuilder) + +// WithStartTime sets startTime on the metrics builder. +func WithStartTime(startTime pdata.Timestamp) metricBuilderOption { + return func(mb *MetricsBuilder) { + mb.startTime = startTime + } +} + +func NewMetricsBuilder(settings MetricsSettings, options ...metricBuilderOption) *MetricsBuilder { + mb := &MetricsBuilder{ + startTime: pdata.NewTimestampFromTime(time.Now()), + metricSystemMemoryUsage: newMetricSystemMemoryUsage(settings.SystemMemoryUsage), + } + for _, op := range options { + op(mb) + } + return mb +} + +// Emit appends generated metrics to a pdata.MetricsSlice and updates the internal state to be ready for recording +// another set of data points. This function will be doing all transformations required to produce metric representation +// defined in metadata and user settings, e.g. delta/cumulative translation. +func (mb *MetricsBuilder) Emit(metrics pdata.MetricSlice) { + mb.metricSystemMemoryUsage.emit(metrics) +} + +// RecordSystemMemoryUsageDataPoint adds a data point to system.memory.usage metric. +func (mb *MetricsBuilder) RecordSystemMemoryUsageDataPoint(ts pdata.Timestamp, val int64, stateAttributeValue string) { + mb.metricSystemMemoryUsage.recordDataPoint(mb.startTime, ts, val, stateAttributeValue) +} + +// Reset resets metrics builder to its initial state. It should be used when external metrics source is restarted, +// and metrics builder should update its startTime and reset it's internal state accordingly. +func (mb *MetricsBuilder) Reset(options ...metricBuilderOption) { + mb.startTime = pdata.NewTimestampFromTime(time.Now()) + for _, op := range options { + op(mb) + } +} + +// Attributes contains the possible metric attributes that can be used. +var Attributes = struct { + // State (Breakdown of memory usage by type.) + State string +}{ + "state", +} + +// A is an alias for Attributes. +var A = Attributes + +// AttributeState are the possible values that the attribute "state" can have. +var AttributeState = struct { + Buffered string + Cached string + Inactive string + Free string + SlabReclaimable string + SlabUnreclaimable string + Used string +}{ + "buffered", + "cached", + "inactive", + "free", + "slab_reclaimable", + "slab_unreclaimable", + "used", +} diff --git a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/memory_scraper.go b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/memory_scraper.go index 17fac979bf22..d39923862e8b 100644 --- a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/memory_scraper.go +++ b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/memory_scraper.go @@ -18,7 +18,9 @@ import ( "context" "time" + "github.com/shirou/gopsutil/v3/host" "github.com/shirou/gopsutil/v3/mem" + "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/model/pdata" "go.opentelemetry.io/collector/receiver/scrapererror" @@ -30,17 +32,28 @@ const metricsLen = 1 // scraper for Memory Metrics type scraper struct { config *Config + mb *metadata.MetricsBuilder // for mocking gopsutil mem.VirtualMemory virtualMemory func() (*mem.VirtualMemoryStat, error) + bootTime func() (uint64, error) } // newMemoryScraper creates a Memory Scraper func newMemoryScraper(_ context.Context, cfg *Config) *scraper { - return &scraper{config: cfg, virtualMemory: mem.VirtualMemory} + return &scraper{config: cfg, virtualMemory: mem.VirtualMemory, bootTime: host.BootTime} } -func (s *scraper) Scrape(_ context.Context) (pdata.Metrics, error) { +func (s *scraper) start(context.Context, component.Host) error { + bootTime, err := s.bootTime() + if err != nil { + return err + } + s.mb = metadata.NewMetricsBuilder(s.config.Metrics, metadata.WithStartTime(pdata.Timestamp(bootTime*1e9))) + return nil +} + +func (s *scraper) scrape(_ context.Context) (pdata.Metrics, error) { md := pdata.NewMetrics() metrics := md.ResourceMetrics().AppendEmpty().InstrumentationLibraryMetrics().AppendEmpty().Metrics() @@ -50,21 +63,7 @@ func (s *scraper) Scrape(_ context.Context) (pdata.Metrics, error) { return md, scrapererror.NewPartialScrapeError(err, metricsLen) } - metrics.EnsureCapacity(metricsLen) - initializeMemoryUsageMetric(metrics.AppendEmpty(), now, memInfo) + s.recordMemoryUsageDataPoints(now, memInfo) + s.mb.Emit(metrics) return md, nil } - -func initializeMemoryUsageMetric(metric pdata.Metric, now pdata.Timestamp, memInfo *mem.VirtualMemoryStat) { - metadata.Metrics.SystemMemoryUsage.Init(metric) - - idps := metric.Sum().DataPoints() - idps.EnsureCapacity(memStatesLen) - appendMemoryUsageStateDataPoints(idps, now, memInfo) -} - -func initializeMemoryUsageDataPoint(dataPoint pdata.NumberDataPoint, now pdata.Timestamp, stateLabel string, value int64) { - dataPoint.Attributes().InsertString(metadata.Attributes.State, stateLabel) - dataPoint.SetTimestamp(now) - dataPoint.SetIntVal(value) -} diff --git a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/memory_scraper_linux.go b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/memory_scraper_linux.go index 1270321e1870..e94384474f3f 100644 --- a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/memory_scraper_linux.go +++ b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/memory_scraper_linux.go @@ -24,13 +24,11 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata" ) -const memStatesLen = 6 - -func appendMemoryUsageStateDataPoints(idps pdata.NumberDataPointSlice, now pdata.Timestamp, memInfo *mem.VirtualMemoryStat) { - initializeMemoryUsageDataPoint(idps.AppendEmpty(), now, metadata.AttributeState.Used, int64(memInfo.Used)) - initializeMemoryUsageDataPoint(idps.AppendEmpty(), now, metadata.AttributeState.Free, int64(memInfo.Free)) - initializeMemoryUsageDataPoint(idps.AppendEmpty(), now, metadata.AttributeState.Buffered, int64(memInfo.Buffers)) - initializeMemoryUsageDataPoint(idps.AppendEmpty(), now, metadata.AttributeState.Cached, int64(memInfo.Cached)) - initializeMemoryUsageDataPoint(idps.AppendEmpty(), now, metadata.AttributeState.SlabReclaimable, int64(memInfo.Sreclaimable)) - initializeMemoryUsageDataPoint(idps.AppendEmpty(), now, metadata.AttributeState.SlabUnreclaimable, int64(memInfo.Sunreclaim)) +func (s *scraper) recordMemoryUsageDataPoints(now pdata.Timestamp, memInfo *mem.VirtualMemoryStat) { + s.mb.RecordSystemMemoryUsageDataPoint(now, int64(memInfo.Used), metadata.AttributeState.Used) + s.mb.RecordSystemMemoryUsageDataPoint(now, int64(memInfo.Free), metadata.AttributeState.Free) + s.mb.RecordSystemMemoryUsageDataPoint(now, int64(memInfo.Buffers), metadata.AttributeState.Buffered) + s.mb.RecordSystemMemoryUsageDataPoint(now, int64(memInfo.Cached), metadata.AttributeState.Cached) + s.mb.RecordSystemMemoryUsageDataPoint(now, int64(memInfo.Sreclaimable), metadata.AttributeState.SlabReclaimable) + s.mb.RecordSystemMemoryUsageDataPoint(now, int64(memInfo.Sunreclaim), metadata.AttributeState.SlabUnreclaimable) } diff --git a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/memory_scraper_others.go b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/memory_scraper_others.go index 4286707c30b1..0394837875b7 100644 --- a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/memory_scraper_others.go +++ b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/memory_scraper_others.go @@ -24,10 +24,8 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata" ) -const memStatesLen = 3 - -func appendMemoryUsageStateDataPoints(idps pdata.NumberDataPointSlice, now pdata.Timestamp, memInfo *mem.VirtualMemoryStat) { - initializeMemoryUsageDataPoint(idps.AppendEmpty(), now, metadata.AttributeState.Used, int64(memInfo.Used)) - initializeMemoryUsageDataPoint(idps.AppendEmpty(), now, metadata.AttributeState.Free, int64(memInfo.Free)) - initializeMemoryUsageDataPoint(idps.AppendEmpty(), now, metadata.AttributeState.Inactive, int64(memInfo.Inactive)) +func (s *scraper) recordMemoryUsageDataPoints(now pdata.Timestamp, memInfo *mem.VirtualMemoryStat) { + s.mb.RecordSystemMemoryUsageDataPoint(now, int64(memInfo.Used), metadata.AttributeState.Used) + s.mb.RecordSystemMemoryUsageDataPoint(now, int64(memInfo.Free), metadata.AttributeState.Free) + s.mb.RecordSystemMemoryUsageDataPoint(now, int64(memInfo.Inactive), metadata.AttributeState.Inactive) } diff --git a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/memory_scraper_test.go b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/memory_scraper_test.go index c48259e06d74..505cbff9a793 100644 --- a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/memory_scraper_test.go +++ b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/memory_scraper_test.go @@ -23,8 +23,8 @@ import ( "github.com/shirou/gopsutil/v3/mem" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/model/pdata" - "go.opentelemetry.io/collector/receiver/scrapererror" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver/internal" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata" @@ -33,60 +33,104 @@ import ( func TestScrape(t *testing.T) { type testCase struct { name string + config Config + bootTimeFunc func() (uint64, error) virtualMemoryFunc func() (*mem.VirtualMemoryStat, error) - expectedErr string + initializationErr string + scrapeErr string + expectMetrics int + expectedStartTime pdata.Timestamp } testCases := []testCase{ { - name: "Standard", + name: "Standard", + config: Config{Metrics: metadata.DefaultMetricsSettings()}, + expectMetrics: metricsLen, + }, + { + name: "Validate Start Time", + config: Config{Metrics: metadata.DefaultMetricsSettings()}, + bootTimeFunc: func() (uint64, error) { return 100, nil }, + expectMetrics: metricsLen, + expectedStartTime: 100 * 1e9, + }, + { + name: "Boot Time Error", + config: Config{Metrics: metadata.DefaultMetricsSettings()}, + bootTimeFunc: func() (uint64, error) { return 0, errors.New("err1") }, + initializationErr: "err1", + expectMetrics: metricsLen, + }, + { + name: "Disable one metric", + config: (func() Config { + config := Config{Metrics: metadata.DefaultMetricsSettings()} + config.Metrics.SystemMemoryUsage.Enabled = false + return config + })(), + expectMetrics: metricsLen - 1, }, { name: "Error", + config: Config{Metrics: metadata.DefaultMetricsSettings()}, virtualMemoryFunc: func() (*mem.VirtualMemoryStat, error) { return nil, errors.New("err1") }, - expectedErr: "err1", + scrapeErr: "err1", + expectMetrics: metricsLen, }, } - for _, test := range testCases { t.Run(test.name, func(t *testing.T) { - scraper := newMemoryScraper(context.Background(), &Config{}) + scraper := newMemoryScraper(context.Background(), &test.config) + if test.bootTimeFunc != nil { + scraper.bootTime = test.bootTimeFunc + } if test.virtualMemoryFunc != nil { scraper.virtualMemory = test.virtualMemoryFunc } - md, err := scraper.Scrape(context.Background()) - if test.expectedErr != "" { - assert.EqualError(t, err, test.expectedErr) - - isPartial := scrapererror.IsPartialScrapeError(err) - assert.True(t, isPartial) - if isPartial { - assert.Equal(t, metricsLen, err.(scrapererror.PartialScrapeError).Failed) - } + err := scraper.start(context.Background(), componenttest.NewNopHost()) + if test.initializationErr != "" { + assert.EqualError(t, err, test.initializationErr) + return + } + require.NoError(t, err, "Failed to initialize memory scraper: %v", err) + md, err := scraper.scrape(context.Background()) + if test.scrapeErr != "" { + assert.EqualError(t, err, test.scrapeErr) return } require.NoError(t, err, "Failed to scrape metrics: %v", err) - assert.Equal(t, 1, md.MetricCount()) - + assert.Equal(t, test.expectMetrics, md.MetricCount()) metrics := md.ResourceMetrics().At(0).InstrumentationLibraryMetrics().At(0).Metrics() - assertMemoryUsageMetricValid(t, metrics.At(0), metadata.Metrics.SystemMemoryUsage.New()) - - if runtime.GOOS == "linux" { - assertMemoryUsageMetricHasLinuxSpecificStateLabels(t, metrics.At(0)) - } else if runtime.GOOS != "windows" { - internal.AssertSumMetricHasAttributeValue(t, metrics.At(0), 2, metadata.Attributes.State, pdata.NewAttributeValueString(metadata.AttributeState.Inactive)) + assert.Equal(t, test.expectMetrics, metrics.Len()) + + if test.expectMetrics > 0 { + assertMemoryUsageMetricValid(t, metrics.At(0), test.expectedStartTime) + if runtime.GOOS == "linux" { + assertMemoryUsageMetricHasLinuxSpecificStateLabels(t, metrics.At(0)) + } else if runtime.GOOS != "windows" { + internal.AssertSumMetricHasAttributeValue(t, metrics.At(0), 2, metadata.Attributes.State, pdata.NewAttributeValueString(metadata.AttributeState.Inactive)) + } + internal.AssertSameTimeStampForAllMetrics(t, metrics) } - internal.AssertSameTimeStampForAllMetrics(t, metrics) }) } } -func assertMemoryUsageMetricValid(t *testing.T, metric pdata.Metric, descriptor pdata.Metric) { - internal.AssertDescriptorEqual(t, descriptor, metric) +func assertMemoryUsageMetricValid(t *testing.T, metric pdata.Metric, startTime pdata.Timestamp) { + expected := pdata.NewMetric() + expected.SetName("system.memory.usage") + expected.SetDescription("Bytes of memory in use.") + expected.SetUnit("By") + expected.SetDataType(pdata.MetricDataTypeSum) + internal.AssertDescriptorEqual(t, expected, metric) + if startTime != 0 { + internal.AssertSumMetricStartTimeEquals(t, metric, startTime) + } assert.GreaterOrEqual(t, metric.Sum().DataPoints().Len(), 2) internal.AssertSumMetricHasAttributeValue(t, metric, 0, metadata.Attributes.State, pdata.NewAttributeValueString(metadata.AttributeState.Used)) internal.AssertSumMetricHasAttributeValue(t, metric, 1, metadata.Attributes.State, pdata.NewAttributeValueString(metadata.AttributeState.Free)) diff --git a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/memory_scraper_windows.go b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/memory_scraper_windows.go index 1211c0c5d7c5..1b021e4a900b 100644 --- a/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/memory_scraper_windows.go +++ b/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/memory_scraper_windows.go @@ -24,9 +24,7 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver/internal/scraper/memoryscraper/internal/metadata" ) -const memStatesLen = 2 - -func appendMemoryUsageStateDataPoints(idps pdata.NumberDataPointSlice, now pdata.Timestamp, memInfo *mem.VirtualMemoryStat) { - initializeMemoryUsageDataPoint(idps.AppendEmpty(), now, metadata.AttributeState.Used, int64(memInfo.Used)) - initializeMemoryUsageDataPoint(idps.AppendEmpty(), now, metadata.AttributeState.Free, int64(memInfo.Available)) +func (s *scraper) recordMemoryUsageDataPoints(now pdata.Timestamp, memInfo *mem.VirtualMemoryStat) { + s.mb.RecordSystemMemoryUsageDataPoint(now, int64(memInfo.Used), metadata.AttributeState.Used) + s.mb.RecordSystemMemoryUsageDataPoint(now, int64(memInfo.Available), metadata.AttributeState.Free) }