1
- //go:build windows
2
- // +build windows
3
-
4
1
package snclient
5
2
6
3
import (
7
4
"context"
8
- "fmt"
9
- "regexp"
10
- "strconv"
11
- "strings"
12
- "syscall"
13
- "time"
14
- "unsafe"
15
-
16
- "github.com/consol-monitoring/snclient/pkg/pdh"
17
5
)
18
6
19
7
func init () {
@@ -41,17 +29,17 @@ func (c *CheckPDH) Build() *CheckData {
41
29
name : "check_pdh" ,
42
30
description : "Checks pdh paths Handles WildCard Expansion" ,
43
31
detailSyntax : "%(name)" ,
44
- okSyntax : "%(status) - All %(count) Counter Values are ok" ,
45
- topSyntax : "%(status) - %(problem_count)/%(count) Counter (%(count)) %(problem_list)" ,
46
- emptySyntax : "No Counter Found " ,
32
+ okSyntax : "%(status) - All %(count) counter values are ok" ,
33
+ topSyntax : "%(status) - %(problem_count)/%(count) counter (%(count)) %(problem_list)" ,
34
+ emptySyntax : "%(status) - No counter found " ,
47
35
emptyState : CheckExitUnknown ,
48
36
args : map [string ]CheckArgument {
49
- "counter" : {value : & c .CounterPath , description : "The fully qualified Counter Name " },
50
- "host" : {value : & c .HostName , description : "The Name Of the Host Mashine in Network where the Counter should be searched, defults to local mashine " },
51
- "expand-index" : {value : & c .ExpandIndex , description : "Should Indices be translated?" },
52
- "instances" : {value : & c .Instances , description : "Expand WildCards And Fethch all instances" },
53
- "type" : {value : & c .Type , description : "this can be large or float depending what you expect, default is large " },
54
- "english" : {value : & c .EnglishFallBackNames , description : "Using English Names Regardless of system Language requires Windows Vista or higher" },
37
+ "counter" : {value : & c .CounterPath , description : "The fully qualified counter name " },
38
+ "host" : {value : & c .HostName , description : "The name of the host machine in network where the counter should be searched, defaults to local machine " },
39
+ "expand-index" : {value : & c .ExpandIndex , description : "Should indices be translated?" },
40
+ "instances" : {value : & c .Instances , description : "Expand wildcards and fetch all instances" },
41
+ "type" : {value : & c .Type , description : "This can be large or float depending what you expect, default is large" },
42
+ "english" : {value : & c .EnglishFallBackNames , description : "Using English names regardless of system language. Requires Windows Vista or higher" },
55
43
},
56
44
result : & CheckResult {
57
45
State : CheckExitOK ,
@@ -70,168 +58,6 @@ func (c *CheckPDH) Build() *CheckData {
70
58
}
71
59
72
60
// Check implements CheckHandler.
73
- func (c * CheckPDH ) Check (_ context.Context , _ * Agent , check * CheckData , _ []Argument ) (* CheckResult , error ) {
74
- var possiblePaths []string
75
- var hQuery pdh.PDH_HQUERY
76
- // Open Query - Data Source = 0 => Real Time Datasource
77
- ret := pdh .PdhOpenQuery (uintptr (0 ), uintptr (0 ), & hQuery )
78
- defer pdh .PdhCloseQuery (hQuery )
79
-
80
- if ret != pdh .ERROR_SUCCESS {
81
- return nil , fmt .Errorf ("could not open query, something is wrong with the countername" )
82
- }
83
-
84
- tmpPath := c .CounterPath
85
- if c .EnglishFallBackNames {
86
- var hCounter pdh.PDH_HCOUNTER
87
- ret = pdh .PdhAddEnglishCounter (hQuery , tmpPath , 0 , & hCounter )
88
- if ret != pdh .ERROR_SUCCESS {
89
- return nil , fmt .Errorf ("cannot use provided counter path as english fallback path, api response: %d" , ret )
90
- }
91
- tpm , err := pdh .PdhGetCounterInfo (hCounter , false )
92
- if err != nil {
93
- return nil , fmt .Errorf ("cannot use provided counter path as english fallback path, error: %s" , err .Error ())
94
- }
95
- tmpPath = tpm
96
- }
97
-
98
- // If HostName is set it needs to be part of the counter path
99
- if c .HostName != "" {
100
- tmpPath = `\\` + c .HostName + `\` + c .CounterPath
101
- }
102
-
103
- // Find Indices and replace with Performance Name
104
- r := regexp .MustCompile (`\\d+` )
105
- matches := r .FindAllString (c .CounterPath , - 1 )
106
- for _ , match := range matches {
107
- index , err := strconv .Atoi (strings .ReplaceAll (match , `\` , "" ))
108
- if err != nil {
109
- return nil , fmt .Errorf ("could not convert index. error was %s" , err .Error ())
110
- }
111
- res , path := pdh .PdhLookupPerfNameByIndex (uint32 (index )) //nolint:gosec // Index is small and needs to be uint32 for system call
112
- if res != pdh .ERROR_SUCCESS {
113
- return nil , fmt .Errorf ("could not find given index: %d response code: %d" , index , res )
114
- }
115
- tmpPath = strings .Replace (tmpPath , match , "\\ " + path , 1 )
116
- }
117
-
118
- // Expand Counter Path That Ends with WildCard *
119
- if c .Instances && strings .HasSuffix (tmpPath , "*" ) {
120
- res , paths := pdh .PdhExpandCounterPath ("" , tmpPath , 0 )
121
- if res != pdh .ERROR_SUCCESS {
122
- return nil , fmt .Errorf ("something went wrong when expanding the counter path api call returned %d" , res )
123
- }
124
- possiblePaths = append (possiblePaths , paths ... )
125
- } else {
126
- possiblePaths = append (possiblePaths , tmpPath )
127
- }
128
-
129
- counters , err := c .addAllPathToCounter (hQuery , possiblePaths )
130
- if err != nil {
131
- return nil , fmt .Errorf ("could not add all counter path to query, error: %s" , err .Error ())
132
- }
133
-
134
- // Collect Values For All Counters and save values in check.listData
135
- err = collectValuesForAllCounters (hQuery , counters , check )
136
- if err != nil {
137
- return nil , fmt .Errorf ("could not get values for all counter path, error: %s" , err .Error ())
138
- }
139
-
140
- return check .Finalize ()
141
- }
142
-
143
- func collectValuesForAllCounters (hQuery pdh.PDH_HQUERY , counters map [string ]pdh.PDH_HCOUNTER , check * CheckData ) error {
144
- for counterPath , hCounter := range counters {
145
- var resArr [1 ]pdh.PDH_FMT_COUNTERVALUE_ITEM_LARGE // Need at least one nil pointer
146
-
147
- largeArr , ret := collectLargeValuesArray (hCounter , hQuery , resArr )
148
- if ret != pdh .ERROR_SUCCESS && ret != pdh .PDH_MORE_DATA && ret != pdh .PDH_NO_MORE_DATA {
149
- return fmt .Errorf ("could not collect formatted value %v" , ret )
150
- }
151
-
152
- entry := map [string ]string {}
153
- for _ , fmtValue := range largeArr {
154
- entry ["name" ] = strings .Replace (counterPath , "*" , utf16PtrToString (fmtValue .SzName ), 1 )
155
- entry ["value" ] = fmt .Sprintf ("%d" , fmtValue .FmtValue .LargeValue )
156
- if check .showAll {
157
- check .result .Metrics = append (check .result .Metrics ,
158
- & CheckMetric {
159
- Name : strings .Replace (counterPath , "*" , utf16PtrToString (fmtValue .SzName ), 1 ),
160
- ThresholdName : "value" ,
161
- Value : fmtValue .FmtValue .LargeValue ,
162
- Warning : check .warnThreshold ,
163
- Critical : check .critThreshold ,
164
- Min : & Zero ,
165
- })
166
- }
167
- if check .MatchMapCondition (check .filter , entry , true ) {
168
- check .listData = append (check .listData , entry )
169
- }
170
- }
171
- }
172
-
173
- return nil
174
- }
175
-
176
- func (c * CheckPDH ) addAllPathToCounter (hQuery pdh.PDH_HQUERY , possiblePaths []string ) (map [string ]pdh.PDH_HCOUNTER , error ) {
177
- counters := map [string ]pdh.PDH_HCOUNTER {}
178
-
179
- for _ , path := range possiblePaths {
180
- var hCounter pdh.PDH_HCOUNTER
181
- ret := pdh .PdhAddCounter (hQuery , path , 0 , & hCounter )
182
- if ret != pdh .ERROR_SUCCESS {
183
- return nil , fmt .Errorf ("could not add one of the possible paths to the query: %s, api response code: %d" , path , ret )
184
- }
185
- counters [path ] = hCounter
186
- }
187
-
188
- return counters , nil
189
- }
190
-
191
- func collectQueryData (hQuery * pdh.PDH_HQUERY ) uint32 {
192
- ret := pdh .PdhCollectQueryData (* hQuery )
193
- if ret != pdh .PDH_MORE_DATA && ret != pdh .ERROR_SUCCESS {
194
- return ret
195
- }
196
- // PDH requires a double collection with a second wait between the calls See MSDN
197
- time .Sleep (time .Duration (1 ))
198
- ret = pdh .PdhCollectQueryData (* hQuery )
199
-
200
- return ret
201
- }
202
-
203
- /*
204
- - Collect Data
205
- - Collect formatted with size = 0 to get actual size
206
- - if More Data -> Create Actual Array and fill
207
- */
208
- func collectLargeValuesArray (hCounter pdh.PDH_HCOUNTER , hQuery pdh.PDH_HQUERY , resArr [1 ]pdh.PDH_FMT_COUNTERVALUE_ITEM_LARGE ) (values []pdh.PDH_FMT_COUNTERVALUE_ITEM_LARGE , apiResponseCode uint32 ) {
209
- var ret uint32
210
- var filledBuf []pdh.PDH_FMT_COUNTERVALUE_ITEM_LARGE
211
- size := uint32 (0 )
212
- bufferCount := uint32 (0 )
213
- if res := collectQueryData (& hQuery ); res != pdh .ERROR_SUCCESS {
214
- return nil , res
215
- }
216
- if ret = pdh .PdhGetFormattedCounterArrayLarge (hCounter , & size , & bufferCount , & resArr [0 ]); ret == pdh .PDH_MORE_DATA {
217
- // create array of size = bufferCount * sizeOf(pdh.PDH_FMT_COUNTERVALUE_ITEM_LARGE)
218
- filledBuf = make ([]pdh.PDH_FMT_COUNTERVALUE_ITEM_LARGE , bufferCount )
219
- ret = pdh .PdhGetFormattedCounterArrayLarge (hCounter , & size , & bufferCount , & filledBuf [0 ])
220
- }
221
-
222
- return filledBuf , ret
223
- }
224
-
225
- func utf16PtrToString (ptr * uint16 ) string {
226
- if ptr == nil {
227
- return ""
228
- }
229
- end := unsafe .Pointer (ptr )
230
- charCounter := 0
231
- for * (* uint16 )(end ) != 0 {
232
- end = unsafe .Pointer (uintptr (end ) + unsafe .Sizeof (* ptr ))
233
- charCounter ++
234
- }
235
-
236
- return syscall .UTF16ToString (unsafe .Slice (ptr , charCounter ))
61
+ func (c * CheckPDH ) Check (ctx context.Context , snc * Agent , check * CheckData , args []Argument ) (* CheckResult , error ) {
62
+ return c .check (ctx , snc , check , args )
237
63
}
0 commit comments