@@ -45,6 +45,7 @@ const (
45
45
ATTR_Q_DEPTH = "depth"
46
46
ATTR_Q_SINCE_PUT = "time_since_put"
47
47
ATTR_Q_SINCE_GET = "time_since_get"
48
+ ATTR_Q_MAX_DEPTH = "attribute_max_depth"
48
49
)
49
50
50
51
var QueueStatus StatusSet
@@ -79,12 +80,21 @@ func QueueInitAttributes() {
79
80
QueueStatus .Attributes [attr ] = newStatusAttribute (attr , "Input Handles" , ibmmq .MQIA_OPEN_INPUT_COUNT )
80
81
attr = ATTR_Q_OPPROCS
81
82
QueueStatus .Attributes [attr ] = newStatusAttribute (attr , "Input Handles" , ibmmq .MQIA_OPEN_OUTPUT_COUNT )
83
+
82
84
// Usually we get the QDepth from published resources, But on z/OS we can get it from the QSTATUS response
83
- if platform == ibmmq . MQPL_ZOS {
85
+ if ! usePublications {
84
86
attr = ATTR_Q_DEPTH
85
87
QueueStatus .Attributes [attr ] = newStatusAttribute (attr , "Queue Depth" , ibmmq .MQIA_CURRENT_Q_DEPTH )
86
88
}
87
89
90
+ // This is not really a momitoring metric but it enables calculations to be made such as %full for
91
+ // the queue. It's extracted at startup of the program via INQUIRE_Q and not updated later even if the
92
+ // queue definition is changed. It's not easy to generate the % value in this program as the CurDepth will
93
+ // usually - but not always - come from the published resource stats. So we don't have direct access to it.
94
+ // Recording the MaxDepth allows Prometheus etc to do the calculation regardless of how the CurDepth was obtained.
95
+ attr = ATTR_Q_MAX_DEPTH
96
+ QueueStatus .Attributes [attr ] = newStatusAttribute (attr , "Queue Max Depth" , - 1 )
97
+
88
98
attr = ATTR_Q_QTIME_SHORT
89
99
QueueStatus .Attributes [attr ] = newStatusAttribute (attr , "Queue Time Short" , ibmmq .MQIACF_Q_TIME_INDICATOR )
90
100
QueueStatus .Attributes [attr ].index = 0
@@ -178,6 +188,66 @@ func collectQueueStatus(pattern string, instanceType int32) error {
178
188
return err
179
189
}
180
190
191
+ // Issue the INQUIRE_Q call for wildcarded queue names and
192
+ // extract the required attributes - currently, just the
193
+ // Maximum Queue Depth
194
+ func inquireQueueAttributes (objectPatternsList string ) error {
195
+ var err error
196
+
197
+ statusClearReplyQ ()
198
+
199
+ if objectPatternsList == "" {
200
+ return err
201
+ }
202
+
203
+ objectPatterns := strings .Split (strings .TrimSpace (objectPatternsList ), "," )
204
+ for i := 0 ; i < len (objectPatterns ) && err == nil ; i ++ {
205
+ var buf []byte
206
+ pattern := strings .TrimSpace (objectPatterns [i ])
207
+ if len (pattern ) == 0 {
208
+ continue
209
+ }
210
+
211
+ putmqmd , pmo , cfh , buf := statusSetCommandHeaders ()
212
+
213
+ // Can allow all the other fields to default
214
+ cfh .Command = ibmmq .MQCMD_INQUIRE_Q
215
+
216
+ // Add the parameters one at a time into a buffer
217
+ pcfparm := new (ibmmq.PCFParameter )
218
+ pcfparm .Type = ibmmq .MQCFT_STRING
219
+ pcfparm .Parameter = ibmmq .MQCA_Q_NAME
220
+ pcfparm .String = []string {pattern }
221
+ cfh .ParameterCount ++
222
+ buf = append (buf , pcfparm .Bytes ()... )
223
+
224
+ pcfparm = new (ibmmq.PCFParameter )
225
+ pcfparm .Type = ibmmq .MQCFT_INTEGER_LIST
226
+ pcfparm .Parameter = ibmmq .MQIACF_Q_ATTRS
227
+ pcfparm .Int64Value = []int64 {int64 (ibmmq .MQIA_MAX_Q_DEPTH )}
228
+ cfh .ParameterCount ++
229
+ buf = append (buf , pcfparm .Bytes ()... )
230
+
231
+ // Once we know the total number of parameters, put the
232
+ // CFH header on the front of the buffer.
233
+ buf = append (cfh .Bytes (), buf ... )
234
+
235
+ // And now put the command to the queue
236
+ err = cmdQObj .Put (putmqmd , pmo , buf )
237
+ if err != nil {
238
+ return err
239
+ }
240
+
241
+ for allReceived := false ; ! allReceived ; {
242
+ cfh , buf , allReceived , err = statusGetReply ()
243
+ if buf != nil {
244
+ parseQAttrData (cfh , buf )
245
+ }
246
+ }
247
+ }
248
+ return nil
249
+ }
250
+
181
251
// Given a PCF response message, parse it to extract the desired statistics
182
252
func parseQData (instanceType int32 , cfh * ibmmq.MQCFH , buf []byte ) string {
183
253
var elem * ibmmq.PCFParameter
@@ -248,9 +318,68 @@ func parseQData(instanceType int32, cfh *ibmmq.MQCFH, buf []byte) string {
248
318
QueueStatus .Attributes [ATTR_Q_SINCE_PUT ].Values [key ] = newStatusValueInt64 (statusTimeDiff (now , lastPutDate , lastPutTime ))
249
319
QueueStatus .Attributes [ATTR_Q_SINCE_GET ].Values [key ] = newStatusValueInt64 (statusTimeDiff (now , lastGetDate , lastGetTime ))
250
320
321
+ if s , ok := qInfoMap [key ]; ok {
322
+ maxDepth := s .MaxDepth
323
+ QueueStatus .Attributes [ATTR_Q_MAX_DEPTH ].Values [key ] = newStatusValueInt64 (maxDepth )
324
+ }
251
325
return key
252
326
}
253
327
328
+ func parseQAttrData (cfh * ibmmq.MQCFH , buf []byte ) {
329
+ var elem * ibmmq.PCFParameter
330
+
331
+ qName := ""
332
+
333
+ parmAvail := true
334
+ bytesRead := 0
335
+ offset := 0
336
+ datalen := len (buf )
337
+ if cfh .ParameterCount == 0 {
338
+ return
339
+ }
340
+
341
+ // Parse it once to extract the fields that are needed for the map key
342
+ for parmAvail && cfh .CompCode != ibmmq .MQCC_FAILED {
343
+ elem , bytesRead = ibmmq .ReadPCFParameter (buf [offset :])
344
+ offset += bytesRead
345
+ // Have we now reached the end of the message
346
+ if offset >= datalen {
347
+ parmAvail = false
348
+ }
349
+
350
+ // Only one field needed for queues
351
+ switch elem .Parameter {
352
+ case ibmmq .MQCA_Q_NAME :
353
+ qName = strings .TrimSpace (elem .String [0 ])
354
+ }
355
+ }
356
+
357
+ // And then re-parse the message so we can store the metrics now knowing the map key
358
+ parmAvail = true
359
+ offset = 0
360
+ for parmAvail && cfh .CompCode != ibmmq .MQCC_FAILED {
361
+ elem , bytesRead = ibmmq .ReadPCFParameter (buf [offset :])
362
+ offset += bytesRead
363
+ // Have we now reached the end of the message
364
+ if offset >= datalen {
365
+ parmAvail = false
366
+ }
367
+
368
+ switch elem .Parameter {
369
+ case ibmmq .MQIA_MAX_Q_DEPTH :
370
+ v := elem .Int64Value [0 ]
371
+ if v > 0 {
372
+ if qInfo , ok := qInfoMap [qName ]; ok {
373
+ qInfo .MaxDepth = v
374
+ }
375
+ }
376
+ }
377
+
378
+ }
379
+
380
+ return
381
+ }
382
+
254
383
// Return a standardised value.
255
384
func QueueNormalise (attr * StatusAttribute , v int64 ) float64 {
256
385
return statusNormalise (attr , v )
0 commit comments