Skip to content

Commit 124dd80

Browse files
committed
Modified definition of error types for MQRC/MQCC
Added metaprefix option for prometheus monitor
1 parent e139323 commit 124dd80

File tree

10 files changed

+207
-146
lines changed

10 files changed

+207
-146
lines changed

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ This repository demonstrates how you can call IBM MQ from applications written i
44
The repository also includes programs to export MQ statistics to some monitoring
55
packages including Prometheus, InfluxDB and OpenTSDB.
66

7+
A minimum level of MQ V9 is required to build this package.
8+
The monitoring data published by the queue manager is not available before
9+
that version.
10+
711
## MQI Description
812

913
The ibmmq directory contains a Go package, exposing an MQI-like interface.
@@ -26,6 +30,9 @@ have a copy of MQ installed to build against. It uses cgo to access the MQI C st
2630
installed in the default location on a Linux platform (/opt/mqm) but you can easily change the
2731
cgo directives in the source files if necessary.
2832

33+
A minimum level of MQ V9 is required. The monitoring data published
34+
by the queue manager is not available before that version.
35+
2936
Some Windows capability is also included. One constraint in the cgo package is its support
3037
for path names containing spaces and special characters, which makes it tricky to
3138
compile against a copy of MQ installed in the regular location. To build these packages I copied
@@ -175,6 +182,16 @@ connectivity, without requiring a CCDT. See the clientconn sample program
175182
for an example of using the MQCD.
176183
* Moved sample programs into subdirectory
177184

185+
15 Feb 2017
186+
* API BREAKING CHANGE: The MQI verbs have been changed to return a single
187+
error indicator instead of two separate values. See mqitest.go for
188+
examples of how MQRC/MQCC codes can now be tested and extracted. This change
189+
makes the MQI implementation a bit more natural for Go environments.
190+
191+
25 Mar 2017
192+
* Added the metaPrefix option to the Prometheus monitor. This allows selection of non-default resources such as the MQ Bridge for Salesforce included in MQ 9.0.2.
193+
194+
178195
## Health Warning
179196

180197
This package is provided as-is with no guarantees of support or updates. There are also no guarantees of compatibility

cmd/mq_prometheus/config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ type mqExporterConfig struct {
2929
monitoredQueues string
3030
monitoredQueuesFile string
3131

32+
metaPrefix string
33+
3234
cc mqmetric.ClientConfig
3335

3436
httpListenPort string
@@ -56,6 +58,7 @@ func initConfig() {
5658
flag.StringVar(&config.replyQ, "ibmmq.replyQueue", "SYSTEM.DEFAULT.MODEL.QUEUE", "Reply Queue to collect data")
5759
flag.StringVar(&config.monitoredQueues, "ibmmq.monitoredQueues", "", "Patterns of queues to monitor")
5860
flag.StringVar(&config.monitoredQueuesFile, "ibmmq.monitoredQueuesFile", "", "File with patterns of queues to monitor")
61+
flag.StringVar(&config.metaPrefix, "metaPrefix", "", "Override path to monitoring resource topic")
5962

6063
flag.BoolVar(&config.cc.ClientMode, "ibmmq.client", false, "Connect as MQ client")
6164

cmd/mq_prometheus/main.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,13 @@ func main() {
5656
// What metrics can the queue manager provide? Find out, and
5757
// subscribe.
5858
if err == nil {
59-
err = mqmetric.DiscoverAndSubscribe(config.monitoredQueues, true, "")
59+
// Do we need to expand wildcarded queue names
60+
// or use the wildcard as-is in the subscriptions
61+
wildcardResource := true
62+
if config.metaPrefix != "" {
63+
wildcardResource = false
64+
}
65+
err = mqmetric.DiscoverAndSubscribe(config.monitoredQueues, wildcardResource, config.metaPrefix)
6066
}
6167

6268
// Once everything has been discovered, and the subscriptions

cmd/samples/clientconn/clientconn.go

Lines changed: 73 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -37,78 +37,81 @@ package main
3737
*/
3838

3939
import (
40-
"bufio"
41-
"fmt"
42-
"ibmmq"
43-
"os"
44-
"time"
40+
"bufio"
41+
"fmt"
42+
"ibmmq"
43+
"os"
44+
"time"
4545
)
4646

4747
func main() {
48-
var qMgrName string
49-
var err error
50-
var qMgr ibmmq.MQQueueManager
51-
52-
if len(os.Args) != 4 {
53-
fmt.Println("clientconn <qmgrname> <channelname> <conname>")
54-
fmt.Println("")
55-
fmt.Println("For example")
56-
fmt.Println(" clientconn QMGR1 \"SYSTEM.DEF.SVRCONN\" \"myhost.example.com(1414)\"")
57-
fmt.Println("All parameters are required.")
58-
os.Exit(1)
59-
}
60-
61-
// Which queue manager do we want to connect to
62-
qMgrName = os.Args[1]
63-
64-
// Allocate the MQCNO and MQCD structures needed for the
65-
// MQCONNX call.
66-
cno := ibmmq.NewMQCNO()
67-
cd := ibmmq.NewMQCD()
68-
69-
// Fill in the required fields in the
70-
// MQCD channel definition structure
71-
cd.ChannelName = os.Args[2]
72-
cd.ConnectionName = os.Args[3]
73-
74-
// Reference the CD structure from the CNO
75-
// and indicate that we want to use the client
76-
// connection method.
77-
cno.ClientConn = cd
78-
cno.Options = ibmmq.MQCNO_CLIENT_BINDING
79-
80-
// Also fill in the userid and password if the MQSAMP_USER_ID
81-
// environment variable is set. This is the same as the C
82-
// sample programs such as amqsput.
83-
userId := os.Getenv("MQSAMP_USER_ID")
84-
if userId != "" {
85-
scanner := bufio.NewScanner(os.Stdin)
86-
csp := ibmmq.NewMQCSP()
87-
csp.AuthenticationType = ibmmq.MQCSP_AUTH_USER_ID_AND_PWD
88-
csp.UserId = userId
89-
90-
fmt.Println("Enter password : ")
91-
scanner.Scan()
92-
csp.Password = scanner.Text()
93-
94-
// And make the CNO refer to the CSP structure
95-
cno.SecurityParms = csp
96-
}
97-
98-
// And connect. Wait a short time before
99-
// disconnecting.
100-
qMgr, mqreturn, err := ibmmq.Connx(qMgrName, cno)
101-
if err == nil {
102-
fmt.Printf("Connection to %s succeeded.\n", qMgrName)
103-
d, _ := time.ParseDuration("5s")
104-
time.Sleep(d)
105-
qMgr.Disc()
106-
} else {
107-
fmt.Printf("Connection to %s failed.\n", qMgrName)
108-
fmt.Println(err)
109-
}
110-
111-
fmt.Println("Done.")
112-
os.Exit((int)(mqreturn.MQCC))
48+
var qMgrName string
49+
var err error
50+
var qMgr ibmmq.MQQueueManager
51+
var rc int
52+
53+
if len(os.Args) != 4 {
54+
fmt.Println("clientconn <qmgrname> <channelname> <conname>")
55+
fmt.Println("")
56+
fmt.Println("For example")
57+
fmt.Println(" clientconn QMGR1 \"SYSTEM.DEF.SVRCONN\" \"myhost.example.com(1414)\"")
58+
fmt.Println("All parameters are required.")
59+
os.Exit(1)
60+
}
61+
62+
// Which queue manager do we want to connect to
63+
qMgrName = os.Args[1]
64+
65+
// Allocate the MQCNO and MQCD structures needed for the
66+
// MQCONNX call.
67+
cno := ibmmq.NewMQCNO()
68+
cd := ibmmq.NewMQCD()
69+
70+
// Fill in the required fields in the
71+
// MQCD channel definition structure
72+
cd.ChannelName = os.Args[2]
73+
cd.ConnectionName = os.Args[3]
74+
75+
// Reference the CD structure from the CNO
76+
// and indicate that we want to use the client
77+
// connection method.
78+
cno.ClientConn = cd
79+
cno.Options = ibmmq.MQCNO_CLIENT_BINDING
80+
81+
// Also fill in the userid and password if the MQSAMP_USER_ID
82+
// environment variable is set. This is the same as the C
83+
// sample programs such as amqsput.
84+
userId := os.Getenv("MQSAMP_USER_ID")
85+
if userId != "" {
86+
scanner := bufio.NewScanner(os.Stdin)
87+
csp := ibmmq.NewMQCSP()
88+
csp.AuthenticationType = ibmmq.MQCSP_AUTH_USER_ID_AND_PWD
89+
csp.UserId = userId
90+
91+
fmt.Println("Enter password : ")
92+
scanner.Scan()
93+
csp.Password = scanner.Text()
94+
95+
// And make the CNO refer to the CSP structure
96+
cno.SecurityParms = csp
97+
}
98+
99+
// And connect. Wait a short time before
100+
// disconnecting.
101+
qMgr, err = ibmmq.Connx(qMgrName, cno)
102+
if err == nil {
103+
fmt.Printf("Connection to %s succeeded.\n", qMgrName)
104+
d, _ := time.ParseDuration("5s")
105+
time.Sleep(d)
106+
qMgr.Disc()
107+
rc = 0
108+
} else {
109+
fmt.Printf("Connection to %s failed.\n", qMgrName)
110+
fmt.Println(err)
111+
rc = int(err.(*ibmmq.MQReturn).MQCC)
112+
}
113+
114+
fmt.Println("Done.")
115+
os.Exit(rc)
113116

114117
}

cmd/samples/mqitest/mqitest.go

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func main() {
6262

6363
qMgrName = os.Args[2]
6464
connected := false
65-
qMgr, mqreturn, err := ibmmq.Conn(qMgrName)
65+
qMgr, err := ibmmq.Conn(qMgrName)
6666
if err != nil {
6767
fmt.Println(err)
6868
} else {
@@ -80,7 +80,7 @@ func main() {
8080
mqod.ObjectType = ibmmq.MQOT_Q
8181
mqod.ObjectName = os.Args[1]
8282

83-
qObject, mqreturn, err = qMgr.Open(mqod, openOptions)
83+
qObject, err = qMgr.Open(mqod, openOptions)
8484
if err != nil {
8585
fmt.Println(err)
8686
} else {
@@ -103,7 +103,7 @@ func main() {
103103
msgData := "Hello from Go"
104104
buffer := []byte(msgData)
105105

106-
mqreturn, err = qObject.Put(putmqmd, pmo, buffer)
106+
err = qObject.Put(putmqmd, pmo, buffer)
107107

108108
if err != nil {
109109
fmt.Println(err)
@@ -115,7 +115,7 @@ func main() {
115115
// The message was put in syncpoint so it needs
116116
// to be committed.
117117
if err == nil {
118-
mqreturn, err = qMgr.Cmit()
118+
err = qMgr.Cmit()
119119
if err != nil {
120120
fmt.Println(err)
121121
}
@@ -136,12 +136,13 @@ func main() {
136136
gmo.WaitInterval = 3000
137137
buffer := make([]byte, 32768)
138138

139-
datalen, mqreturn, err = qObject.Get(getmqmd, gmo, buffer)
139+
datalen, err = qObject.Get(getmqmd, gmo, buffer)
140140

141141
if err != nil {
142142
msgAvail = false
143143
fmt.Println(err)
144-
if mqreturn.MQRC == ibmmq.MQRC_NO_MSG_AVAILABLE {
144+
mqret := err.(*ibmmq.MQReturn)
145+
if mqret.MQRC == ibmmq.MQRC_NO_MSG_AVAILABLE {
145146
// not a real error so reset err
146147
err = nil
147148
}
@@ -154,7 +155,7 @@ func main() {
154155

155156
// MQCLOSE the queue
156157
if err == nil {
157-
mqreturn, err = qObject.Close(0)
158+
err = qObject.Close(0)
158159
if err != nil {
159160
fmt.Println(err)
160161
} else {
@@ -174,7 +175,7 @@ func main() {
174175
mqsd.Options |= ibmmq.MQSO_MANAGED
175176
mqsd.ObjectString = "$SYS/MQ/INFO/QMGR/" + qMgrName + "/ActivityTrace/ApplName/mqitest"
176177

177-
subObject, mqreturn, err = qMgr.Sub(mqsd, &managedQObject)
178+
subObject, err = qMgr.Sub(mqsd, &managedQObject)
178179

179180
if err != nil {
180181
fmt.Println(err)
@@ -201,12 +202,13 @@ func main() {
201202
gmo.WaitInterval = 3000
202203
buffer := make([]byte, 32768)
203204

204-
datalen, mqreturn, err = managedQObject.Get(getmqmd, gmo, buffer)
205+
datalen, err = managedQObject.Get(getmqmd, gmo, buffer)
205206

206207
if err != nil {
207208
msgAvail = false
208209
fmt.Println(err)
209-
if mqreturn.MQRC == ibmmq.MQRC_NO_MSG_AVAILABLE {
210+
mqret := err.(*ibmmq.MQReturn)
211+
if mqret.MQRC == ibmmq.MQRC_NO_MSG_AVAILABLE {
210212
// not a real error so reset err, but
211213
// end retrieval loop
212214
err = nil
@@ -229,7 +231,7 @@ func main() {
229231
mqod.ObjectType = ibmmq.MQOT_Q_MGR
230232
mqod.ObjectName = ""
231233

232-
qMgrObject, mqreturn, err = qMgr.Open(mqod, openOptions)
234+
qMgrObject, err = qMgr.Open(mqod, openOptions)
233235

234236
if err != nil {
235237
fmt.Println(err)
@@ -243,7 +245,7 @@ func main() {
243245
ibmmq.MQCA_DEAD_LETTER_Q_NAME,
244246
ibmmq.MQIA_MSG_MARK_BROWSE_INTERVAL}
245247

246-
intAttrs, charAttrs, _, err := qMgrObject.Inq(selectors, 2, 160)
248+
intAttrs, charAttrs, err := qMgrObject.Inq(selectors, 2, 160)
247249

248250
if err != nil {
249251
fmt.Println(err)
@@ -258,10 +260,15 @@ func main() {
258260

259261
// MQDISC regardless of other errors
260262
if connected {
261-
mqreturn, err = qMgr.Disc()
263+
err = qMgr.Disc()
262264
fmt.Println("Disconnected from queue manager ", qMgrName)
263265
}
264266

265-
os.Exit((int)(mqreturn.MQCC))
267+
if err == nil {
268+
os.Exit(0)
269+
} else {
270+
mqret := err.(*ibmmq.MQReturn)
271+
os.Exit((int)(mqret.MQCC))
272+
}
266273

267274
}

0 commit comments

Comments
 (0)