master
go 661 lines 19.9 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 //go:build cgo && ibm_mq
4
5 package pcf
6
7 import (
8 "fmt"
9 "path/filepath"
10 "strconv"
11 "strings"
12
13 "github.com/ibm-messaging/mq-golang/v5/ibmmq"
14 )
15
16 // QueueInfo contains queue information including type
17 type QueueInfo struct {
18 Name string
19 Type int32 // MQQT_LOCAL, MQQT_ALIAS, MQQT_REMOTE, MQQT_MODEL, MQQT_CLUSTER
20
21 // Basic metrics (available from both discovery and individual queries)
22 CurrentDepth int64
23 MaxDepth int64
24
25 // Configuration attributes (extracted from individual queue queries)
26 InhibitGet AttributeValue
27 InhibitPut AttributeValue
28 BackoutThreshold AttributeValue
29 TriggerDepth AttributeValue
30 TriggerType AttributeValue
31 MaxMsgLength AttributeValue
32 DefPriority AttributeValue
33 ServiceInterval AttributeValue
34 RetentionInterval AttributeValue
35 Scope AttributeValue
36 Usage AttributeValue
37 MsgDeliverySequence AttributeValue
38 HardenGetBackout AttributeValue
39 DefPersistence AttributeValue
40 }
41
42 // QueueTypeString converts MQ queue type to string for labels
43 func QueueTypeString(qtype int32) string {
44 name := ibmmq.MQItoStringStripPrefix("QT", int(qtype))
45
46 if name == "" || name == strconv.Itoa(int(qtype)) {
47 return "unknown"
48 }
49
50 // "_LOCAL" -> "local"
51 return strings.ToLower(strings.TrimPrefix(name, "_"))
52 }
53
54 // GetQueueList returns a list of queues with their types.
55 func (c *Client) GetQueueList() ([]QueueInfo, error) {
56 c.protocol.Debugf("Getting queue list from queue manager '%s'", c.config.QueueManager)
57
58 const pattern = "*"
59 params := []pcfParameter{
60 newStringParameter(ibmmq.MQCA_Q_NAME, pattern),
61 }
62
63 c.protocol.Debugf("Queue name parameter - value='%s', length=%d", pattern, len(pattern))
64 response, err := c.sendPCFCommand(ibmmq.MQCMD_INQUIRE_Q, params)
65 if err != nil {
66 c.protocol.Errorf("Failed to get queue list from queue manager '%s': %v", c.config.QueueManager, err)
67 return nil, err
68 }
69
70 // Convert PCFParameter array to QueueListWithTypeResult
71 result := c.parseQueueListResponseWithTypeFromParams(response)
72
73 if result.InternalErrors > 0 {
74 c.protocol.Warningf("Encountered %d internal errors while parsing queue list from queue manager '%s'",
75 result.InternalErrors, c.config.QueueManager)
76 }
77
78 for errCode, count := range result.ErrorCounts {
79 if errCode < 0 {
80 c.protocol.Warningf("Internal error %d occurred %d times while parsing queue list from queue manager '%s'",
81 errCode, count, c.config.QueueManager)
82 } else {
83 c.protocol.Warningf("MQ error %d (%s) occurred %d times while parsing queue list from queue manager '%s'",
84 errCode, mqReasonString(errCode), count, c.config.QueueManager)
85 }
86 }
87
88 c.protocol.Debugf("Retrieved %d queues from queue manager '%s'", len(result.Queues), c.config.QueueManager)
89
90 return result.Queues, nil
91 }
92
93 // GetQueues collects comprehensive queue metrics with full transparency statistics
94 func (c *Client) GetQueues(collectConfig, collectMetrics, collectReset bool, maxQueues int, selector string, collectSystem bool) (*QueueCollectionResult, error) {
95 c.protocol.Debugf("Collecting queue metrics with selector '%s', max=%d, config=%v, metrics=%v, reset=%v, system=%v",
96 selector, maxQueues, collectConfig, collectMetrics, collectReset, collectSystem)
97
98 result := &QueueCollectionResult{
99 Stats: CollectionStats{},
100 }
101
102 // Step 1: Discovery
103 discoveredQueues, err := c.discoverQueues(result)
104 if err != nil {
105 return result, err
106 }
107
108 // Step 2: Filtering
109 queuesToEnrich := c.filterQueues(discoveredQueues, selector, collectSystem, maxQueues, result)
110
111 // Step 3: Enrichment
112 c.enrichQueues(queuesToEnrich, collectConfig, collectMetrics, collectReset, result)
113
114 c.protocol.Debugf("Queue collection complete - discovered:%d visible:%d included:%d enriched:%d",
115 result.Stats.Discovery.AvailableItems,
116 result.Stats.Discovery.AvailableItems-result.Stats.Discovery.InvisibleItems,
117 result.Stats.Discovery.IncludedItems,
118 len(result.Queues))
119
120 return result, nil
121 }
122
123 func (c *Client) discoverQueues(result *QueueCollectionResult) ([]string, error) {
124 // Use MQCMD_INQUIRE_Q_NAMES which requires less authorization than MQCMD_INQUIRE_Q
125 response, err := c.sendPCFCommand(ibmmq.MQCMD_INQUIRE_Q_NAMES, []*ibmmq.PCFParameter{
126 {
127 Type: ibmmq.MQCFT_STRING,
128 Parameter: ibmmq.MQCA_Q_NAME,
129 String: []string{"*"},
130 },
131 {
132 Type: ibmmq.MQCFT_INTEGER,
133 Parameter: ibmmq.MQIA_Q_TYPE,
134 Int64Value: []int64{int64(ibmmq.MQQT_LOCAL)},
135 },
136 })
137 if err != nil {
138 result.Stats.Discovery.Success = false
139 c.protocol.Errorf("Queue discovery failed: %v", err)
140 return nil, fmt.Errorf("queue discovery failed: %w", err)
141 }
142
143 result.Stats.Discovery.Success = true
144
145 // Parse the response from MQCMD_INQUIRE_Q_NAMES
146 var queueNames []string
147 for _, param := range response {
148 // MQCMD_INQUIRE_Q_NAMES returns MQCACF_Q_NAMES (string list)
149 if param.Type == ibmmq.MQCFT_STRING_LIST && param.Parameter == ibmmq.MQCACF_Q_NAMES {
150 for _, qName := range param.String {
151 queueNames = append(queueNames, strings.TrimSpace(qName))
152 }
153 }
154 }
155
156 result.Stats.Discovery.AvailableItems = int64(len(queueNames))
157 result.Stats.Discovery.InvisibleItems = 0
158 result.Stats.Discovery.ErrorCounts = make(map[int32]int)
159
160 if len(queueNames) == 0 {
161 c.protocol.Debugf("No queues discovered")
162 } else {
163 c.protocol.Debugf("Discovered %d queues", len(queueNames))
164 }
165
166 return queueNames, nil
167 }
168
169 func (c *Client) filterQueues(queues []string, selector string, collectSystem bool, maxQueues int, result *QueueCollectionResult) []string {
170 visibleItems := result.Stats.Discovery.AvailableItems - result.Stats.Discovery.InvisibleItems
171 enrichAll := maxQueues <= 0 || visibleItems <= int64(maxQueues)
172
173 c.protocol.Debugf("Discovery found %d visible queues (total: %d, invisible: %d). EnrichAll=%v",
174 visibleItems, result.Stats.Discovery.AvailableItems, result.Stats.Discovery.InvisibleItems, enrichAll)
175
176 var queuesToEnrich []string
177 if enrichAll || selector == "*" {
178 for _, queueName := range queues {
179 if !collectSystem && strings.HasPrefix(queueName, "SYSTEM.") {
180 result.Stats.Discovery.ExcludedItems++
181 continue
182 }
183 queuesToEnrich = append(queuesToEnrich, queueName)
184 result.Stats.Discovery.IncludedItems++
185 }
186 c.protocol.Debugf("Enriching %d queues (excluded %d system queues)",
187 len(queuesToEnrich), result.Stats.Discovery.ExcludedItems)
188 } else {
189 for _, queueName := range queues {
190 if !collectSystem && strings.HasPrefix(queueName, "SYSTEM.") {
191 result.Stats.Discovery.ExcludedItems++
192 continue
193 }
194
195 matched, err := filepath.Match(selector, queueName)
196 if err != nil {
197 c.protocol.Warningf("Invalid selector pattern '%s': %v", selector, err)
198 matched = false
199 }
200
201 if matched {
202 queuesToEnrich = append(queuesToEnrich, queueName)
203 result.Stats.Discovery.IncludedItems++
204 } else {
205 result.Stats.Discovery.ExcludedItems++
206 }
207 }
208 c.protocol.Debugf("Selector '%s' matched %d queues, excluded %d (including system filtering)",
209 selector, result.Stats.Discovery.IncludedItems, result.Stats.Discovery.ExcludedItems)
210 }
211 return queuesToEnrich
212 }
213
214 func (c *Client) enrichQueues(queuesToEnrich []string, collectConfig, collectMetrics, collectReset bool, result *QueueCollectionResult) {
215 for _, queueName := range queuesToEnrich {
216 qm := QueueMetrics{Name: queueName}
217
218 if collectConfig {
219 c.enrichQueueWithConfig(&qm, result)
220 }
221
222 if collectMetrics {
223 c.enrichQueueWithMetrics(&qm, result)
224 }
225
226 if collectReset {
227 c.enrichQueueWithResetStats(&qm, result)
228 }
229
230 result.Queues = append(result.Queues, qm)
231 }
232 }
233
234 func (c *Client) enrichQueueWithConfig(qm *QueueMetrics, result *QueueCollectionResult) {
235 if result.Stats.Config == nil {
236 result.Stats.Config = &EnrichmentStats{
237 TotalItems: int64(len(result.Queues)),
238 ErrorCounts: make(map[int32]int),
239 }
240 }
241
242 configData, err := c.getQueueConfiguration(qm.Name)
243 if err != nil {
244 result.Stats.Config.FailedItems++
245 if pcfErr, ok := err.(*PCFError); ok {
246 result.Stats.Config.ErrorCounts[pcfErr.Code]++
247 } else {
248 result.Stats.Config.ErrorCounts[-1]++
249 }
250 c.protocol.Debugf("Failed to get config for queue '%s': %v", qm.Name, err)
251 return
252 }
253
254 result.Stats.Config.OkItems++
255 qm.Type = QueueType(configData.Type)
256 qm.CurrentDepth = configData.CurrentDepth
257 qm.MaxDepth = configData.MaxDepth
258 qm.InhibitGet = configData.InhibitGet
259 qm.InhibitPut = configData.InhibitPut
260 qm.BackoutThreshold = configData.BackoutThreshold
261 qm.TriggerDepth = configData.TriggerDepth
262 qm.TriggerType = configData.TriggerType
263 qm.MaxMsgLength = configData.MaxMsgLength
264 qm.DefPriority = configData.DefPriority
265 }
266
267 func (c *Client) enrichQueueWithMetrics(qm *QueueMetrics, result *QueueCollectionResult) {
268 if result.Stats.Metrics == nil {
269 result.Stats.Metrics = &EnrichmentStats{
270 TotalItems: int64(len(result.Queues)),
271 ErrorCounts: make(map[int32]int),
272 }
273 }
274
275 err := c.enrichWithStatus(qm)
276 if err != nil {
277 result.Stats.Metrics.FailedItems++
278 if pcfErr, ok := err.(*PCFError); ok {
279 result.Stats.Metrics.ErrorCounts[pcfErr.Code]++
280 } else {
281 result.Stats.Metrics.ErrorCounts[-1]++
282 }
283 c.protocol.Debugf("QUEUE '%s' failed to get metrics: %v", qm.Name, err)
284 } else {
285 result.Stats.Metrics.OkItems++
286 }
287 }
288
289 func (c *Client) enrichQueueWithResetStats(qm *QueueMetrics, result *QueueCollectionResult) {
290 if result.Stats.Reset == nil {
291 result.Stats.Reset = &EnrichmentStats{
292 TotalItems: int64(len(result.Queues)),
293 ErrorCounts: make(map[int32]int),
294 }
295 }
296
297 err := c.enrichWithResetStats(qm)
298 if err != nil {
299 result.Stats.Reset.FailedItems++
300 if pcfErr, ok := err.(*PCFError); ok {
301 result.Stats.Reset.ErrorCounts[pcfErr.Code]++
302 } else {
303 result.Stats.Reset.ErrorCounts[-1]++
304 }
305 c.protocol.Debugf("QUEUE '%s' failed to get reset stats: %v", qm.Name, err)
306 } else {
307 result.Stats.Reset.OkItems++
308 }
309 }
310
311 // getQueueConfiguration gets full configuration data for a specific queue
312 func (c *Client) getQueueConfiguration(queueName string) (*QueueInfo, error) {
313 c.protocol.Debugf("Getting configuration for queue '%s'", queueName)
314
315 params := []pcfParameter{
316 newStringParameter(ibmmq.MQCA_Q_NAME, queueName),
317 }
318
319 response, err := c.sendPCFCommand(ibmmq.MQCMD_INQUIRE_Q, params)
320 if err != nil {
321 return nil, fmt.Errorf("QUEUE '%s' failed to get configuration: %w", queueName, err)
322 }
323
324 attrs, err := c.parsePCFResponseFromParams(response, "")
325 if err != nil {
326 return nil, fmt.Errorf("QUEUE '%s' failed to parse configuration response: %w", queueName, err)
327 }
328
329 queueInfo := &QueueInfo{
330 Name: queueName,
331 }
332
333 if qtype, ok := attrs[ibmmq.MQIA_Q_TYPE]; ok {
334 if qtypeInt, ok := qtype.(int32); ok {
335 queueInfo.Type = qtypeInt
336 }
337 }
338
339 if depth, ok := attrs[ibmmq.MQIA_CURRENT_Q_DEPTH]; ok {
340 if depthInt, ok := depth.(int32); ok {
341 queueInfo.CurrentDepth = int64(depthInt)
342 }
343 }
344 if maxDepth, ok := attrs[ibmmq.MQIA_MAX_Q_DEPTH]; ok {
345 if maxDepthInt, ok := maxDepth.(int32); ok {
346 queueInfo.MaxDepth = int64(maxDepthInt)
347 }
348 }
349
350 queueInfo.InhibitGet = NotCollected
351 queueInfo.InhibitPut = NotCollected
352 queueInfo.BackoutThreshold = NotCollected
353 queueInfo.TriggerDepth = NotCollected
354 queueInfo.TriggerType = NotCollected
355 queueInfo.MaxMsgLength = NotCollected
356 queueInfo.DefPriority = NotCollected
357 queueInfo.ServiceInterval = NotCollected
358 queueInfo.RetentionInterval = NotCollected
359 queueInfo.Scope = NotCollected
360 queueInfo.Usage = NotCollected
361 queueInfo.MsgDeliverySequence = NotCollected
362 queueInfo.HardenGetBackout = NotCollected
363 queueInfo.DefPersistence = NotCollected
364
365 if attr, ok := attrs[ibmmq.MQIA_INHIBIT_GET]; ok {
366 if val, ok := attr.(int32); ok {
367 queueInfo.InhibitGet = AttributeValue(val)
368 }
369 }
370
371 if attr, ok := attrs[ibmmq.MQIA_INHIBIT_PUT]; ok {
372 if val, ok := attr.(int32); ok {
373 queueInfo.InhibitPut = AttributeValue(val)
374 }
375 }
376
377 if attr, ok := attrs[ibmmq.MQIA_BACKOUT_THRESHOLD]; ok {
378 if val, ok := attr.(int32); ok {
379 queueInfo.BackoutThreshold = AttributeValue(val)
380 }
381 }
382
383 if attr, ok := attrs[ibmmq.MQIA_TRIGGER_DEPTH]; ok {
384 if val, ok := attr.(int32); ok {
385 queueInfo.TriggerDepth = AttributeValue(val)
386 }
387 }
388
389 if attr, ok := attrs[ibmmq.MQIA_TRIGGER_TYPE]; ok {
390 if val, ok := attr.(int32); ok {
391 queueInfo.TriggerType = AttributeValue(val)
392 }
393 }
394
395 if attr, ok := attrs[ibmmq.MQIA_MAX_MSG_LENGTH]; ok {
396 if val, ok := attr.(int32); ok {
397 queueInfo.MaxMsgLength = AttributeValue(val)
398 }
399 }
400
401 if attr, ok := attrs[ibmmq.MQIA_DEF_PRIORITY]; ok {
402 if val, ok := attr.(int32); ok {
403 queueInfo.DefPriority = AttributeValue(val)
404 }
405 }
406
407 if attr, ok := attrs[ibmmq.MQIA_Q_SERVICE_INTERVAL]; ok {
408 if val, ok := attr.(int32); ok {
409 queueInfo.ServiceInterval = AttributeValue(val)
410 }
411 }
412
413 if attr, ok := attrs[ibmmq.MQIA_RETENTION_INTERVAL]; ok {
414 if val, ok := attr.(int32); ok {
415 queueInfo.RetentionInterval = AttributeValue(val)
416 }
417 }
418
419 if attr, ok := attrs[ibmmq.MQIA_SCOPE]; ok {
420 if val, ok := attr.(int32); ok {
421 queueInfo.Scope = AttributeValue(val)
422 }
423 }
424
425 if attr, ok := attrs[ibmmq.MQIA_USAGE]; ok {
426 if val, ok := attr.(int32); ok {
427 queueInfo.Usage = AttributeValue(val)
428 }
429 }
430
431 if attr, ok := attrs[ibmmq.MQIA_MSG_DELIVERY_SEQUENCE]; ok {
432 if val, ok := attr.(int32); ok {
433 queueInfo.MsgDeliverySequence = AttributeValue(val)
434 }
435 }
436
437 if attr, ok := attrs[ibmmq.MQIA_HARDEN_GET_BACKOUT]; ok {
438 if val, ok := attr.(int32); ok {
439 queueInfo.HardenGetBackout = AttributeValue(val)
440 }
441 }
442
443 if attr, ok := attrs[ibmmq.MQIA_DEF_PERSISTENCE]; ok {
444 if val, ok := attr.(int32); ok {
445 queueInfo.DefPersistence = AttributeValue(val)
446 }
447 }
448
449 c.protocol.Debugf("Retrieved configuration for queue '%s' (type: %d)",
450 queueName, queueInfo.Type)
451
452 return queueInfo, nil
453 }
454
455 // enrichWithStatus enriches queue metrics with runtime status
456 func (c *Client) enrichWithStatus(metrics *QueueMetrics) error {
457 params := []pcfParameter{
458 newStringParameter(ibmmq.MQCA_Q_NAME, metrics.Name),
459 newIntParameter(ibmmq.MQIA_Q_TYPE, ibmmq.MQQT_ALL),
460 newIntParameter(ibmmq.MQIACF_Q_STATUS_ATTRS, ibmmq.MQIACF_ALL),
461 }
462
463 response, err := c.sendPCFCommand(ibmmq.MQCMD_INQUIRE_Q_STATUS, params)
464 if err != nil {
465 return err
466 }
467
468 attrs, err := c.parsePCFResponseFromParams(response, "")
469 if err != nil {
470 return err
471 }
472
473 if depth, ok := attrs[ibmmq.MQIA_CURRENT_Q_DEPTH]; ok {
474 metrics.CurrentDepth = int64(depth.(int32))
475 }
476 if maxDepth, ok := attrs[ibmmq.MQIA_MAX_Q_DEPTH]; ok {
477 metrics.MaxDepth = int64(maxDepth.(int32))
478 }
479
480 metrics.OpenInputCount = NotCollected
481 metrics.OpenOutputCount = NotCollected
482 metrics.OldestMsgAge = NotCollected
483 metrics.UncommittedMsgs = NotCollected
484 metrics.LastGetDate = NotCollected
485 metrics.LastGetTime = NotCollected
486 metrics.LastPutDate = NotCollected
487 metrics.LastPutTime = NotCollected
488
489 if val, ok := attrs[ibmmq.MQIA_OPEN_INPUT_COUNT]; ok {
490 metrics.OpenInputCount = AttributeValue(val.(int32))
491 }
492 if val, ok := attrs[ibmmq.MQIA_OPEN_OUTPUT_COUNT]; ok {
493 metrics.OpenOutputCount = AttributeValue(val.(int32))
494 }
495 if val, ok := attrs[ibmmq.MQIACF_OLDEST_MSG_AGE]; ok {
496 metrics.OldestMsgAge = AttributeValue(val.(int32))
497 }
498 if val, ok := attrs[ibmmq.MQIACF_UNCOMMITTED_MSGS]; ok {
499 metrics.UncommittedMsgs = AttributeValue(val.(int32))
500 }
501
502 if val, ok := attrs[ibmmq.MQCACF_LAST_GET_DATE]; ok {
503 if dateStr, ok := val.(string); ok && dateStr != "" {
504 if dateInt, err := strconv.ParseInt(dateStr, 10, 64); err == nil {
505 metrics.LastGetDate = AttributeValue(dateInt)
506 }
507 }
508 }
509 if val, ok := attrs[ibmmq.MQCACF_LAST_GET_TIME]; ok {
510 if timeStr, ok := val.(string); ok && timeStr != "" {
511 if timeInt, err := strconv.ParseInt(timeStr, 10, 64); err == nil {
512 metrics.LastGetTime = AttributeValue(timeInt)
513 }
514 }
515 }
516 if val, ok := attrs[ibmmq.MQCACF_LAST_PUT_DATE]; ok {
517 if dateStr, ok := val.(string); ok && dateStr != "" {
518 if dateInt, err := strconv.ParseInt(dateStr, 10, 64); err == nil {
519 metrics.LastPutDate = AttributeValue(dateInt)
520 }
521 }
522 }
523 if val, ok := attrs[ibmmq.MQCACF_LAST_PUT_TIME]; ok {
524 if timeStr, ok := val.(string); ok && timeStr != "" {
525 if timeInt, err := strconv.ParseInt(timeStr, 10, 64); err == nil {
526 metrics.LastPutTime = AttributeValue(timeInt)
527 }
528 }
529 }
530
531 // MQIACF_Q_TIME_INDICATOR returns an array with [short_period, long_period] time indicators
532 if val, ok := attrs[ibmmq.MQIACF_Q_TIME_INDICATOR]; ok {
533 if arrayVal, ok := val.([]int32); ok && len(arrayVal) >= 2 {
534 metrics.QTimeShort = AttributeValue(arrayVal[0])
535 metrics.QTimeLong = AttributeValue(arrayVal[1])
536 c.protocol.Debugf("QUEUE '%s' time indicators - short: %d, long: %d microseconds",
537 metrics.Name, arrayVal[0], arrayVal[1])
538 }
539 }
540
541 // Queue file size metrics (IBM MQ 9.1.5+)
542 metrics.CurrentFileSize = NotCollected
543 metrics.CurrentMaxFileSize = NotCollected
544
545 if val, ok := attrs[ibmmq.MQIACF_CUR_Q_FILE_SIZE]; ok {
546 metrics.CurrentFileSize = AttributeValue(val.(int32))
547 c.protocol.Debugf("QUEUE '%s' current file size: %d bytes", metrics.Name, val.(int32))
548 }
549 if val, ok := attrs[ibmmq.MQIACF_CUR_MAX_FILE_SIZE]; ok {
550 metrics.CurrentMaxFileSize = AttributeValue(val.(int32))
551 c.protocol.Debugf("QUEUE '%s' current max file size: %d bytes", metrics.Name, val.(int32))
552 }
553
554 metrics.HasStatusMetrics = true
555
556 // Log structured queue metrics
557 c.protocol.Debugf("QUEUE '%s' messages current_depth=%d max_depth=%d",
558 metrics.Name, metrics.CurrentDepth, metrics.MaxDepth)
559
560 if metrics.OpenInputCount != NotCollected || metrics.OpenOutputCount != NotCollected {
561 c.protocol.Debugf("QUEUE '%s' connections open_input=%d open_output=%d",
562 metrics.Name, metrics.OpenInputCount, metrics.OpenOutputCount)
563 }
564
565 if metrics.OldestMsgAge != NotCollected {
566 c.protocol.Debugf("QUEUE '%s' seconds oldest_msg_age=%d",
567 metrics.Name, metrics.OldestMsgAge)
568 }
569
570 return nil
571 }
572
573 // enrichWithResetStats enriches queue metrics with reset statistics
574 func (c *Client) enrichWithResetStats(metrics *QueueMetrics) error {
575 params := []pcfParameter{
576 newStringParameter(ibmmq.MQCA_Q_NAME, metrics.Name),
577 }
578
579 response, err := c.sendPCFCommand(ibmmq.MQCMD_RESET_Q_STATS, params)
580 if err != nil {
581 return err
582 }
583
584 attrs, err := c.parsePCFResponseFromParams(response, "")
585 if err != nil {
586 return err
587 }
588
589 if val, ok := attrs[ibmmq.MQIA_MSG_ENQ_COUNT]; ok {
590 metrics.EnqueueCount = int64(val.(int32))
591 }
592 if val, ok := attrs[ibmmq.MQIA_MSG_DEQ_COUNT]; ok {
593 metrics.DequeueCount = int64(val.(int32))
594 }
595 if val, ok := attrs[ibmmq.MQIA_HIGH_Q_DEPTH]; ok {
596 metrics.HighDepth = int64(val.(int32))
597 }
598 if val, ok := attrs[ibmmq.MQIA_TIME_SINCE_RESET]; ok {
599 metrics.TimeSinceReset = int64(val.(int32))
600 }
601
602 metrics.HasResetStats = true
603
604 // Log structured reset statistics
605 c.protocol.Debugf("QUEUE '%s' operations enqueue_count=%d dequeue_count=%d",
606 metrics.Name, metrics.EnqueueCount, metrics.DequeueCount)
607 c.protocol.Debugf("QUEUE '%s' messages high_depth=%d time_since_reset=%d",
608 metrics.Name, metrics.HighDepth, metrics.TimeSinceReset)
609
610 return nil
611 }
612
613 // GetQueueConfig returns configuration for a specific queue.
614 func (c *Client) GetQueueConfig(queueName string) (*QueueConfig, error) {
615 params := []pcfParameter{
616 newStringParameter(ibmmq.MQCA_Q_NAME, queueName),
617 }
618 response, err := c.sendPCFCommand(ibmmq.MQCMD_INQUIRE_Q, params)
619 if err != nil {
620 return nil, err
621 }
622
623 attrs, err := c.parsePCFResponseFromParams(response, "")
624 if err != nil {
625 return nil, err
626 }
627
628 config := &QueueConfig{
629 Name: queueName,
630 }
631
632 if queueType, ok := attrs[ibmmq.MQIA_Q_TYPE]; ok {
633 config.Type = QueueType(queueType.(int32))
634 }
635
636 if inhibitGet, ok := attrs[ibmmq.MQIA_INHIBIT_GET]; ok {
637 config.InhibitGet = int64(inhibitGet.(int32))
638 }
639 if inhibitPut, ok := attrs[ibmmq.MQIA_INHIBIT_PUT]; ok {
640 config.InhibitPut = int64(inhibitPut.(int32))
641 }
642
643 if backoutThreshold, ok := attrs[ibmmq.MQIA_BACKOUT_THRESHOLD]; ok {
644 config.BackoutThreshold = int64(backoutThreshold.(int32))
645 }
646 if triggerDepth, ok := attrs[ibmmq.MQIA_TRIGGER_DEPTH]; ok {
647 config.TriggerDepth = int64(triggerDepth.(int32))
648 }
649 if triggerType, ok := attrs[ibmmq.MQIA_TRIGGER_TYPE]; ok {
650 config.TriggerType = int64(triggerType.(int32))
651 }
652
653 if maxMsgLength, ok := attrs[ibmmq.MQIA_MAX_MSG_LENGTH]; ok {
654 config.MaxMsgLength = int64(maxMsgLength.(int32))
655 }
656 if defPriority, ok := attrs[ibmmq.MQIA_DEF_PRIORITY]; ok {
657 config.DefPriority = int64(defPriority.(int32))
658 }
659
660 return config, nil
661 }