Skip to content

Commit e090084

Browse files
Add error check to groupToEvents so we don't blindly add error values (#39404) (#39504)
* add error check to perfmon groupToEvents * linter... * tests * add changelog * fix changelog * make linter happy (cherry picked from commit 760208b) Co-authored-by: Alex K <[email protected]> Co-authored-by: fearful-symmetry <[email protected]>
1 parent 5e6903b commit e090084

File tree

3 files changed

+72
-5
lines changed

3 files changed

+72
-5
lines changed

CHANGELOG.next.asciidoc

+1
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff]
174174

175175
*Winlogbeat*
176176

177+
- Fix error handling in perfmon metrics. {issue}38140[38140] {pull}39404[39404]
177178

178179
*Elastic Logging Plugin*
179180

metricbeat/module/windows/perfmon/data.go

+10-5
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package perfmon
2121

2222
import (
23+
"errors"
2324
"fmt"
2425
"regexp"
2526
"strconv"
@@ -48,7 +49,7 @@ func (re *Reader) groupToEvents(counters map[string][]pdh.CounterValue) []mb.Eve
4849
// The counter has a negative value or the counter was successfully found, but the data returned is not valid.
4950
// This error can occur if the counter value is less than the previous value. (Because counter values always increment, the counter value rolls over to zero when it reaches its maximum value.)
5051
// This is not an error that stops the application from running successfully and a positive counter value should be retrieved in the later calls.
51-
if val.Err.Error == pdh.PDH_CALC_NEGATIVE_VALUE || val.Err.Error == pdh.PDH_INVALID_DATA {
52+
if errors.Is(val.Err.Error, pdh.PDH_CALC_NEGATIVE_VALUE) || errors.Is(val.Err.Error, pdh.PDH_INVALID_DATA) {
5253
re.log.Debugw("Counter value retrieval returned",
5354
"error", val.Err.Error, "cstatus", pdh.PdhErrno(val.Err.CStatus), logp.Namespace("perfmon"), "query", counterPath)
5455
continue
@@ -69,7 +70,9 @@ func (re *Reader) groupToEvents(counters map[string][]pdh.CounterValue) []mb.Eve
6970
if _, ok := eventMap[eventKey]; !ok {
7071
eventMap[eventKey] = &mb.Event{
7172
MetricSetFields: mapstr.M{},
72-
Error: fmt.Errorf("failed on query=%v: %w", counterPath, val.Err.Error),
73+
}
74+
if val.Err.Error != nil {
75+
eventMap[eventKey].Error = fmt.Errorf("failed on query=%v: %w", counterPath, val.Err.Error)
7376
}
7477
if val.Instance != "" {
7578
// will ignore instance index
@@ -93,9 +96,11 @@ func (re *Reader) groupToEvents(counters map[string][]pdh.CounterValue) []mb.Eve
9396
}
9497
}
9598
// Write the values into the map.
96-
var events []mb.Event
99+
events := make([]mb.Event, len(eventMap))
100+
iter := 0
97101
for _, val := range eventMap {
98-
events = append(events, *val)
102+
events[iter] = *val
103+
iter++
99104
}
100105
return events
101106
}
@@ -111,7 +116,7 @@ func (re *Reader) groupToSingleEvent(counters map[string][]pdh.CounterValue) mb.
111116
// Some counters, such as rate counters, require two counter values in order to compute a displayable value. In this case we must call PdhCollectQueryData twice before calling PdhGetFormattedCounterValue.
112117
// For more information, see Collecting Performance Data (https://docs.microsoft.com/en-us/windows/desktop/PerfCtrs/collecting-performance-data).
113118
if val.Err.Error != nil {
114-
if val.Err.Error == pdh.PDH_CALC_NEGATIVE_VALUE || val.Err.Error == pdh.PDH_INVALID_DATA {
119+
if errors.Is(val.Err.Error, pdh.PDH_CALC_NEGATIVE_VALUE) || errors.Is(val.Err.Error, pdh.PDH_INVALID_DATA) {
115120
re.log.Debugw("Counter value retrieval returned",
116121
"error", val.Err.Error, "cstatus", pdh.PdhErrno(val.Err.CStatus), logp.Namespace("perfmon"), "query", counterPath)
117122
continue

metricbeat/module/windows/perfmon/data_test.go

+61
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,67 @@ import (
2828
"github.com/elastic/elastic-agent-libs/mapstr"
2929
)
3030

31+
func TestGroupErrors(t *testing.T) {
32+
reader := Reader{
33+
config: Config{
34+
GroupMeasurements: true,
35+
},
36+
query: pdh.Query{},
37+
log: nil,
38+
counters: []PerfCounter{
39+
{
40+
QueryField: "datagrams_sent_per_sec",
41+
QueryName: `\UDPv4\Datagrams Sent/sec`,
42+
Format: "float",
43+
ObjectName: "UDPv4",
44+
ObjectField: "object",
45+
ChildQueries: []string{`\UDPv4\Datagrams Sent/sec`},
46+
},
47+
{
48+
QueryField: "%_processor_time",
49+
QueryName: `\Processor Information(_Total)\% Processor Time`,
50+
Format: "float",
51+
ObjectName: "Processor Information",
52+
ObjectField: "object",
53+
InstanceName: "_Total",
54+
InstanceField: "instance",
55+
ChildQueries: []string{`\Processor Information(_Total)\% Processor Time`},
56+
},
57+
{
58+
QueryField: "current_disk_queue_length",
59+
QueryName: `\PhysicalDisk(_Total)\Current Disk Queue Length`,
60+
Format: "float",
61+
ObjectName: "PhysicalDisk",
62+
ObjectField: "object",
63+
InstanceName: "_Total",
64+
InstanceField: "instance",
65+
ChildQueries: []string{`\PhysicalDisk(_Total)\Current Disk Queue Length`},
66+
},
67+
},
68+
}
69+
70+
counters := map[string][]pdh.CounterValue{
71+
`\UDPv4\Datagrams Sent/sec`: {
72+
{Instance: "", Measurement: 23},
73+
},
74+
`\Processor Information(_Total)\% Processor Time`: {
75+
{Instance: "_Total", Measurement: 11},
76+
},
77+
`\PhysicalDisk(_Total)\Current Disk Queue Length`: {
78+
{Instance: "_Total", Measurement: 20},
79+
},
80+
}
81+
82+
events := reader.groupToEvents(counters)
83+
assert.NotNil(t, events)
84+
assert.Equal(t, 3, len(events))
85+
86+
for _, event := range events {
87+
assert.NoError(t, event.Error)
88+
}
89+
90+
}
91+
3192
func TestGroupToEvents(t *testing.T) {
3293
reader := Reader{
3394
config: Config{

0 commit comments

Comments
 (0)