Skip to content

Commit c2d4302

Browse files
committed
mqmetric restructure phase 1: move as much as possible to structures without breaking API compatibility
1 parent 57d7ea4 commit c2d4302

File tree

10 files changed

+481
-322
lines changed

10 files changed

+481
-322
lines changed

mqmetric/channel.go

Lines changed: 83 additions & 73 deletions
Large diffs are not rendered by default.

mqmetric/discover.go

Lines changed: 30 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -105,19 +105,10 @@ const ClassNameQ = "STATQ"
105105
const maxBufSize = 100 * 1024 * 1024 // 100 MB
106106
const defaultMaxQDepth = 5000
107107

108-
// Metrics is the global variable for the tree of data
109-
var Metrics AllMetrics
110-
111-
// Only issue the warning about a '/' in an object name once.
112-
var globalSlashWarning = false
113-
var localSlashWarning = false
114-
115108
var qInfoMap map[string]*ObjInfo
116109
var chlInfoMap map[string]*ObjInfo
117110

118111
var locale string
119-
var discoveryDone = false
120-
var publicationCount = 0
121112

122113
func GetDiscoveredQueues() []string {
123114
traceEntry("GetDiscoveredQueues")
@@ -130,7 +121,7 @@ func GetDiscoveredQueues() []string {
130121
}
131122

132123
func GetProcessPublicationCount() int {
133-
return publicationCount
124+
return ci.publicationCount
134125
}
135126

136127
/*
@@ -153,14 +144,14 @@ func VerifyConfig() (int32, error) {
153144
var compCode = ibmmq.MQCC_OK
154145

155146
traceEntry("VerifyConfig")
156-
if !discoveryDone {
147+
if !ci.discoveryDone {
157148
err = fmt.Errorf("Error: Need to call DiscoverAndSubscribe first")
158149
compCode = ibmmq.MQCC_FAILED
159150
}
160151

161152
if err == nil {
162153
selectors := []int32{ibmmq.MQIA_MAX_Q_DEPTH, ibmmq.MQIA_DEFINITION_TYPE}
163-
v, err = replyQObj.InqMap(selectors)
154+
v, err = ci.si.replyQObj.InqMap(selectors)
164155
if err == nil {
165156
maxQDepth := v[ibmmq.MQIA_MAX_Q_DEPTH].(int32)
166157
// Function has tuning based on number of queues to be monitored
@@ -172,8 +163,8 @@ func VerifyConfig() (int32, error) {
172163
// and assume monitor collection interval is one minute
173164
// Since we don't do pubsub-based collection on z/OS, this qdepth doesn't matter
174165
recommendedDepth := (20 + len(qInfoMap)*5) * 6
175-
if maxQDepth < int32(recommendedDepth) && usePublications {
176-
err = fmt.Errorf("Warning: Maximum queue depth on %s may be too low. Current value = %d. Suggested depth based on queue count is at least %d", replyQBaseName, maxQDepth, recommendedDepth)
166+
if maxQDepth < int32(recommendedDepth) && ci.usePublications {
167+
err = fmt.Errorf("Warning: Maximum queue depth on %s may be too low. Current value = %d. Suggested depth based on queue count is at least %d", ci.si.replyQBaseName, maxQDepth, recommendedDepth)
177168
compCode = ibmmq.MQCC_WARNING
178169
}
179170

@@ -184,7 +175,7 @@ func VerifyConfig() (int32, error) {
184175
// separate patterns, then this will overestimate what's needed. Hence it's a warning, not an error.
185176
recommendedDepth = len(chlInfoMap) + 20
186177
if maxQDepth < int32(recommendedDepth) && len(chlInfoMap) > 0 {
187-
err = fmt.Errorf("Warning: Maximum queue depth on %s may be too low. Current value = %d. Suggested depth based on channel count is at least %d\n", replyQBaseName, maxQDepth, recommendedDepth)
178+
err = fmt.Errorf("Warning: Maximum queue depth on %s may be too low. Current value = %d. Suggested depth based on channel count is at least %d\n", ci.si.replyQBaseName, maxQDepth, recommendedDepth)
188179
compCode = ibmmq.MQCC_WARNING
189180
}
190181

@@ -193,7 +184,7 @@ func VerifyConfig() (int32, error) {
193184
// A LOCAL queue would end up with mixed sets of replies/publications
194185
defType := v[ibmmq.MQIA_DEFINITION_TYPE].(int32)
195186
if defType == ibmmq.MQQDT_PREDEFINED {
196-
err = fmt.Errorf("Error: ReplyQ parameter %s must refer to a MODEL queue,", replyQBaseName)
187+
err = fmt.Errorf("Error: ReplyQ parameter %s must refer to a MODEL queue,", ci.si.replyQBaseName)
197188
compCode = ibmmq.MQCC_FAILED
198189
}
199190
}
@@ -212,7 +203,7 @@ issuing the MQSUB calls to collect the data
212203
func DiscoverAndSubscribe(dc DiscoverConfig) error {
213204
traceEntry("DiscoverAndSubscribe")
214205

215-
discoveryDone = true
206+
ci.discoveryDone = true
216207
redo := false
217208

218209
qInfoMap = make(map[string]*ObjInfo)
@@ -225,7 +216,7 @@ func DiscoverAndSubscribe(dc DiscoverConfig) error {
225216
func RediscoverAndSubscribe(dc DiscoverConfig) error {
226217
traceEntry("RediscoverAndSubscribe")
227218

228-
discoveryDone = true
219+
ci.discoveryDone = true
229220
redo := true
230221

231222
// Assume queues have been deleted and we will tidy up later.
@@ -309,8 +300,8 @@ func discoverAndSubscribe(dc DiscoverConfig, redo bool) error {
309300
// we round up the number of qmgr subs and per-queue subs. This will need extension if more object types are supported
310301
// in the amqsrua-style of resource subscriptions. Add a few extra just in case.
311302
recommendedHandles := 20 + len(qInfoMap)*5 + 10
312-
if maxHandles < int32(recommendedHandles) && usePublications {
313-
err = fmt.Errorf("MAXHANDS attribute on queue manager needs increasing. Current value = %d. Recommended minimum based on number of monitored queues = %d", maxHandles, recommendedHandles)
303+
if ci.si.maxHandles < int32(recommendedHandles) && ci.usePublications {
304+
err = fmt.Errorf("MAXHANDS attribute on queue manager needs increasing. Current value = %d. Recommended minimum based on number of monitored queues = %d", ci.si.maxHandles, recommendedHandles)
314305
}
315306
}
316307

@@ -334,9 +325,9 @@ func discoverClasses(dc DiscoverConfig, metaPrefix string) error {
334325
traceEntry("discoverClasses")
335326
// Have to know the starting point for the topic that tells about classes
336327
if metaPrefix == "" {
337-
rootTopic = "$SYS/MQ/INFO/QMGR/" + resolvedQMgrName + "/Monitor/METADATA/CLASSES"
328+
rootTopic = "$SYS/MQ/INFO/QMGR/" + ci.si.resolvedQMgrName + "/Monitor/METADATA/CLASSES"
338329
} else {
339-
rootTopic = metaPrefix + "/INFO/QMGR/" + resolvedQMgrName + "/Monitor/METADATA/CLASSES"
330+
rootTopic = metaPrefix + "/INFO/QMGR/" + ci.si.resolvedQMgrName + "/Monitor/METADATA/CLASSES"
340331
}
341332
sub, err = subscribeManaged(rootTopic, &metaReplyQObj)
342333
if err == nil {
@@ -382,7 +373,7 @@ func discoverClasses(dc DiscoverConfig, metaPrefix string) error {
382373
}
383374
}
384375

385-
subsOpened = true
376+
ci.si.subsOpened = true
386377
traceExitErr("discoverClasses", 0, err)
387378
return err
388379
}
@@ -592,7 +583,7 @@ func discoverStats(dc DiscoverConfig) error {
592583
Metrics.Classes = make(map[int]*MonClass)
593584

594585
// Allow us to proceed on z/OS even though it does not support pub/sub resources
595-
if metaPrefix == "" && !usePublications {
586+
if metaPrefix == "" && !ci.usePublications {
596587
traceExit("discoverStats", 1)
597588
return nil
598589
}
@@ -681,7 +672,7 @@ func discoverQueues(monitoredQueuePatterns string) error {
681672
qList, err = inquireObjects(monitoredQueuePatterns, ibmmq.MQOT_Q)
682673
}
683674

684-
localSlashWarning = false
675+
ci.localSlashWarning = false
685676
if len(qList) > 0 {
686677
//fmt.Printf("Monitoring Queues: %v\n", qList)
687678
for i := 0; i < len(qList); i++ {
@@ -697,8 +688,8 @@ func discoverQueues(monitoredQueuePatterns string) error {
697688
// Because of the possible complexities of pattern matching, we don't
698689
// actually fail the discovery process, but instead issue a warning and continue with
699690
// other queues.
700-
if strings.Contains(qName, "/") && globalSlashWarning == false {
701-
localSlashWarning = true // First time through, issue the warning for all queues
691+
if strings.Contains(qName, "/") && ci.globalSlashWarning == false {
692+
ci.localSlashWarning = true // First time through, issue the warning for all queues
702693
logError("Warning: Cannot subscribe to queue containing '/': %s", qName)
703694
continue
704695
}
@@ -711,7 +702,7 @@ func discoverQueues(monitoredQueuePatterns string) error {
711702
qInfoMap[qName] = qInfoElem
712703
}
713704

714-
if useStatus {
705+
if ci.useStatus {
715706
if usingRegExp {
716707
for qName, _ := range qInfoMap {
717708
if len(qName) > 0 {
@@ -723,8 +714,8 @@ func discoverQueues(monitoredQueuePatterns string) error {
723714
}
724715
}
725716

726-
if localSlashWarning {
727-
globalSlashWarning = true
717+
if ci.localSlashWarning {
718+
ci.globalSlashWarning = true
728719
}
729720

730721
if err != nil {
@@ -797,7 +788,7 @@ func inquireObjects(objectPatternsList string, objectType int32) ([]string, erro
797788
pmo.Options |= ibmmq.MQPMO_FAIL_IF_QUIESCING
798789

799790
putmqmd.Format = "MQADMIN"
800-
putmqmd.ReplyToQ = statusReplyQObj.Name
791+
putmqmd.ReplyToQ = ci.si.statusReplyQObj.Name
801792
putmqmd.MsgType = ibmmq.MQMT_REQUEST
802793
putmqmd.Report = ibmmq.MQRO_PASS_DISCARD_AND_EXPIRY
803794

@@ -826,7 +817,7 @@ func inquireObjects(objectPatternsList string, objectType int32) ([]string, erro
826817

827818
// We don't see shared queues in the returned set unless explicitly asked for.
828819
// MQQSGD_ALL returns all locals, and (if qmgr in a QSG) also shared queues.
829-
if platform == ibmmq.MQPL_ZOS {
820+
if ci.si.platform == ibmmq.MQPL_ZOS {
830821
pcfparm = new(ibmmq.PCFParameter)
831822
pcfparm.Type = ibmmq.MQCFT_INTEGER
832823
pcfparm.Parameter = ibmmq.MQIA_QSG_DISP
@@ -840,7 +831,7 @@ func inquireObjects(objectPatternsList string, objectType int32) ([]string, erro
840831
buf = append(cfh.Bytes(), buf...)
841832

842833
// And put the command to the queue
843-
err = cmdQObj.Put(putmqmd, pmo, buf)
834+
err = ci.si.cmdQObj.Put(putmqmd, pmo, buf)
844835

845836
if err != nil {
846837
traceExitErr("inquireObjects", 3, err)
@@ -863,7 +854,7 @@ func inquireObjects(objectPatternsList string, objectType int32) ([]string, erro
863854
for truncation := true; truncation; {
864855
buf = make([]byte, bufSize)
865856

866-
datalen, err = statusReplyQObj.Get(getmqmd, gmo, buf)
857+
datalen, err = ci.si.statusReplyQObj.Get(getmqmd, gmo, buf)
867858
if err == nil {
868859
truncation = false
869860
cfh, offset := ibmmq.ReadPCFHeader(buf)
@@ -955,7 +946,7 @@ func createSubscriptions() error {
955946
}
956947
} else {
957948
topic := fmt.Sprintf(ty.ObjectTopic, key)
958-
sub, err = subscribe(topic, &replyQObj)
949+
sub, err = subscribe(topic, &ci.si.replyQObj)
959950
if err == nil {
960951
ty.subHobj[key] = sub
961952
im[key].firstCollection = true
@@ -967,7 +958,7 @@ func createSubscriptions() error {
967958

968959
// Don't have a qmgr-level subscription to this topic. Should
969960
// only do this subscription once at startup
970-
sub, err = subscribe(ty.ObjectTopic, &replyQObj)
961+
sub, err = subscribe(ty.ObjectTopic, &ci.si.replyQObj)
971962
ty.subHobj[QMgrMapKey] = sub
972963
}
973964
}
@@ -1008,9 +999,9 @@ func ProcessPublications() error {
1008999

10091000
traceEntry("ProcessPublications")
10101001

1011-
publicationCount = 0
1002+
ci.publicationCount = 0
10121003

1013-
if !usePublications {
1004+
if !ci.usePublications {
10141005
traceExit("ProcessPublications", 1)
10151006
return nil
10161007
}
@@ -1023,7 +1014,7 @@ func ProcessPublications() error {
10231014
// Most common error will be MQRC_NO_MESSAGE_AVAILABLE
10241015
// which will end the loop.
10251016
if err == nil {
1026-
publicationCount++
1017+
ci.publicationCount++
10271018
elemList, _ := parsePCFResponse(data)
10281019

10291020
// A typical publication contains some fixed

mqmetric/globals.go

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
package mqmetric
2+
3+
/*
4+
Copyright (c) IBM Corporation 2016, 2021
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
18+
Contributors:
19+
Mark Taylor - Initial Contribution
20+
*/
21+
22+
import (
23+
"github.com/ibm-messaging/mq-golang/v5/ibmmq"
24+
)
25+
26+
type sessionInfo struct {
27+
qMgr ibmmq.MQQueueManager
28+
cmdQObj ibmmq.MQObject
29+
replyQObj ibmmq.MQObject
30+
qMgrObject ibmmq.MQObject
31+
replyQBaseName string
32+
statusReplyQObj ibmmq.MQObject
33+
34+
platform int32
35+
commandLevel int32
36+
maxHandles int32
37+
resolvedQMgrName string
38+
39+
qmgrConnected bool
40+
queuesOpened bool
41+
subsOpened bool
42+
}
43+
44+
type connectionInfo struct {
45+
si sessionInfo
46+
47+
tzOffsetSecs float64
48+
usePublications bool
49+
useStatus bool
50+
useResetQStats bool
51+
showInactiveChannels bool
52+
53+
// Only issue the warning about a '/' in an object name once.
54+
globalSlashWarning bool
55+
localSlashWarning bool
56+
57+
discoveryDone bool
58+
publicationCount int
59+
60+
objectStatus [GOOT_LAST_USED + 1]objectStatus
61+
}
62+
63+
type objectStatus struct {
64+
init bool
65+
objectSeen map[string]bool
66+
}
67+
68+
const (
69+
GOOT_Q = 1
70+
GOOT_NAMELIST = 2
71+
GOOT_PROCESS = 3
72+
GOOT_STORAGE_CLASS = 4
73+
GOOT_Q_MGR = 5
74+
GOOT_CHANNEL = 6
75+
GOOT_AUTH_INFO = 7
76+
GOOT_TOPIC = 8
77+
GOOT_COMM_INFO = 9
78+
GOOT_CF_STRUC = 10
79+
GOOT_LISTENER = 11
80+
GOOT_SERVICE = 12
81+
GOOT_APP = 13
82+
GOOT_PUB = 14
83+
GOOT_SUB = 15
84+
GOOT_NHA = 16
85+
GOOT_BP = 17
86+
GOOT_PS = 18
87+
GOOT_LAST_USED = GOOT_PS
88+
)
89+
90+
var ci *connectionInfo
91+
92+
// This are used externally so we need to maintain them as public exports until
93+
// there's a major version change. At which point we will move them to fields of
94+
// the objectStatus structure, retrievable by a getXXX() call instead of as public
95+
// variables. The mq-metric-samples exporters will then need to change to match.
96+
var (
97+
Metrics AllMetrics
98+
QueueManagerStatus StatusSet
99+
ChannelStatus StatusSet
100+
QueueStatus StatusSet
101+
TopicStatus StatusSet
102+
SubStatus StatusSet
103+
UsagePsStatus StatusSet
104+
UsageBpStatus StatusSet
105+
)
106+
107+
func newConnectionInfo() *connectionInfo {
108+
109+
traceEntry("newConnectionInfo")
110+
111+
ci := new(connectionInfo)
112+
ci.si.qmgrConnected = false
113+
ci.si.queuesOpened = false
114+
ci.si.subsOpened = false
115+
116+
ci.usePublications = true
117+
ci.useStatus = false
118+
ci.useResetQStats = false
119+
ci.showInactiveChannels = false
120+
121+
ci.globalSlashWarning = false
122+
ci.localSlashWarning = false
123+
ci.discoveryDone = false
124+
ci.publicationCount = 0
125+
126+
for i := 1; i <= GOOT_LAST_USED; i++ {
127+
ci.objectStatus[i].init = false
128+
}
129+
130+
traceExit("newConnectionInfo", 0)
131+
132+
return ci
133+
}
134+
135+
// Initialise this package with a default connection object for compatibility
136+
func initConnection() {
137+
traceEntry("initConnection")
138+
139+
ci = newConnectionInfo()
140+
141+
traceExit("initConnection", 0)
142+
143+
}

0 commit comments

Comments
 (0)