diff --git a/CHANGELOG.md b/CHANGELOG.md index 7be2c41..201edee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Changelog Newest updates are at the top of this file. +## Jul 23 2020 - v5.1.0 +* Update for MQ 9.2.0 +* mqmetric - Add explicit client configuration options +* mqmetric - Add counter of how many resource publicatins read per scrape + ## June 1 2020 - v5.0.0 * Migration for Go modules (requires new major number) (#138) * ibmmq - Add all string mapping functions from cmqstrc (#142) diff --git a/Dockerfile b/Dockerfile index 17006da..a0f11bc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -52,7 +52,7 @@ RUN mkdir -p $GOPATH/src $GOPATH/bin $GOPATH/pkg \ # Location of the downloadable MQ client package \ ENV RDURL="https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqdev/redist" \ RDTAR="IBM-MQC-Redist-LinuxX64.tar.gz" \ - VRMF=9.1.5.0 + VRMF=9.2.0.0 # Install the MQ client from the Redistributable package. This also contains the # header files we need to compile against. diff --git a/ibmmq/cmqc_aix.go b/ibmmq/cmqc_aix.go index 87f2b2c..def9529 100644 --- a/ibmmq/cmqc_aix.go +++ b/ibmmq/cmqc_aix.go @@ -32,8 +32,8 @@ package ibmmq **************************************************************** * * -* Generated on: 3/16/20 3:14 PM -* Build Level: p915-L200316 +* Generated on: 7/9/20 2:30 PM +* Build Level: p920-L200709 * Build Type: Production * */ @@ -1004,7 +1004,7 @@ const ( MQCMDI_SEC_SIGNOFF_ERROR int32 = 17 MQCMDI_SEC_TIMER_ZERO int32 = 14 MQCMDI_SEC_UPPERCASE int32 = 21 - MQCMDL_CURRENT_LEVEL int32 = 915 + MQCMDL_CURRENT_LEVEL int32 = 920 MQCMDL_LEVEL_1 int32 = 100 MQCMDL_LEVEL_101 int32 = 101 MQCMDL_LEVEL_110 int32 = 110 @@ -1045,6 +1045,7 @@ const ( MQCMDL_LEVEL_913 int32 = 913 MQCMDL_LEVEL_914 int32 = 914 MQCMDL_LEVEL_915 int32 = 915 + MQCMDL_LEVEL_920 int32 = 920 MQCMD_ACCOUNTING_MQI int32 = 167 MQCMD_ACCOUNTING_Q int32 = 168 MQCMD_ACTIVITY_MSG int32 = 69 diff --git a/ibmmq/cmqc_darwin.go b/ibmmq/cmqc_darwin.go index c6c8e43..4f20ea7 100644 --- a/ibmmq/cmqc_darwin.go +++ b/ibmmq/cmqc_darwin.go @@ -30,8 +30,8 @@ package ibmmq **************************************************************** * * -* Generated on: 3/16/20 3:14 PM -* Build Level: p915-L200316 +* Generated on: 7/9/20 2:30 PM +* Build Level: p920-L200709 * Build Type: Production * */ @@ -1002,7 +1002,7 @@ const ( MQCMDI_SEC_SIGNOFF_ERROR int32 = 17 MQCMDI_SEC_TIMER_ZERO int32 = 14 MQCMDI_SEC_UPPERCASE int32 = 21 - MQCMDL_CURRENT_LEVEL int32 = 915 + MQCMDL_CURRENT_LEVEL int32 = 920 MQCMDL_LEVEL_1 int32 = 100 MQCMDL_LEVEL_101 int32 = 101 MQCMDL_LEVEL_110 int32 = 110 @@ -1043,6 +1043,7 @@ const ( MQCMDL_LEVEL_913 int32 = 913 MQCMDL_LEVEL_914 int32 = 914 MQCMDL_LEVEL_915 int32 = 915 + MQCMDL_LEVEL_920 int32 = 920 MQCMD_ACCOUNTING_MQI int32 = 167 MQCMD_ACCOUNTING_Q int32 = 168 MQCMD_ACTIVITY_MSG int32 = 69 diff --git a/ibmmq/cmqc_linux_amd64.go b/ibmmq/cmqc_linux_amd64.go index f695943..5819dbd 100644 --- a/ibmmq/cmqc_linux_amd64.go +++ b/ibmmq/cmqc_linux_amd64.go @@ -30,8 +30,8 @@ package ibmmq **************************************************************** * * -* Generated on: 3/16/20 3:14 PM -* Build Level: p915-L200316 +* Generated on: 7/9/20 2:30 PM +* Build Level: p920-L200709 * Build Type: Production * */ @@ -1002,7 +1002,7 @@ const ( MQCMDI_SEC_SIGNOFF_ERROR int32 = 17 MQCMDI_SEC_TIMER_ZERO int32 = 14 MQCMDI_SEC_UPPERCASE int32 = 21 - MQCMDL_CURRENT_LEVEL int32 = 915 + MQCMDL_CURRENT_LEVEL int32 = 920 MQCMDL_LEVEL_1 int32 = 100 MQCMDL_LEVEL_101 int32 = 101 MQCMDL_LEVEL_110 int32 = 110 @@ -1043,6 +1043,7 @@ const ( MQCMDL_LEVEL_913 int32 = 913 MQCMDL_LEVEL_914 int32 = 914 MQCMDL_LEVEL_915 int32 = 915 + MQCMDL_LEVEL_920 int32 = 920 MQCMD_ACCOUNTING_MQI int32 = 167 MQCMD_ACCOUNTING_Q int32 = 168 MQCMD_ACTIVITY_MSG int32 = 69 diff --git a/ibmmq/cmqc_linux_ppc64le.go b/ibmmq/cmqc_linux_ppc64le.go index daf8a84..6419dbe 100644 --- a/ibmmq/cmqc_linux_ppc64le.go +++ b/ibmmq/cmqc_linux_ppc64le.go @@ -30,8 +30,8 @@ package ibmmq **************************************************************** * * -* Generated on: 3/16/20 3:14 PM -* Build Level: p915-L200316 +* Generated on: 7/9/20 2:30 PM +* Build Level: p920-L200709 * Build Type: Production * */ @@ -1002,7 +1002,7 @@ const ( MQCMDI_SEC_SIGNOFF_ERROR int32 = 17 MQCMDI_SEC_TIMER_ZERO int32 = 14 MQCMDI_SEC_UPPERCASE int32 = 21 - MQCMDL_CURRENT_LEVEL int32 = 915 + MQCMDL_CURRENT_LEVEL int32 = 920 MQCMDL_LEVEL_1 int32 = 100 MQCMDL_LEVEL_101 int32 = 101 MQCMDL_LEVEL_110 int32 = 110 @@ -1043,6 +1043,7 @@ const ( MQCMDL_LEVEL_913 int32 = 913 MQCMDL_LEVEL_914 int32 = 914 MQCMDL_LEVEL_915 int32 = 915 + MQCMDL_LEVEL_920 int32 = 920 MQCMD_ACCOUNTING_MQI int32 = 167 MQCMD_ACCOUNTING_Q int32 = 168 MQCMD_ACTIVITY_MSG int32 = 69 diff --git a/ibmmq/cmqc_linux_s390x.go b/ibmmq/cmqc_linux_s390x.go index 526eb3e..1140744 100644 --- a/ibmmq/cmqc_linux_s390x.go +++ b/ibmmq/cmqc_linux_s390x.go @@ -30,8 +30,8 @@ package ibmmq **************************************************************** * * -* Generated on: 3/16/20 3:14 PM -* Build Level: p915-L200316 +* Generated on: 7/9/20 2:30 PM +* Build Level: p920-L200709 * Build Type: Production * */ @@ -1002,7 +1002,7 @@ const ( MQCMDI_SEC_SIGNOFF_ERROR int32 = 17 MQCMDI_SEC_TIMER_ZERO int32 = 14 MQCMDI_SEC_UPPERCASE int32 = 21 - MQCMDL_CURRENT_LEVEL int32 = 915 + MQCMDL_CURRENT_LEVEL int32 = 920 MQCMDL_LEVEL_1 int32 = 100 MQCMDL_LEVEL_101 int32 = 101 MQCMDL_LEVEL_110 int32 = 110 @@ -1043,6 +1043,7 @@ const ( MQCMDL_LEVEL_913 int32 = 913 MQCMDL_LEVEL_914 int32 = 914 MQCMDL_LEVEL_915 int32 = 915 + MQCMDL_LEVEL_920 int32 = 920 MQCMD_ACCOUNTING_MQI int32 = 167 MQCMD_ACCOUNTING_Q int32 = 168 MQCMD_ACTIVITY_MSG int32 = 69 diff --git a/ibmmq/cmqc_windows.go b/ibmmq/cmqc_windows.go index 7376808..9cc2227 100644 --- a/ibmmq/cmqc_windows.go +++ b/ibmmq/cmqc_windows.go @@ -30,8 +30,8 @@ package ibmmq **************************************************************** * * -* Generated on: 3/16/20 3:14 PM -* Build Level: p915-L200316 +* Generated on: 7/9/20 2:30 PM +* Build Level: p920-L200709 * Build Type: Production * */ @@ -1002,7 +1002,7 @@ const ( MQCMDI_SEC_SIGNOFF_ERROR int32 = 17 MQCMDI_SEC_TIMER_ZERO int32 = 14 MQCMDI_SEC_UPPERCASE int32 = 21 - MQCMDL_CURRENT_LEVEL int32 = 915 + MQCMDL_CURRENT_LEVEL int32 = 920 MQCMDL_LEVEL_1 int32 = 100 MQCMDL_LEVEL_101 int32 = 101 MQCMDL_LEVEL_110 int32 = 110 @@ -1043,6 +1043,7 @@ const ( MQCMDL_LEVEL_913 int32 = 913 MQCMDL_LEVEL_914 int32 = 914 MQCMDL_LEVEL_915 int32 = 915 + MQCMDL_LEVEL_920 int32 = 920 MQCMD_ACCOUNTING_MQI int32 = 167 MQCMD_ACCOUNTING_Q int32 = 168 MQCMD_ACTIVITY_MSG int32 = 69 diff --git a/ibmmq/mqi.go b/ibmmq/mqi.go index 1a56093..a6d71b5 100644 --- a/ibmmq/mqi.go +++ b/ibmmq/mqi.go @@ -46,7 +46,7 @@ package ibmmq #cgo windows CFLAGS: -I"C:/Program Files/IBM/MQ/Tools/c/include" #cgo !windows,!aix,!darwin LDFLAGS: -L/opt/mqm/lib64 -lmqm_r -Wl,-rpath,/opt/mqm/lib64 -Wl,-rpath,/usr/lib64 #cgo darwin LDFLAGS: -L/opt/mqm/lib64 -lmqm_r -Wl,-rpath,/opt/mqm/lib64 -Wl,-rpath,/usr/lib64 -#cgo aix LDFLAGS: -L/usr/mqm/lib64 -lmqm_r +#cgo aix LDFLAGS: -L/usr/mqm/lib64 -lmqm_r #cgo windows LDFLAGS: -L "C:/Program Files/IBM/MQ/bin64" -lmqm #include diff --git a/ibmmq/mqistr.go b/ibmmq/mqistr.go index 989e571..4d6f8dd 100644 --- a/ibmmq/mqistr.go +++ b/ibmmq/mqistr.go @@ -1377,6 +1377,8 @@ func MQItoString(class string, value int) string { s = "MQCMDL_LEVEL_914" case 915: s = "MQCMDL_LEVEL_915" + case 920: + s = "MQCMDL_LEVEL_920" default: s = "" } diff --git a/mqmetric/channel.go b/mqmetric/channel.go index 9f94e40..7cbae4d 100644 --- a/mqmetric/channel.go +++ b/mqmetric/channel.go @@ -214,6 +214,37 @@ func CollectChannelStatus(patterns string) error { } } } + + // If someone has asked to see all the channel definitions, not just those that have a valid + // CHSTATUS response, then we can look through the list of all known channels that match + // our patterns (chlInfoMap) and add some dummy values to the status maps if the channel + // is not already there. Some of the fields do need to be faked up as we don't know anything about + // the "partner" + if err == nil && showInactiveChannels { + for chlName, v := range chlInfoMap { + found := false + chlPrefix := chlName + "/" + for k, _ := range ChannelStatus.Attributes[ATTR_CHL_STATUS].Values { + if strings.HasPrefix(k, chlPrefix) { + found = true + break + } + } + if !found { + // A channel key is normally made up of 4 elements but we only know 1 + key := chlName + "/" + DUMMY_STRING + "/" + DUMMY_STRING + "/" + DUMMY_STRING + + ChannelStatus.Attributes[ATTR_CHL_NAME].Values[key] = newStatusValueString(chlName) + ChannelStatus.Attributes[ATTR_CHL_CONNNAME].Values[key] = newStatusValueString(DUMMY_STRING) + ChannelStatus.Attributes[ATTR_CHL_JOBNAME].Values[key] = newStatusValueString(DUMMY_STRING) + ChannelStatus.Attributes[ATTR_CHL_RQMNAME].Values[key] = newStatusValueString(DUMMY_STRING) + + ChannelStatus.Attributes[ATTR_CHL_STATUS].Values[key] = newStatusValueInt64(int64(ibmmq.MQCHS_INACTIVE)) + ChannelStatus.Attributes[ATTR_CHL_STATUS_SQUASH].Values[key] = newStatusValueInt64(SQUASH_CHL_STATUS_STOPPED) + ChannelStatus.Attributes[ATTR_CHL_TYPE].Values[key] = newStatusValueInt64(v.AttrChlType) + } + } + } return err } @@ -486,7 +517,7 @@ func inquireChannelAttributes(objectPatternsList string, infoMap map[string]*Obj pcfparm = new(ibmmq.PCFParameter) pcfparm.Type = ibmmq.MQCFT_INTEGER_LIST pcfparm.Parameter = ibmmq.MQIACF_CHANNEL_ATTRS - pcfparm.Int64Value = []int64{int64(ibmmq.MQIACH_MAX_INSTANCES), int64(ibmmq.MQIACH_MAX_INSTS_PER_CLIENT), int64(ibmmq.MQCACH_DESC)} + pcfparm.Int64Value = []int64{int64(ibmmq.MQIACH_MAX_INSTANCES), int64(ibmmq.MQIACH_MAX_INSTS_PER_CLIENT), int64(ibmmq.MQCACH_DESC), int64(ibmmq.MQIACH_CHANNEL_TYPE)} cfh.ParameterCount++ buf = append(buf, pcfparm.Bytes()...) @@ -575,6 +606,18 @@ func parseChannelAttrData(cfh *ibmmq.MQCFH, buf []byte, infoMap map[string]*ObjI } + case ibmmq.MQIACH_CHANNEL_TYPE: + v := elem.Int64Value[0] + if v > 0 { + if ci, ok = infoMap[chlName]; !ok { + ci = new(ObjInfo) + infoMap[chlName] = ci + } + ci.AttrChlType = v + ci.exists = true + + } + case ibmmq.MQCACH_DESC: v := elem.String[0] if v != "" { diff --git a/mqmetric/discover.go b/mqmetric/discover.go index 1dbfa1a..5c64a45 100755 --- a/mqmetric/discover.go +++ b/mqmetric/discover.go @@ -93,6 +93,7 @@ type ObjInfo struct { // Some channel information AttrMaxInst int64 AttrMaxInstC int64 + AttrChlType int64 } // QMgrMapKey can never be a real object name and is therefore useful in @@ -116,6 +117,7 @@ var chlInfoMap map[string]*ObjInfo var locale string var discoveryDone = false +var publicationCount = 0 func GetDiscoveredQueues() []string { keys := make([]string, 0) @@ -125,6 +127,10 @@ func GetDiscoveredQueues() []string { return keys } +func GetProcessPublicationCount() int { + return publicationCount +} + /* * A collector can set the locale (eg "Fr_FR") before doing the discovery * process to get access to the MQ-translated strings @@ -928,20 +934,21 @@ func ProcessPublications() error { var elementidx int var value int64 + publicationCount = 0 + if !usePublications { return nil } // Keep reading all available messages until queue is empty. Don't // do a GET-WAIT; just immediate removals. - cnt := 0 for err == nil { data, err = getMessage(false) // Most common error will be MQRC_NO_MESSAGE_AVAILABLE // which will end the loop. if err == nil { - cnt++ + publicationCount++ elemList, _ := parsePCFResponse(data) // A typical publication contains some fixed diff --git a/mqmetric/mqif.go b/mqmetric/mqif.go index eeca2f4..02ecf38 100644 --- a/mqmetric/mqif.go +++ b/mqmetric/mqif.go @@ -48,9 +48,10 @@ var ( queuesOpened = false subsOpened = false - usePublications = true - useStatus = false - useResetQStats = false + usePublications = true + useStatus = false + useResetQStats = false + showInactiveChannels = false ) type ConnectionConfig struct { @@ -59,9 +60,14 @@ type ConnectionConfig struct { Password string TZOffsetSecs float64 - UsePublications bool - UseStatus bool - UseResetQStats bool + UsePublications bool + UseStatus bool + UseResetQStats bool + ShowInactiveChannels bool + + CcdtUrl string + ConnName string + Channel string } // Which objects are available for subscription. How @@ -97,15 +103,29 @@ to be used for all responses including the publications */ func InitConnection(qMgrName string, replyQ string, cc *ConnectionConfig) error { var err error + var gocd *ibmmq.MQCD var mqreturn *ibmmq.MQReturn var errorString = "" gocno := ibmmq.NewMQCNO() gocsp := ibmmq.NewMQCSP() + // Copy initialisation configuraton information to global vars tzOffsetSecs = cc.TZOffsetSecs + showInactiveChannels = cc.ShowInactiveChannels // Explicitly force client mode if requested. Otherwise use the "default" + // Client mode can be come from a simple boolean, or from having + // common configurations with the CCDT or ConnName/Channel being set. + if cc.CcdtUrl != "" { + cc.ClientMode = true + } else if cc.ConnName != "" || cc.Channel != "" { + cc.ClientMode = true + gocd = ibmmq.NewMQCD() + gocd.ChannelName = cc.Channel + gocd.ConnectionName = cc.ConnName + } + // connection mechanism depending on what is installed or configured. if cc.ClientMode { gocno.Options = ibmmq.MQCNO_CLIENT_BINDING @@ -113,6 +133,15 @@ func InitConnection(qMgrName string, replyQ string, cc *ConnectionConfig) error // configured (eg MQ_CONNECT_TYPE or client-only installation) connections. But // it is a bad idea to try to reconnect to a different queue manager. gocno.Options |= ibmmq.MQCNO_RECONNECT_Q_MGR + if cc.CcdtUrl != "" { + gocno.CCDTUrl = cc.CcdtUrl + logInfo("Trying to connect as client using CCDT: %s", gocno.CCDTUrl) + } else if gocd != nil { + gocno.ClientConn = gocd + logInfo("Trying to connect as client using ConnName: %s, Channel: %s", gocd.ConnectionName, gocd.ChannelName) + } else { + logInfo("Trying to connect as client with external configuration") + } } gocno.Options |= ibmmq.MQCNO_HANDLE_SHARE_BLOCK