Skip to content

Commit 88697dc

Browse files
authored
[pkg/winperfcounters] Add support to retrieve raw values (#39835)
Adding public methods that allow to retrieve the raw values of Windows performance counters. This is needed to allow removal of the vendored code under `receiver/hostmetricsreceiver/internal/perfcounters/` used only by that component. This vendored code retrieves raw values of counters instead of calculated ones, e.g.: it doesn't retrieve rate, but the actual values used to calculate the rate of a counter. See #38858 (comment) for details.
1 parent 54eb1c1 commit 88697dc

File tree

11 files changed

+365
-35
lines changed

11 files changed

+365
-35
lines changed
Lines changed: 27 additions & 0 deletions
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: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: pkg/winperfcounters
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Add methods to scrape raw values from Windows performance counters.
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: [39835]
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: [api]

pkg/winperfcounters/internal/third_party/telegraf/win_perf_counters/pdh.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ var (
180180
pdh_ValidatePathW *syscall.Proc
181181
pdh_ExpandWildCardPathW *syscall.Proc
182182
pdh_GetCounterInfoW *syscall.Proc
183+
pdh_GetRawCounterValue *syscall.Proc
184+
pdh_GetRawCounterArrayW *syscall.Proc
183185
)
184186

185187
func init() {
@@ -198,6 +200,8 @@ func init() {
198200
pdh_ValidatePathW = libpdhDll.MustFindProc("PdhValidatePathW")
199201
pdh_ExpandWildCardPathW = libpdhDll.MustFindProc("PdhExpandWildCardPathW")
200202
pdh_GetCounterInfoW = libpdhDll.MustFindProc("PdhGetCounterInfoW")
203+
pdh_GetRawCounterValue = libpdhDll.MustFindProc("PdhGetRawCounterValue")
204+
pdh_GetRawCounterArrayW = libpdhDll.MustFindProc("PdhGetRawCounterArrayW")
201205
}
202206

203207
// PdhAddCounter adds the specified counter to the query. This is the internationalized version. Preferably, use the
@@ -498,3 +502,45 @@ func PdhGetCounterInfo(hCounter PDH_HCOUNTER, bRetrieveExplainText int, pdwBuffe
498502

499503
return uint32(ret)
500504
}
505+
506+
// PdhGetRawCounterValue retrieves the current raw value of the specified counter.
507+
// hCounter [in]
508+
// Handle of the counter from which you want to retrieve the raw value. The PdhAddCounter function returns this handle.
509+
//
510+
// lpdwType [out]
511+
// Pointer to a variable that receives the counter type. For a list of counter types, see the Counter Types section of the Windows Server documentation.
512+
//
513+
// pValue [out]
514+
// Pointer to a PDH_RAW_COUNTER structure that receives the raw counter value.
515+
func PdhGetRawCounterValue(hCounter PDH_HCOUNTER, lpdwType *uint32, pValue *PDH_RAW_COUNTER) uint32 {
516+
ret, _, _ := pdh_GetRawCounterValue.Call(
517+
uintptr(hCounter),
518+
uintptr(unsafe.Pointer(lpdwType)),
519+
uintptr(unsafe.Pointer(pValue)),
520+
)
521+
522+
return uint32(ret)
523+
}
524+
525+
// PdhGetRawCounterArrayW retrieves an array of raw counter values for all instances of the specified counter.
526+
// hCounter [in]
527+
// Handle of the counter from which you want to retrieve the raw values. The PdhAddCounter function returns this handle.
528+
//
529+
// lpdwBufferSize [in, out]
530+
// Pointer to a variable that specifies the size of the buffer, in bytes. If the buffer is too small, the function sets this variable to the required buffer size.
531+
//
532+
// lpdwBufferCount [out]
533+
// Pointer to a variable that receives the number of elements in the buffer.
534+
//
535+
// itemBuffer [out]
536+
// Pointer to a buffer that receives an array of PDH_RAW_COUNTER_ITEM structures. Each structure contains the raw counter value for an instance.
537+
func PdhGetRawCounterArrayW(hCounter PDH_HCOUNTER, lpdwBufferSize *uint32, lpdwBufferCount *uint32, itemBuffer *byte) uint32 {
538+
ret, _, _ := pdh_GetRawCounterArrayW.Call(
539+
uintptr(hCounter),
540+
uintptr(unsafe.Pointer(lpdwBufferSize)),
541+
uintptr(unsafe.Pointer(lpdwBufferCount)),
542+
uintptr(unsafe.Pointer(itemBuffer)),
543+
)
544+
545+
return uint32(ret)
546+
}

pkg/winperfcounters/internal/third_party/telegraf/win_perf_counters/pdh_386.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,24 @@ type PDH_FMT_COUNTERVALUE_ITEM_LONG struct {
7373
FmtValue PDH_FMT_COUNTERVALUE_LONG
7474
}
7575

76+
// PDH_RAW_COUNTER structure contains the raw data value of a counter.
77+
type PDH_RAW_COUNTER struct {
78+
CStatus uint32 // Counter status that indicates if the counter value is valid.
79+
padding [4]byte
80+
TimeStamp FILETIME // Time at which the sample was taken.
81+
FirstValue int64 // First raw counter value.
82+
SecondValue int64 // Second raw counter value (used for some calculations).
83+
MultiCount uint32 // Counter type-specific value.
84+
padding2 [4]byte
85+
}
86+
87+
// PDH_RAW_COUNTER_ITEM structure contains the raw counter value for a specific instance.
88+
type PDH_RAW_COUNTER_ITEM struct {
89+
SzName *uint16 // Pointer to the instance name.
90+
padding [4]byte
91+
RawValue PDH_RAW_COUNTER // Raw counter value for the instance.
92+
}
93+
7694
// PDH_COUNTER_INFO structure contains information describing the properties of a counter. This information also includes the counter path.
7795
type PDH_COUNTER_INFO struct {
7896
// Size of the structure, including the appended strings, in bytes.

pkg/winperfcounters/internal/third_party/telegraf/win_perf_counters/pdh_amd64.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,21 @@ type PDH_FMT_COUNTERVALUE_ITEM_LONG struct {
6868
FmtValue PDH_FMT_COUNTERVALUE_LONG
6969
}
7070

71+
// PDH_RAW_COUNTER structure contains the raw data value of a counter.
72+
type PDH_RAW_COUNTER struct {
73+
CStatus uint32 // Counter status that indicates if the counter value is valid.
74+
TimeStamp FILETIME // Time at which the sample was taken.
75+
FirstValue int64 // First raw counter value.
76+
SecondValue int64 // Second raw counter value (used for some calculations).
77+
MultiCount uint32 // Counter type-specific value.
78+
}
79+
80+
// PDH_RAW_COUNTER_ITEM structure contains the raw counter value for a specific instance.
81+
type PDH_RAW_COUNTER_ITEM struct {
82+
SzName *uint16 // Pointer to the instance name.
83+
RawValue PDH_RAW_COUNTER // Raw counter value for the instance.
84+
}
85+
7186
// PDH_COUNTER_INFO structure contains information describing the properties of a counter. This information also includes the counter path.
7287
type PDH_COUNTER_INFO struct {
7388
// Size of the structure, including the appended strings, in bytes.

pkg/winperfcounters/internal/third_party/telegraf/win_perf_counters/performance_query.go

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,18 @@ import (
1111
"unsafe"
1212
)
1313

14-
// PerformanceQuery is abstraction for PDH_FMT_COUNTERVALUE_ITEM_DOUBLE
14+
// CounterValue is abstraction for PDH_FMT_COUNTERVALUE_ITEM_DOUBLE
1515
type CounterValue struct {
1616
InstanceName string
1717
Value float64
1818
}
1919

20+
// RawCounterValue is abstraction for PDH_RAW_COUNTER_ITEM
21+
type RawCounterValue struct {
22+
InstanceName string
23+
RawValue int64
24+
}
25+
2026
// PerformanceQuery provides wrappers around Windows performance counters API for easy usage in GO
2127
type PerformanceQuery interface {
2228
Open() error
@@ -26,6 +32,8 @@ type PerformanceQuery interface {
2632
GetCounterPath(counterHandle PDH_HCOUNTER) (string, error)
2733
GetFormattedCounterValueDouble(hCounter PDH_HCOUNTER) (float64, error)
2834
GetFormattedCounterArrayDouble(hCounter PDH_HCOUNTER) ([]CounterValue, error)
35+
GetRawCounterValue(hCounter PDH_HCOUNTER) (int64, error)
36+
GetRawCounterArray(hCounter PDH_HCOUNTER) ([]RawCounterValue, error)
2937
CollectData() error
3038
CollectDataWithTime() (time.Time, error)
3139
IsVistaOrNewer() bool
@@ -163,6 +171,45 @@ func (m *PerformanceQueryImpl) GetFormattedCounterArrayDouble(hCounter PDH_HCOUN
163171
return nil, NewPdhError(ret)
164172
}
165173

174+
func (m *PerformanceQueryImpl) GetRawCounterValue(hCounter PDH_HCOUNTER) (int64, error) {
175+
var counterType uint32
176+
var rawValue PDH_RAW_COUNTER
177+
var ret uint32
178+
179+
if ret = PdhGetRawCounterValue(hCounter, &counterType, &rawValue); ret == ERROR_SUCCESS {
180+
if rawValue.CStatus == PDH_CSTATUS_VALID_DATA {
181+
return rawValue.FirstValue, nil
182+
} else {
183+
return 0, NewPdhError(rawValue.CStatus)
184+
}
185+
} else {
186+
return 0, NewPdhError(ret)
187+
}
188+
}
189+
190+
func (m *PerformanceQueryImpl) GetRawCounterArray(hCounter PDH_HCOUNTER) ([]RawCounterValue, error) {
191+
var buffSize uint32
192+
var itemCount uint32
193+
var ret uint32
194+
195+
if ret = PdhGetRawCounterArrayW(hCounter, &buffSize, &itemCount, nil); ret == PDH_MORE_DATA {
196+
buff := make([]byte, buffSize)
197+
198+
if ret = PdhGetRawCounterArrayW(hCounter, &buffSize, &itemCount, &buff[0]); ret == ERROR_SUCCESS {
199+
items := unsafe.Slice((*PDH_RAW_COUNTER_ITEM)(unsafe.Pointer(&buff[0])), itemCount)
200+
values := make([]RawCounterValue, 0, itemCount)
201+
for _, item := range items {
202+
if item.RawValue.CStatus == PDH_CSTATUS_VALID_DATA {
203+
val := RawCounterValue{UTF16PtrToString(item.SzName), item.RawValue.FirstValue}
204+
values = append(values, val)
205+
}
206+
}
207+
return values, nil
208+
}
209+
}
210+
return nil, NewPdhError(ret)
211+
}
212+
166213
func (m *PerformanceQueryImpl) CollectData() error {
167214
var ret uint32
168215
if m.query == 0 {

0 commit comments

Comments
 (0)