Skip to content

Commit a00798c

Browse files
committed
Add option to add CUSTOM attribute to qmgr/queue tags (ibm-messaging/mq-metric-samples#392)
1 parent b786483 commit a00798c

File tree

7 files changed

+178
-122
lines changed

7 files changed

+178
-122
lines changed

CHANGELOG.md

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,35 @@
11
# Changelog
22
Newest updates are at the top of this file.
33

4-
## XXX XX 2025 - v5.6.5
4+
## XXX XX 2025 - v5.6.5
5+
- Update for MQ 9.4.4
56
- mqmetric - Make command requests (and replies) expire after a while
7+
- mqmetric - Add option to add CUSTOM attribute to qmgr/queue tags (ibm-messaging/mq-metric-samples#392)
68

7-
## Jun 16 2025 - v5.6.4
9+
## Jun 16 2025 - v5.6.4
810
- Update for MQ 9.4.3
911
- mqmetric - Add MQTT metrics
10-
- mqmetric - Add security_protocol metric for channels
12+
- mqmetric - Add security_protocol metric for channels
1113
- mqmetric - Add sslciph label/tag for channels
1214
- mqmetric - Fail connection in preference to warning when unexpected error
13-
- mqmetric - Some z/OS versions don't support MQINQ(MQCA_VERSION) (#395)
15+
- mqmetric - Some z/OS versions don't support MQINQ(MQCA_VERSION) (#395)
1416
- mqmetric - Add startTime (epoch, milliseconds) for all channel types
1517
- mqmetric - Add active_service metric for qmgr
1618
- mqmetric - Increase recommended max qdepth on replyQ as there are now more potential queue subscriptions
1719
- samples - JWT prefer to use ClientSecret instead of Password
1820

19-
## May 08 2025 - v5.6.3
21+
## May 08 2025 - v5.6.3
2022
- mqmetric - Fixes for #222 and ibm-messaging/mq-metric-samples#395
2123

22-
## Feb 28 2025 - v5.6.2
24+
## Feb 28 2025 - v5.6.2
2325
- Update for MQ 9.4.2
2426
- ibmmq - Add function to map PCF attribute values to strings
2527
- ibmmq - Interpret more PCF types (the filters)
2628
- ibmmq - MaxSCOLength fix - PR #216
2729
- ibmmq - Add MQIGolangVersion function
2830
- ibmmq - Handle MQ C client callbacks with wrong hObj (#217)
2931
- mqmetric - Ignore the EXTENDED queue metrics unless explicitly enabled
30-
- mqmetric - Deal with possible duplication of metrics between QSTATUS and published QSTAT values
32+
- mqmetric - Deal with possible duplication of metrics between QSTATUS and published QSTAT values
3133
Without this change, Prometheus (at least) will panic. The system topic metrics were extended
3234
in MQ 9.4.2 and potentially in various fixpacks for older LTS releases; this version of the collector code is required
3335
once you reach those qmgr levels.
@@ -37,24 +39,24 @@ Newest updates are at the top of this file.
3739
- samples - Ensure Dockerfile examples do not pull base images from Dockerhub
3840
- samples - Remove unnecessary (incorrect) declarations
3941

40-
## Oct 24 2024 - v5.6.1
42+
## Oct 24 2024 - v5.6.1
4143
- Update for MQ 9.4.1
4244
- Some linter-suggested code changes
4345
- ibmmq - Support for new MQSCO HTTPS fields
4446
- ibmmq - Support for parsing MQRFH2 structures
4547
- mqmetric - Force conversion to 1208 for resource metrics (#345)
4648
- New package for instrumenting applications for OpenTelemetry Tracing
4749

48-
## Jun 18 2024 - v5.6.0
50+
## Jun 18 2024 - v5.6.0
4951
- Update for MQ 9.4.0
5052

51-
## Feb 29 2024 - v5.5.4
53+
## Feb 29 2024 - v5.5.4
5254
- Update for MQ 9.3.5
5355
- ibmmq - Add simple tracing for MQI calls (MQIGO_TRACE env var)
5456
- samples - Add sample obtaining and using a JWT token
5557
- Make Go 1.18 baseline compiler
5658

57-
## Nov 13 2023 - v5.5.3
59+
## Nov 13 2023 - v5.5.3
5860
- mqmetric - MQ 9.3 permits resource subscriptions for queues with '/' in name
5961

6062
## Nov 08 2023 - v5.5.2
@@ -64,8 +66,8 @@ Newest updates are at the top of this file.
6466
## Oct 19 2023 - v5.5.1
6567
- Update for MQ 9.3.4
6668
- ibmmq - Support for new CSP JWT Token field
67-
- mqmetric - metrics.txt now includes the published resource metrics, automatically generated
68-
from product documentation
69+
- mqmetric - metrics.txt now includes the published resource metrics, automatically generated
70+
from product documentation
6971
- Refresh links to IBM documentation
7072

7173
## Jun 21 2023 - v5.5.0
@@ -77,14 +79,14 @@ Newest updates are at the top of this file.
7779
- Update for MQ 9.3.2
7880
- mqmetric - Add hostname tag for 9.3.2 qmgrs (added to DIS QMSTATUS response) (ibm-messaging/mq-metric-samples#184)
7981
- mqmetric - Add subscriptions to NativeHA published metrics
80-
- mqmetric - Add metrics for status of log extents
82+
- mqmetric - Add metrics for status of log extents
8183

8284
## Jan 10 2023 - v5.3.3
8385
- ibmmq - Add more attributes that can be MQINQ'd
8486
- mqmetric - New metric qmgr_active_listeners (ibm-messaging/mq-metric-samples#183)
8587
- mqmetric - Add qmgr description as tag (ibm-messaging/mq-metric-samples#184)
86-
- mqmetric - Add metrics.txt to list the available metrics that do not come from
87-
the amqsrua-style publication
88+
- mqmetric - Add metrics.txt to list the available metrics that do not come from
89+
the amqsrua-style publication
8890

8991
## Oct 17 2022 - v5.3.2
9092
- Update for MQ 9.3.1
@@ -94,7 +96,7 @@ Newest updates are at the top of this file.
9496
- mqmetric - Add metrics for AMQP channels
9597
- mqmetric - Add cluster name as tag for queues (#191)
9698
- Rewrite README to better match recent compiler versions and module management
97-
- Update expected Go compiler version
99+
- Update expected Go compiler version
98100

99101
## Jul 23 2022 - v5.3.1
100102
- Fix #189 compile problem

mqmetric/discover.go

Lines changed: 129 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ type ObjInfo struct {
8282
exists bool // Used during rediscovery
8383
firstCollection bool // To indicate discard needed of first stat
8484
Description string
85+
Custom string
8586
// Qmgr attributes
8687
QMgrName string
8788
HostName string
@@ -392,40 +393,42 @@ func discoverClasses(dc DiscoverConfig, metaPrefix string) error {
392393
defer metaReplyQObj.Close(0)
393394
defer mqtd.unsubscribe()
394395

395-
elemList, _ := parsePCFResponse(data)
396-
397-
for i := 0; i < len(elemList); i++ {
398-
if elemList[i].Type != ibmmq.MQCFT_GROUP {
399-
continue
400-
}
401-
group := elemList[i]
402-
cl := new(MonClass)
403-
classIndex := 0
404-
cl.Types = make(map[int]*MonType)
405-
cl.Parent = GetPublishedMetrics(k)
396+
if err == nil {
397+
elemList, _ := parsePCFResponse(data)
406398

407-
for j := 0; j < len(group.GroupList); j++ {
408-
elem := group.GroupList[j]
409-
switch elem.Parameter {
410-
case ibmmq.MQIAMO_MONITOR_CLASS:
411-
classIndex = int(elem.Int64Value[0])
412-
case ibmmq.MQIAMO_MONITOR_FLAGS:
413-
cl.flags = int(elem.Int64Value[0])
414-
case ibmmq.MQCAMO_MONITOR_CLASS:
415-
cl.Name = elem.String[0]
416-
case ibmmq.MQCAMO_MONITOR_DESC:
417-
cl.Description = elem.String[0]
418-
case ibmmq.MQCA_TOPIC_STRING:
419-
cl.typesTopic = elem.String[0]
420-
default:
421-
e2 := fmt.Errorf("Unknown parameter %d in class discovery", elem.Parameter)
422-
traceExitErr("discoverClasses", 1, e2)
423-
return e2
399+
for i := 0; i < len(elemList); i++ {
400+
if elemList[i].Type != ibmmq.MQCFT_GROUP {
401+
continue
402+
}
403+
group := elemList[i]
404+
cl := new(MonClass)
405+
classIndex := 0
406+
cl.Types = make(map[int]*MonType)
407+
cl.Parent = GetPublishedMetrics(k)
408+
409+
for j := 0; j < len(group.GroupList); j++ {
410+
elem := group.GroupList[j]
411+
switch elem.Parameter {
412+
case ibmmq.MQIAMO_MONITOR_CLASS:
413+
classIndex = int(elem.Int64Value[0])
414+
case ibmmq.MQIAMO_MONITOR_FLAGS:
415+
cl.flags = int(elem.Int64Value[0])
416+
case ibmmq.MQCAMO_MONITOR_CLASS:
417+
cl.Name = elem.String[0]
418+
case ibmmq.MQCAMO_MONITOR_DESC:
419+
cl.Description = elem.String[0]
420+
case ibmmq.MQCA_TOPIC_STRING:
421+
cl.typesTopic = elem.String[0]
422+
default:
423+
e2 := fmt.Errorf("Unknown parameter %d in class discovery", elem.Parameter)
424+
traceExitErr("discoverClasses", 1, e2)
425+
return e2
426+
}
424427
}
425-
}
426428

427-
if includeClass(dc, cl.Name) {
428-
cl.Parent.Classes[classIndex] = cl
429+
if includeClass(dc, cl.Name) {
430+
cl.Parent.Classes[classIndex] = cl
431+
}
429432
}
430433
}
431434
}
@@ -449,50 +452,52 @@ func discoverTypes(dc DiscoverConfig, cl *MonClass) error {
449452
defer metaReplyQObj.Close(0)
450453
defer mqtd.unsubscribe()
451454

452-
elemList, _ := parsePCFResponse(data)
453-
454-
for i := 0; i < len(elemList); i++ {
455-
if elemList[i].Type != ibmmq.MQCFT_GROUP {
456-
continue
457-
}
458-
459-
group := elemList[i]
460-
ty := new(MonType)
461-
ty.Elements = make(map[int]*MonElement)
462-
ty.subHobj = make(map[string]*MQTopicDescriptor)
463-
464-
typeIndex := 0
465-
ty.Parent = cl
455+
if err == nil {
456+
elemList, _ := parsePCFResponse(data)
466457

467-
for j := 0; j < len(group.GroupList); j++ {
468-
elem := group.GroupList[j]
469-
switch elem.Parameter {
458+
for i := 0; i < len(elemList); i++ {
459+
if elemList[i].Type != ibmmq.MQCFT_GROUP {
460+
continue
461+
}
470462

471-
case ibmmq.MQIAMO_MONITOR_TYPE:
472-
typeIndex = int(elem.Int64Value[0])
473-
case ibmmq.MQCAMO_MONITOR_TYPE:
474-
ty.Name = elem.String[0]
475-
case ibmmq.MQCAMO_MONITOR_DESC:
476-
ty.Description = elem.String[0]
477-
case ibmmq.MQCA_TOPIC_STRING:
478-
ty.elementTopic = elem.String[0]
479-
default:
480-
e2 := fmt.Errorf("Unknown parameter %d in type discovery", elem.Parameter)
481-
traceExitErr("discoverTypes", 1, e2)
482-
return e2
463+
group := elemList[i]
464+
ty := new(MonType)
465+
ty.Elements = make(map[int]*MonElement)
466+
ty.subHobj = make(map[string]*MQTopicDescriptor)
467+
468+
typeIndex := 0
469+
ty.Parent = cl
470+
471+
for j := 0; j < len(group.GroupList); j++ {
472+
elem := group.GroupList[j]
473+
switch elem.Parameter {
474+
475+
case ibmmq.MQIAMO_MONITOR_TYPE:
476+
typeIndex = int(elem.Int64Value[0])
477+
case ibmmq.MQCAMO_MONITOR_TYPE:
478+
ty.Name = elem.String[0]
479+
case ibmmq.MQCAMO_MONITOR_DESC:
480+
ty.Description = elem.String[0]
481+
case ibmmq.MQCA_TOPIC_STRING:
482+
ty.elementTopic = elem.String[0]
483+
default:
484+
e2 := fmt.Errorf("Unknown parameter %d in type discovery", elem.Parameter)
485+
traceExitErr("discoverTypes", 1, e2)
486+
return e2
487+
}
483488
}
484-
}
485-
if ty.Parent.Name == "STATQ" && dc.MonitoredQueues.SubscriptionSelector != "" {
486-
if strings.Contains(dc.MonitoredQueues.SubscriptionSelector, ty.Name) {
489+
if ty.Parent.Name == "STATQ" && dc.MonitoredQueues.SubscriptionSelector != "" {
490+
if strings.Contains(dc.MonitoredQueues.SubscriptionSelector, ty.Name) {
491+
if includeType(dc, ty.Name) {
492+
cl.Types[typeIndex] = ty
493+
}
494+
} else {
495+
logDebug("Not subscribing to Class STATQ Type %s resources", ty.Name)
496+
}
497+
} else {
487498
if includeType(dc, ty.Name) {
488499
cl.Types[typeIndex] = ty
489500
}
490-
} else {
491-
logDebug("Not subscribing to Class STATQ Type %s resources", ty.Name)
492-
}
493-
} else {
494-
if includeType(dc, ty.Name) {
495-
cl.Types[typeIndex] = ty
496501
}
497502
}
498503
}
@@ -520,46 +525,48 @@ func discoverElements(dc DiscoverConfig, ty *MonType) error {
520525
defer metaReplyQObj.Close(0)
521526
defer mqtd.unsubscribe()
522527

523-
elemList, _ := parsePCFResponse(data)
524-
525-
for i := 0; i < len(elemList); i++ {
526-
527-
if elemList[i].Type == ibmmq.MQCFT_STRING && elemList[i].Parameter == ibmmq.MQCA_TOPIC_STRING {
528-
ty.ObjectTopic = elemList[i].String[0]
529-
continue
530-
}
531-
532-
if elemList[i].Type != ibmmq.MQCFT_GROUP {
533-
continue
534-
}
528+
if err == nil {
529+
elemList, _ := parsePCFResponse(data)
535530

536-
group := elemList[i]
531+
for i := 0; i < len(elemList); i++ {
537532

538-
elem = new(MonElement)
539-
elementIndex := 0
540-
elem.Parent = ty
541-
elem.Values = make(map[string]int64)
533+
if elemList[i].Type == ibmmq.MQCFT_STRING && elemList[i].Parameter == ibmmq.MQCA_TOPIC_STRING {
534+
ty.ObjectTopic = elemList[i].String[0]
535+
continue
536+
}
542537

543-
for j := 0; j < len(group.GroupList); j++ {
544-
e := group.GroupList[j]
545-
switch e.Parameter {
538+
if elemList[i].Type != ibmmq.MQCFT_GROUP {
539+
continue
540+
}
546541

547-
case ibmmq.MQIAMO_MONITOR_ELEMENT:
548-
elementIndex = int(e.Int64Value[0])
549-
case ibmmq.MQIAMO_MONITOR_DATATYPE:
550-
elem.Datatype = int32(e.Int64Value[0])
551-
case ibmmq.MQCAMO_MONITOR_DESC:
552-
elem.Description = e.String[0]
553-
default:
554-
e2 := fmt.Errorf("Unknown parameter %d in type discovery", e.Parameter)
555-
traceExitErr("discoverElements", 1, e2)
556-
return e2
542+
group := elemList[i]
543+
544+
elem = new(MonElement)
545+
elementIndex := 0
546+
elem.Parent = ty
547+
elem.Values = make(map[string]int64)
548+
549+
for j := 0; j < len(group.GroupList); j++ {
550+
e := group.GroupList[j]
551+
switch e.Parameter {
552+
553+
case ibmmq.MQIAMO_MONITOR_ELEMENT:
554+
elementIndex = int(e.Int64Value[0])
555+
case ibmmq.MQIAMO_MONITOR_DATATYPE:
556+
elem.Datatype = int32(e.Int64Value[0])
557+
case ibmmq.MQCAMO_MONITOR_DESC:
558+
elem.Description = e.String[0]
559+
default:
560+
e2 := fmt.Errorf("Unknown parameter %d in type discovery", e.Parameter)
561+
traceExitErr("discoverElements", 1, e2)
562+
return e2
563+
}
557564
}
558-
}
559565

560-
elem.MetricName = formatDescription(elem)
561-
if includeElem(ci, elem, true) {
562-
ty.Elements[elementIndex] = elem
566+
elem.MetricName = formatDescription(elem)
567+
if includeElem(ci, elem, true) {
568+
ty.Elements[elementIndex] = elem
569+
}
563570
}
564571
}
565572
}
@@ -1648,6 +1655,25 @@ func GetObjectDescription(key string, objectType int32) string {
16481655
}
16491656
}
16501657

1658+
func GetObjectCustom(key string, objectType int32) string {
1659+
var o *ObjInfo
1660+
ok := false
1661+
switch objectType {
1662+
case ibmmq.MQOT_Q:
1663+
o, ok = qInfoMap[key]
1664+
case OT_Q_MGR:
1665+
o = qMgrInfo
1666+
ok = true
1667+
}
1668+
1669+
if !ok || strings.TrimSpace(o.Custom) == "" {
1670+
// return something so Prometheus doesn't turn it into "0.0"
1671+
return DUMMY_STRING
1672+
} else {
1673+
return o.Custom
1674+
}
1675+
}
1676+
16511677
func trimToNull(s string) string {
16521678
var rc string
16531679
i := strings.IndexByte(s, 0)

0 commit comments

Comments
 (0)