From 49aa1f12cfaa836254fbeab7237438a64eec6fd4 Mon Sep 17 00:00:00 2001 From: Ruben Ruiz de Gauna Date: Mon, 19 Jun 2023 14:32:38 +0200 Subject: [PATCH] [receiver/hostmetrics] send process.cpu.utilization if enabled --- ...rics-receiver-process-cpu-utilization.yaml | 20 +++++ .../scraper/processscraper/process_scraper.go | 11 ++- .../processscraper/process_scraper_test.go | 82 +++++++++++++++++++ 3 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 .chloggen/fix-hostmetrics-receiver-process-cpu-utilization.yaml diff --git a/.chloggen/fix-hostmetrics-receiver-process-cpu-utilization.yaml b/.chloggen/fix-hostmetrics-receiver-process-cpu-utilization.yaml new file mode 100644 index 000000000000..93794c60b88a --- /dev/null +++ b/.chloggen/fix-hostmetrics-receiver-process-cpu-utilization.yaml @@ -0,0 +1,20 @@ +# Use this changelog template to create an entry for release notes. +# If your change doesn't affect end users, such as a test fix or a tooling change, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: bug_fix + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: receiver/hostmetricsreceiver + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Fix not sending `process.cpu.utilization` when `process.cpu.time` is disabled. + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [23450] + +# (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: \ No newline at end of file diff --git a/receiver/hostmetricsreceiver/internal/scraper/processscraper/process_scraper.go b/receiver/hostmetricsreceiver/internal/scraper/processscraper/process_scraper.go index 0e8223a973bf..4aee653a155b 100644 --- a/receiver/hostmetricsreceiver/internal/scraper/processscraper/process_scraper.go +++ b/receiver/hostmetricsreceiver/internal/scraper/processscraper/process_scraper.go @@ -237,7 +237,7 @@ func (s *scraper) getProcessMetadata() ([]*processMetadata, error) { } func (s *scraper) scrapeAndAppendCPUTimeMetric(now pcommon.Timestamp, handle processHandle, pid int32) error { - if !s.config.MetricsBuilderConfig.Metrics.ProcessCPUTime.Enabled { + if !s.config.MetricsBuilderConfig.Metrics.ProcessCPUTime.Enabled && !s.config.MetricsBuilderConfig.Metrics.ProcessCPUUtilization.Enabled { return nil } @@ -246,7 +246,14 @@ func (s *scraper) scrapeAndAppendCPUTimeMetric(now pcommon.Timestamp, handle pro return err } - s.recordCPUTimeMetric(now, times) + if s.config.MetricsBuilderConfig.Metrics.ProcessCPUTime.Enabled { + s.recordCPUTimeMetric(now, times) + } + + if !s.config.MetricsBuilderConfig.Metrics.ProcessCPUUtilization.Enabled { + return nil + } + if _, ok := s.ucals[pid]; !ok { s.ucals[pid] = &ucal.CPUUtilizationCalculator{} } diff --git a/receiver/hostmetricsreceiver/internal/scraper/processscraper/process_scraper_test.go b/receiver/hostmetricsreceiver/internal/scraper/processscraper/process_scraper_test.go index e77eec9bf699..27097fdf689a 100644 --- a/receiver/hostmetricsreceiver/internal/scraper/processscraper/process_scraper_test.go +++ b/receiver/hostmetricsreceiver/internal/scraper/processscraper/process_scraper_test.go @@ -1089,3 +1089,85 @@ func TestScrapeMetrics_DontCheckDisabledMetrics(t *testing.T) { assert.Nil(t, err) }) } + +func TestScrapeMetrics_CpuUtilizationWhenCpuTimesIsDisabled(t *testing.T) { + skipTestOnUnsupportedOS(t) + + testCases := []struct { + name string + processCPUTimes bool + processCPUUtilization bool + expectedMetricCount int + expectedMetricNames []string + }{ + { + name: "process.cpu.time enabled, process.cpu.utilization disabled", + processCPUTimes: true, + processCPUUtilization: false, + expectedMetricCount: 1, + expectedMetricNames: []string{"process.cpu.time"}, + }, + { + name: "process.cpu.time disabled, process.cpu.utilization enabled", + processCPUTimes: false, + processCPUUtilization: true, + expectedMetricCount: 1, + expectedMetricNames: []string{"process.cpu.utilization"}, + }, + { + name: "process.cpu.time enabled, process.cpu.utilization enabled", + processCPUTimes: true, + processCPUUtilization: true, + expectedMetricCount: 2, + expectedMetricNames: []string{"process.cpu.time", "process.cpu.utilization"}, + }, + } + + for i := range testCases { + testCase := testCases[i] + t.Run(testCase.name, func(t *testing.T) { + metricsBuilderConfig := metadata.DefaultMetricsBuilderConfig() + + metricsBuilderConfig.Metrics.ProcessCPUTime.Enabled = testCase.processCPUTimes + metricsBuilderConfig.Metrics.ProcessCPUUtilization.Enabled = testCase.processCPUUtilization + + // disable some default metrics for easy assertion + metricsBuilderConfig.Metrics.ProcessMemoryUsage.Enabled = false + metricsBuilderConfig.Metrics.ProcessMemoryVirtual.Enabled = false + metricsBuilderConfig.Metrics.ProcessDiskIo.Enabled = false + + config := &Config{MetricsBuilderConfig: metricsBuilderConfig} + + scraper, err := newProcessScraper(receivertest.NewNopCreateSettings(), config) + require.NoError(t, err, "Failed to create process scraper: %v", err) + err = scraper.start(context.Background(), componenttest.NewNopHost()) + require.NoError(t, err, "Failed to initialize process scraper: %v", err) + + handleMock := newDefaultHandleMock() + handleMock.On("Name").Return("test", nil) + handleMock.On("Exe").Return("test", nil) + handleMock.On("CreateTime").Return(time.Now().UnixMilli(), nil) + + scraper.getProcessHandles = func() (processHandles, error) { + return &processHandlesMock{handles: []*processHandleMock{handleMock}}, nil + } + + // scrape the first time + _, err = scraper.scrape(context.Background()) + assert.Nil(t, err) + + // scrape second time to get utilization + md, err := scraper.scrape(context.Background()) + assert.Nil(t, err) + + for k := 0; k < md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().Len(); k++ { + fmt.Println(md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(k).Name()) + } + assert.Equal(t, testCase.expectedMetricCount, md.MetricCount()) + for metricIdx, expectedMetricName := range testCase.expectedMetricNames { + assert.Equal(t, expectedMetricName, md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(metricIdx).Name()) + } + }) + } + +}