diff --git a/ibm-mq-metrics/config.yml b/ibm-mq-metrics/config.yml index 69e99e6cf..6f2b50e46 100644 --- a/ibm-mq-metrics/config.yml +++ b/ibm-mq-metrics/config.yml @@ -186,6 +186,8 @@ metrics: enabled: true "ibm.mq.heartbeat": # Queue manager heartbeat enabled: true + "ibm.mq.queue_manager.uptime": # Queue manager uptime + enabled: true "ibm.mq.archive.log.size": # Queue manager archive log size enabled: true "ibm.mq.manager.max.active.channels": # Queue manager max active channels diff --git a/ibm-mq-metrics/model/metrics.yaml b/ibm-mq-metrics/model/metrics.yaml index cfdfca3f2..e9cdeaa9c 100644 --- a/ibm-mq-metrics/model/metrics.yaml +++ b/ibm-mq-metrics/model/metrics.yaml @@ -533,6 +533,16 @@ groups: attributes: - ref: ibm.mq.queue.manager requirement_level: required + - id: ibm.mq.queue_manager.uptime + type: metric + metric_name: ibm.mq.queue_manager.uptime + stability: development + brief: "Queue manager uptime" + instrument: counter + unit: "s" + attributes: + - ref: ibm.mq.queue.manager + requirement_level: required - id: ibm.mq.archive.log.size type: metric metric_name: ibm.mq.archive.log.size diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metrics/Metrics.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metrics/Metrics.java index b5c5f3c87..adfe58153 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metrics/Metrics.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metrics/Metrics.java @@ -360,6 +360,14 @@ public static LongGauge createIbmMqHeartbeat(Meter meter) { .build(); } + public static LongCounter createIbmMqQueueManagerUptime(Meter meter) { + return meter + .counterBuilder("ibm.mq.queue_manager.uptime") + .setUnit("s") + .setDescription("Queue manager uptime") + .build(); + } + public static LongGauge createIbmMqArchiveLogSize(Meter meter) { return meter .gaugeBuilder("ibm.mq.archive.log.size") diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metrics/MetricsConfig.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metrics/MetricsConfig.java index 2b4c09958..f2bc14c85 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metrics/MetricsConfig.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metrics/MetricsConfig.java @@ -171,6 +171,10 @@ public boolean isIbmMqHeartbeatEnabled() { return isEnabled("ibm.mq.heartbeat"); } + public boolean isIbmMqQueueManagerUptimeEnabled() { + return isEnabled("ibm.mq.queue_manager.uptime"); + } + public boolean isIbmMqArchiveLogSizeEnabled() { return isEnabled("ibm.mq.archive.log.size"); } diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MessageBuddy.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MessageBuddy.java index 688f9541d..248190965 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MessageBuddy.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MessageBuddy.java @@ -11,6 +11,8 @@ import com.ibm.mq.headers.pcf.PCFException; import com.ibm.mq.headers.pcf.PCFMessage; import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; public final class MessageBuddy { @@ -72,4 +74,29 @@ public static long channelStartTime(PCFMessage message) throws PCFException { public static String jobName(PCFMessage message) throws PCFException { return message.getStringParameterValue(CMQCFC.MQCACH_MCA_JOB_NAME).trim(); } + + /** + * Calculate the queue manager uptime in seconds. + * + *

Fetches the queue manager start date and time from the PCF response, parses them, and + * calculates the difference from the current system time. + * + * @param message the PCF response message containing queue manager information + * @return uptime in seconds since the queue manager started + * @throws PCFException if the required attributes cannot be retrieved from the PCF message + */ + public static long queueManagerUptime(PCFMessage message) throws PCFException { + String date = message.getStringParameterValue(CMQCFC.MQCACF_Q_MGR_START_DATE).trim(); + String time = message.getStringParameterValue(CMQCFC.MQCACF_Q_MGR_START_TIME).trim(); + + // Parse the date (format: yyyy-MM-dd) and time (format: HH.mm.ss) + // The queue manager start timestamp does not include timezone information in this PCF response, + // so we normalize to UTC for a stable and predictable baseline across regions. + LocalDateTime qmgrStartLocal = LocalDateTime.parse(date + "T" + time.replaceAll("\\.", ":")); + Instant qmgrStartInstant = qmgrStartLocal.toInstant(ZoneOffset.UTC); + Instant now = Instant.now(); + + // Calculate uptime in seconds + return now.getEpochSecond() - qmgrStartInstant.getEpochSecond(); + } } diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerMetricsCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerMetricsCollector.java index 2b3d57086..e79f6e14f 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerMetricsCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerMetricsCollector.java @@ -11,6 +11,7 @@ import com.ibm.mq.constants.CMQCFC; import com.ibm.mq.headers.pcf.PCFMessage; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongCounter; import io.opentelemetry.api.metrics.LongGauge; import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.ibm.mq.metrics.Metrics; @@ -30,6 +31,7 @@ public final class QueueManagerMetricsCollector implements Consumer metricsList = new ArrayList<>(singletonList("ibm.mq.manager.status")); - + long managerStatus = Long.MIN_VALUE; + long queueManagerUptime = Long.MIN_VALUE; for (MetricData metric : otelTesting.getMetrics()) { - if (metricsList.remove(metric.getName())) { - assertThat(metric.getLongGaugeData().getPoints().iterator().next().getValue()).isEqualTo(2); + if ("ibm.mq.manager.status".equals(metric.getName())) { + managerStatus = metric.getLongGaugeData().getPoints().iterator().next().getValue(); + } + if ("ibm.mq.queue_manager.uptime".equals(metric.getName())) { + queueManagerUptime = metric.getLongSumData().getPoints().iterator().next().getValue(); } } - assertThat(metricsList).isEmpty(); + assertThat(managerStatus).isEqualTo(2); + assertThat(queueManagerUptime).isGreaterThan(0); } /* Request @@ -115,6 +116,8 @@ private static PCFMessage[] createPCFResponseForInquireQMgrStatusCmd() { response1.addParameter(CMQCFC.MQIACF_RESTART_LOG_SIZE, 42); response1.addParameter(CMQCFC.MQIACF_REUSABLE_LOG_SIZE, 42); response1.addParameter(CMQCFC.MQIACF_ARCHIVE_LOG_SIZE, 42); + response1.addParameter(CMQCFC.MQCACF_Q_MGR_START_DATE, "2024-01-01"); + response1.addParameter(CMQCFC.MQCACF_Q_MGR_START_TIME, "12.00.00"); return new PCFMessage[] {response1}; } diff --git a/ibm-mq-metrics/src/test/resources/conf/config.yml b/ibm-mq-metrics/src/test/resources/conf/config.yml index 07b177098..cf9f5a7ea 100644 --- a/ibm-mq-metrics/src/test/resources/conf/config.yml +++ b/ibm-mq-metrics/src/test/resources/conf/config.yml @@ -178,6 +178,8 @@ metrics: enabled: true "ibm.mq.heartbeat": # Queue manager heartbeat enabled: true + "ibm.mq.queue_manager.uptime": # Queue manager uptime + enabled: true "ibm.mq.archive.log.size": # Queue manager archive log size enabled: true "ibm.mq.manager.max.active.channels": # Queue manager max active channels