Skip to content

Commit bb96a89

Browse files
Israel Blancasmx-psi
Israel Blancas
andauthored
[hostmetricsreceiver] Set receiver.hostmetrics.normalizeProcessCPUUtilization feature gate as stable (#34764)
**Description:** receiver.hostmetrics.normalizeProcessCPUUtilization feature gate **Link to tracking Issue:** #34763 --------- Signed-off-by: Israel Blancas <[email protected]> Signed-off-by: Israel Blancas <[email protected]> Co-authored-by: Pablo Baeyens <[email protected]>
1 parent 715f1dd commit bb96a89

File tree

4 files changed

+56
-81
lines changed

4 files changed

+56
-81
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: deprecation
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: hostmetricsreceiver
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Set the receiver.hostmetrics.normalizeProcessCPUUtilization feature gate to stable.
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [34763]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: []

receiver/hostmetricsreceiver/README.md

-16
Original file line numberDiff line numberDiff line change
@@ -201,19 +201,3 @@ export OTEL_RESOURCE_ATTRIBUTES="service.name=<the name of your service>,service
201201
## Entity Events
202202
203203
**Entity Events as logs are experimental** and might eventually be replaced by the result of [the OTEP](https://github.com/open-telemetry/oteps/blob/main/text/entities/0256-entities-data-model.md#entity-events). For now, the hostmetrics receiver can send the host entity event as a log records. By default, the hostmetrics receiver sends periodic EntityState events every 5 minutes. You can change that by setting `metadata_collection_interval`. Entity Events as logs are experimental. The result of the OTEP might eventually replace that.
204-
205-
## Feature Gates
206-
207-
See the [Collector feature gates](https://github.com/open-telemetry/opentelemetry-collector/blob/main/featuregate/README.md#collector-feature-gates) for an overview of feature gates in the collector.
208-
209-
### `receiver.hostmetrics.normalizeProcessCPUUtilization`
210-
211-
When enabled, normalizes the `process.cpu.utilization` metric onto the interval [0-1] by dividing the value by the number of logical processors. With this feature gate disabled, the value of the `process.cpu.utilization` metric may exceed 1.
212-
213-
For example, if you have 4 logical cores on your system, and a process is occupying 2 logical cores for an entire scrape interval, with this feature gate disabled a `process.cpu.utilization` metric will be emitted with a value of 2. if this feature gate is enabled in the same scenario, the value of the emitted metric will be 0.5.
214-
215-
The schedule for this feature gate is:
216-
- Introduced in v0.97.0 (March 2024) as `alpha` - disabled by default.
217-
- Moved to `beta` in v0.100.0 (May 2024) - enabled by default.
218-
- Moved to `stable` in v0.102.0 (June 2024) - cannot be disabled.
219-
- Removed three releases after `stable`.

receiver/hostmetricsreceiver/internal/scraper/processscraper/ucal/cpu_utilization_calculator.go

+18-13
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,24 @@
44
package ucal // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver/internal/scraper/processscraper/ucal"
55

66
import (
7+
"fmt"
78
"time"
89

910
"github.com/shirou/gopsutil/v4/cpu"
1011
"go.opentelemetry.io/collector/featuregate"
1112
"go.opentelemetry.io/collector/pdata/pcommon"
1213
)
1314

14-
var normalizeProcessCPUUtilizationFeatureGate = featuregate.GlobalRegistry().MustRegister(
15-
"receiver.hostmetrics.normalizeProcessCPUUtilization",
16-
featuregate.StageBeta,
17-
featuregate.WithRegisterDescription("When enabled, normalizes the process.cpu.utilization metric onto the interval [0-1] by dividing the value by the number of logical processors."),
18-
featuregate.WithRegisterFromVersion("v0.97.0"),
19-
featuregate.WithRegisterReferenceURL("https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/31368"),
20-
)
15+
func init() {
16+
_ = featuregate.GlobalRegistry().MustRegister(
17+
"receiver.hostmetrics.normalizeProcessCPUUtilization",
18+
featuregate.StageStable,
19+
featuregate.WithRegisterDescription("When enabled, normalizes the process.cpu.utilization metric onto the interval [0-1] by dividing the value by the number of logical processors."),
20+
featuregate.WithRegisterFromVersion("v0.97.0"),
21+
featuregate.WithRegisterToVersion("v0.112.0"),
22+
featuregate.WithRegisterReferenceURL("https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/31368"),
23+
)
24+
}
2125

2226
// CPUUtilization stores the utilization percents [0-1] for the different cpu states
2327
type CPUUtilization struct {
@@ -37,6 +41,10 @@ type CPUUtilizationCalculator struct {
3741
// stored []cpu.TimesStat and time.Time and current []cpu.TimesStat and current time.Time
3842
// If no previous data is stored it will return empty slice of CPUUtilization and no error
3943
func (c *CPUUtilizationCalculator) CalculateAndRecord(now pcommon.Timestamp, logicalCores int, currentCPUStats *cpu.TimesStat, recorder func(pcommon.Timestamp, CPUUtilization)) error {
44+
if logicalCores < 1 {
45+
return fmt.Errorf("number of logical cores is %d", logicalCores)
46+
}
47+
4048
if c.previousCPUStats != nil {
4149
recorder(now, cpuUtilization(logicalCores, c.previousCPUStats, c.previousReadTime, currentCPUStats, now))
4250
}
@@ -57,12 +65,9 @@ func cpuUtilization(logicalCores int, startStats *cpu.TimesStat, startTime pcomm
5765
systemUtilization := (endStats.System - startStats.System) / elapsedTime
5866
ioWaitUtilization := (endStats.Iowait - startStats.Iowait) / elapsedTime
5967

60-
if normalizeProcessCPUUtilizationFeatureGate.IsEnabled() && logicalCores > 0 {
61-
// Normalize onto the [0-1] interval by dividing by the number of logical cores
62-
userUtilization /= float64(logicalCores)
63-
systemUtilization /= float64(logicalCores)
64-
ioWaitUtilization /= float64(logicalCores)
65-
}
68+
userUtilization /= float64(logicalCores)
69+
systemUtilization /= float64(logicalCores)
70+
ioWaitUtilization /= float64(logicalCores)
6671

6772
return CPUUtilization{
6873
User: userUtilization,

receiver/hostmetricsreceiver/internal/scraper/processscraper/ucal/cpu_utilization_calculator_test.go

+11-52
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import (
99

1010
"github.com/shirou/gopsutil/v4/cpu"
1111
"github.com/stretchr/testify/assert"
12-
"github.com/stretchr/testify/require"
13-
"go.opentelemetry.io/collector/featuregate"
1412
"go.opentelemetry.io/collector/pdata/pcommon"
1513
)
1614

@@ -32,7 +30,7 @@ func TestCpuUtilizationCalculator_Calculate(t *testing.T) {
3230
previousReadTime pcommon.Timestamp
3331
previousCPUStat *cpu.TimesStat
3432
expectedUtilization *CPUUtilization
35-
normalize bool
33+
shouldError bool
3634
}{
3735
{
3836
name: "no previous times",
@@ -96,28 +94,6 @@ func TestCpuUtilizationCalculator_Calculate(t *testing.T) {
9694
System: 0.15,
9795
Iowait: 0.0005,
9896
},
99-
normalize: true,
100-
},
101-
{
102-
name: "one second time delta, 2 logical cores, not normalized",
103-
logicalCores: 2,
104-
previousReadTime: 1640097430772858000,
105-
currentReadTime: 1640097431772858000,
106-
previousCPUStat: &cpu.TimesStat{
107-
User: 8258.4,
108-
System: 6193.3,
109-
Iowait: 34.201,
110-
},
111-
currentCPUStat: &cpu.TimesStat{
112-
User: 8258.5,
113-
System: 6193.6,
114-
Iowait: 34.202,
115-
},
116-
expectedUtilization: &CPUUtilization{
117-
User: 0.1,
118-
System: 0.3,
119-
Iowait: 0.001,
120-
},
12197
},
12298
{
12399
name: "0 logical cores",
@@ -134,27 +110,27 @@ func TestCpuUtilizationCalculator_Calculate(t *testing.T) {
134110
System: 6193.6,
135111
Iowait: 34.202,
136112
},
137-
expectedUtilization: &CPUUtilization{
138-
User: 0.1,
139-
System: 0.3,
140-
Iowait: 0.001,
141-
},
113+
shouldError: true,
142114
},
143115
}
144116
for _, test := range testCases {
145117
test := test
146118
t.Run(test.name, func(t *testing.T) {
147-
setNormalizeProcessCPUUtilizationFeatureGate(t, test.normalize)
148119
recorder := inMemoryRecorder{}
149120
calculator := CPUUtilizationCalculator{
150121
previousReadTime: test.previousReadTime,
151122
previousCPUStats: test.previousCPUStat,
152123
}
153124
err := calculator.CalculateAndRecord(test.currentReadTime, test.logicalCores, test.currentCPUStat, recorder.record)
154-
assert.NoError(t, err)
155-
assert.InDelta(t, test.expectedUtilization.System, recorder.cpuUtilization.System, 0.00001)
156-
assert.InDelta(t, test.expectedUtilization.User, recorder.cpuUtilization.User, 0.00001)
157-
assert.InDelta(t, test.expectedUtilization.Iowait, recorder.cpuUtilization.Iowait, 0.00001)
125+
if test.shouldError {
126+
assert.Error(t, err)
127+
} else {
128+
assert.NoError(t, err)
129+
assert.InDelta(t, test.expectedUtilization.System, recorder.cpuUtilization.System, 0.00001)
130+
assert.InDelta(t, test.expectedUtilization.User, recorder.cpuUtilization.User, 0.00001)
131+
assert.InDelta(t, test.expectedUtilization.Iowait, recorder.cpuUtilization.Iowait, 0.00001)
132+
}
133+
158134
})
159135
}
160136
}
@@ -185,20 +161,3 @@ func Test_cpuUtilization(t *testing.T) {
185161
assert.InDelta(t, expectedUtilization.Iowait, actualUtilization.Iowait, 0.00001)
186162

187163
}
188-
189-
func setNormalizeProcessCPUUtilizationFeatureGate(t *testing.T, val bool) {
190-
wasEnabled := normalizeProcessCPUUtilizationFeatureGate.IsEnabled()
191-
err := featuregate.GlobalRegistry().Set(
192-
normalizeProcessCPUUtilizationFeatureGate.ID(),
193-
val,
194-
)
195-
require.NoError(t, err)
196-
197-
t.Cleanup(func() {
198-
err := featuregate.GlobalRegistry().Set(
199-
normalizeProcessCPUUtilizationFeatureGate.ID(),
200-
wasEnabled,
201-
)
202-
require.NoError(t, err)
203-
})
204-
}

0 commit comments

Comments
 (0)