master
go 221 lines 8.97 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
10 "github.com/ibm-messaging/mq-golang/v5/ibmmq"
11 )
12
13 // GetQueueManagerStatus returns the status of the queue manager.
14 func (c *Client) GetQueueManagerStatus() (*QueueManagerMetrics, error) {
15 c.protocol.Debugf("QMGR getting status for queue manager '%s'", c.config.QueueManager)
16
17 response, err := c.sendPCFCommand(ibmmq.MQCMD_INQUIRE_Q_MGR_STATUS, nil)
18 if err != nil {
19 // Fallback to basic inquiry
20 c.protocol.Debugf("QMGR status inquiry failed for queue manager '%s', trying basic inquiry: %v", c.config.QueueManager, err)
21 response, err = c.sendPCFCommand(ibmmq.MQCMD_INQUIRE_Q_MGR, nil)
22 if err != nil {
23 c.protocol.Errorf("QMGR failed to get status for queue manager '%s': %v", c.config.QueueManager, err)
24 return nil, err
25 }
26 }
27
28 attrs := make(map[int32]interface{})
29 for _, param := range response {
30 switch param.Type {
31 case ibmmq.MQCFT_STRING:
32 if len(param.String) > 0 {
33 attrs[param.Parameter] = param.String[0]
34 }
35 case ibmmq.MQCFT_INTEGER:
36 if len(param.Int64Value) > 0 {
37 attrs[param.Parameter] = int32(param.Int64Value[0])
38 }
39 }
40 }
41
42 // If we get a successful response, the queue manager is running
43 metrics := &QueueManagerMetrics{
44 Status: 1,
45 ConnectionCount: NotCollected, // Default to not collected
46 StartDate: NotCollected, // Default to not collected
47 StartTime: NotCollected, // Default to not collected
48 Uptime: NotCollected, // Default to not collected
49 }
50
51 // Extract connection count if available (only from MQCMD_INQUIRE_Q_MGR_STATUS)
52 if connectionCount, ok := attrs[ibmmq.MQIACF_CONNECTION_COUNT]; ok {
53 if count, ok := connectionCount.(int32); ok {
54 metrics.ConnectionCount = AttributeValue(count)
55 c.protocol.Debugf("QMGR '%s' connection count: %d", c.config.QueueManager, count)
56 }
57 } else {
58 c.protocol.Debugf("QMGR '%s' - MQIACF_CONNECTION_COUNT (value %d) not found in response", c.config.QueueManager, ibmmq.MQIACF_CONNECTION_COUNT)
59 }
60
61 // Extract queue manager start date and time for uptime calculation
62 var startDate, startTime string
63
64 // Try to get start date (constant 3175 = MQCACF_Q_MGR_START_DATE)
65 if date, ok := attrs[int32(3175)]; ok {
66 c.protocol.Debugf("Found attribute 3175, type: %T, value: %v", date, date)
67 if dateStr, ok := date.(string); ok {
68 startDate = dateStr
69 metrics.StartDate = AttributeValue(len(dateStr)) // Store length as indicator
70 c.protocol.Debugf("QMGR '%s' start date: %s", c.config.QueueManager, dateStr)
71 } else {
72 c.protocol.Warningf("QMGR: Attribute 3175 is not a string, type: %T", date)
73 }
74 } else {
75 c.protocol.Warningf("UPTIME DEBUG: QMGR '%s' - start date (attribute 3175) not found in response with %d attributes", c.config.QueueManager, len(attrs))
76 }
77
78 // Try to get start time (constant should be around 3176, but let's check for common values)
79 // Check for possible start time constants
80 timeConstants := []int32{3176, 3177, 3178} // Possible values near start date
81 for _, timeConstant := range timeConstants {
82 if time, ok := attrs[timeConstant]; ok {
83 if timeStr, ok := time.(string); ok {
84 startTime = timeStr
85 metrics.StartTime = AttributeValue(len(timeStr)) // Store length as indicator
86 c.protocol.Debugf("QMGR '%s' start time: %s (attribute %d)", c.config.QueueManager, timeStr, int32(timeConstant))
87 break
88 }
89 }
90 }
91 if startTime == "" {
92 c.protocol.Debugf("QMGR '%s' - start time not found in response", c.config.QueueManager)
93 }
94
95 // Calculate uptime if date is available (assume start time 00:00:00 if not provided)
96 if startDate != "" {
97 if startTime == "" {
98 // If no start time provided, assume start of day (00:00:00)
99 startTime = "00:00:00"
100 c.protocol.Debugf("QMGR '%s' - no start time found, assuming 00:00:00", c.config.QueueManager)
101 }
102 if uptime, err := CalculateUptimeSeconds(startDate, startTime); err == nil {
103 metrics.Uptime = AttributeValue(uptime)
104 c.protocol.Debugf("QMGR '%s' uptime: %d seconds", c.config.QueueManager, uptime)
105 } else {
106 c.protocol.Warningf("QMGR failed to calculate uptime for queue manager '%s': %v", c.config.QueueManager, err)
107 }
108 } else {
109 c.protocol.Warningf("QMGR '%s' - no start date available for uptime calculation", c.config.QueueManager)
110 }
111
112 return metrics, nil
113 }
114
115 // refreshStaticDataFromPCF refreshes cached static data using PCF commands (called from connection.go)
116 func (c *Client) refreshStaticDataFromPCF() error {
117 c.protocol.Debugf("Refreshing static data for queue manager '%s' after connection", c.config.QueueManager)
118
119 // Get queue manager version and platform info
120 response, err := c.sendPCFCommand(ibmmq.MQCMD_INQUIRE_Q_MGR, nil)
121 if err != nil {
122 return fmt.Errorf("failed to get queue manager info for '%s': %w", c.config.QueueManager, err)
123 }
124
125 attrs := make(map[int32]interface{})
126 for _, param := range response {
127 switch param.Type {
128 case ibmmq.MQCFT_STRING:
129 if len(param.String) > 0 {
130 attrs[param.Parameter] = param.String[0]
131 }
132 case ibmmq.MQCFT_INTEGER:
133 if len(param.Int64Value) > 0 {
134 attrs[param.Parameter] = int32(param.Int64Value[0])
135 }
136 }
137 }
138
139 // Extract and cache version info
140 if cmdLevel, ok := attrs[ibmmq.MQIA_COMMAND_LEVEL]; ok {
141 if level, ok := cmdLevel.(int32); ok {
142 c.cachedCommandLevel = level
143 // Convert command level to version string
144 major := level / 100
145 minor := (level % 100) / 10
146 c.cachedVersion = fmt.Sprintf("%d.%d", major, minor)
147 c.protocol.Debugf("QMGR '%s' version detected: %s (command level: %d)",
148 c.config.QueueManager, c.cachedVersion, level)
149 }
150 }
151
152 // Extract platform info
153 if platform, ok := attrs[ibmmq.MQIA_PLATFORM]; ok {
154 if plat, ok := platform.(int32); ok {
155 c.cachedPlatform = plat
156 // Use IBM library to get the correct platform name
157 platformName := ibmmq.MQItoString("PL", int(plat))
158 c.cachedEdition = platformName
159 c.protocol.Debugf("QMGR '%s' platform detected: %s (platform code: %d)",
160 c.config.QueueManager, platformName, plat)
161 }
162 }
163
164 // Extract STATINT (Statistics Interval) using official IBM MQ constant
165 // MQIA_STATISTICS_INTERVAL = 131 (X'00000083') - Controls statistics publishing interval
166 if statInt, ok := attrs[ibmmq.MQIA_STATISTICS_INTERVAL]; ok {
167 if interval, ok := statInt.(int32); ok && interval > 0 {
168 c.cachedStatisticsInterval = interval
169 c.protocol.Debugf("QMGR '%s' STATINT detected: %d seconds (MQIA_STATISTICS_INTERVAL=%d)",
170 c.config.QueueManager, interval, ibmmq.MQIA_STATISTICS_INTERVAL)
171 }
172 } else {
173 c.protocol.Debugf("QMGR '%s' STATINT not available (MQIA_STATISTICS_INTERVAL not in response)", c.config.QueueManager)
174 }
175
176 // Extract queue monitoring interval using MQIA_MONITORING_Q = 123
177 if queueMonInt, ok := attrs[int32(123)]; ok {
178 if interval, ok := queueMonInt.(int32); ok && interval >= 0 {
179 c.cachedMonitoringQueue = interval
180 c.protocol.Debugf("QMGR '%s' queue monitoring interval detected: %d seconds (MQIA_MONITORING_Q=123)",
181 c.config.QueueManager, interval)
182 }
183 } else {
184 c.protocol.Debugf("QMGR '%s' queue monitoring interval not available (MQIA_MONITORING_Q not in response)", c.config.QueueManager)
185 }
186
187 // Extract channel monitoring interval using MQIA_MONITORING_CHANNEL = 122
188 if channelMonInt, ok := attrs[int32(122)]; ok {
189 if interval, ok := channelMonInt.(int32); ok && interval >= 0 {
190 c.cachedMonitoringChannel = interval
191 c.protocol.Debugf("QMGR '%s' channel monitoring interval detected: %d seconds (MQIA_MONITORING_CHANNEL=122)",
192 c.config.QueueManager, interval)
193 }
194 } else {
195 c.protocol.Debugf("QMGR '%s' channel monitoring interval not available (MQIA_MONITORING_CHANNEL not in response)", c.config.QueueManager)
196 }
197
198 // Extract auto-defined cluster sender channel monitoring interval using MQIA_MONITORING_AUTO_CLUSSDR = 124
199 if clussdrMonInt, ok := attrs[int32(124)]; ok {
200 if interval, ok := clussdrMonInt.(int32); ok && interval >= 0 {
201 c.cachedMonitoringAutoClussdr = interval
202 c.protocol.Debugf("QMGR '%s' auto cluster sender channel monitoring interval detected: %d seconds (MQIA_MONITORING_AUTO_CLUSSDR=124)",
203 c.config.QueueManager, interval)
204 }
205 } else {
206 c.protocol.Debugf("QMGR '%s' auto cluster sender channel monitoring interval not available (MQIA_MONITORING_AUTO_CLUSSDR not in response)", c.config.QueueManager)
207 }
208
209 // For $SYS topic interval, we'll use a default of 10 seconds as per IBM documentation
210 // This interval is typically not exposed as a queue manager attribute but is configurable
211 // The default publication frequency to $SYS/ topics is approximately every 10 seconds
212 c.cachedSysTopicInterval = 10
213 c.protocol.Debugf("QMGR '%s' $SYS topic interval set to default: %d seconds (configurable, see IBM MQ documentation)",
214 c.config.QueueManager, c.cachedSysTopicInterval)
215
216 c.protocol.Debugf("QMGR static data refreshed for queue manager '%s' - version: %s, platform: %s, STATINT: %d, MONQ: %d, MONCH: %d, MONCLS: %d, SYSTOPIC: %d",
217 c.config.QueueManager, c.cachedVersion, c.cachedEdition, c.cachedStatisticsInterval,
218 c.cachedMonitoringQueue, c.cachedMonitoringChannel, c.cachedMonitoringAutoClussdr, c.cachedSysTopicInterval)
219
220 return nil
221 }