From f0bfd46b1cdaa422ca15779e24fb2a2f50a8bb92 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 13 Jun 2025 13:03:06 -0700 Subject: [PATCH 01/66] first pass addition --- ibm-mq-metrics/build.gradle.kts | 79 ++++ .../io/opentelemetry/ibm/mq/WMQContext.java | 113 +++++ .../io/opentelemetry/ibm/mq/WMQMonitor.java | 220 +++++++++ .../ibm/mq/config/ExcludeFilters.java | 93 ++++ .../ibm/mq/config/QueueManager.java | 258 +++++++++++ .../ibm/mq/config/ResourceFilters.java | 41 ++ .../opentelemetry/ibm/mq/metrics/Metrics.java | 430 ++++++++++++++++++ .../ibm/mq/metrics/MetricsConfig.java | 224 +++++++++ .../ChannelMetricsCollector.java | 238 ++++++++++ .../ibm/mq/metricscollector/FilterType.java | 24 + .../InquireChannelCmdCollector.java | 155 +++++++ .../InquireQCmdCollector.java | 79 ++++ .../InquireQStatusCmdCollector.java | 84 ++++ .../InquireQueueManagerCmdCollector.java | 86 ++++ .../InquireTStatusCmdCollector.java | 144 ++++++ .../ListenerMetricsCollector.java | 121 +++++ .../ibm/mq/metricscollector/MessageBuddy.java | 85 ++++ .../mq/metricscollector/MessageFilter.java | 83 ++++ .../MetricsCollectorContext.java | 113 +++++ .../PerformanceEventQueueCollector.java | 139 ++++++ .../QueueCollectionBuddy.java | 303 ++++++++++++ .../QueueCollectorSharedState.java | 35 ++ .../QueueManagerEventCollector.java | 118 +++++ .../QueueManagerMetricsCollector.java | 121 +++++ .../QueueMetricsCollector.java | 72 +++ .../ReadConfigurationEventQueueCollector.java | 151 ++++++ .../ResetQStatsCmdCollector.java | 66 +++ .../TopicMetricsCollector.java | 36 ++ .../ibm/mq/opentelemetry/Config.java | 91 ++++ .../ibm/mq/opentelemetry/ConfigWrapper.java | 136 ++++++ .../ibm/mq/opentelemetry/Main.java | 96 ++++ .../ibm/mq/util/AuthorityEventCreator.java | 88 ++++ .../io/opentelemetry/ibm/mq/util/WMQUtil.java | 87 ++++ ibm-mq-metrics/src/main/resources/log4j2.xml | 59 +++ .../ChannelMetricsCollectorTest.java | 236 ++++++++++ .../InquireChannelCmdCollectorTest.java | 106 +++++ .../ListenerMetricsCollectorTest.java | 112 +++++ .../ibm/mq/metricscollector/MetricAssert.java | 48 ++ .../QueueCollectionBuddyTest.java | 364 +++++++++++++++ .../QueueManagerMetricsCollectorTest.java | 130 ++++++ .../TopicMetricsCollectorTest.java | 121 +++++ .../ibm/mq/opentelemetry/ConfigTest.java | 65 +++ .../mq/opentelemetry/ConfigWrapperTest.java | 59 +++ .../src/test/resources/conf/config.yml | 217 +++++++++ ibm-mq-metrics/src/test/resources/log4j.xml | 36 ++ settings.gradle.kts | 1 + 46 files changed, 5763 insertions(+) create mode 100644 ibm-mq-metrics/build.gradle.kts create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WMQContext.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WMQMonitor.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/ExcludeFilters.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/QueueManager.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/ResourceFilters.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metrics/Metrics.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metrics/MetricsConfig.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollector.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/FilterType.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollector.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQCmdCollector.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQStatusCmdCollector.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQueueManagerCmdCollector.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireTStatusCmdCollector.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollector.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MessageBuddy.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MessageFilter.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MetricsCollectorContext.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/PerformanceEventQueueCollector.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectorSharedState.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerEventCollector.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerMetricsCollector.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueMetricsCollector.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ReadConfigurationEventQueueCollector.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ResetQStatsCmdCollector.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/TopicMetricsCollector.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Config.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapper.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/AuthorityEventCreator.java create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/WMQUtil.java create mode 100644 ibm-mq-metrics/src/main/resources/log4j2.xml create mode 100644 ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollectorTest.java create mode 100644 ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollectorTest.java create mode 100644 ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollectorTest.java create mode 100644 ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/MetricAssert.java create mode 100644 ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java create mode 100644 ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerMetricsCollectorTest.java create mode 100644 ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/TopicMetricsCollectorTest.java create mode 100644 ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigTest.java create mode 100644 ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java create mode 100644 ibm-mq-metrics/src/test/resources/conf/config.yml create mode 100644 ibm-mq-metrics/src/test/resources/log4j.xml diff --git a/ibm-mq-metrics/build.gradle.kts b/ibm-mq-metrics/build.gradle.kts new file mode 100644 index 000000000..00f3e8274 --- /dev/null +++ b/ibm-mq-metrics/build.gradle.kts @@ -0,0 +1,79 @@ +plugins { + application + id("com.github.johnrengelman.shadow") + id("otel.java-conventions") + id("otel.publish-conventions") +} + +description = "IBM-MQ metrics" +otelJava.moduleName.set("io.opentelemetry.contrib.jmxscraper") +application.mainClass.set("io.opentelemetry.contrib.jmxscraper.JmxScraper") + +sourceSets { + create("integrationTest") { + compileClasspath += sourceSets.main.get().output + runtimeClasspath += sourceSets.main.get().output + } +} + +val integrationTestImplementation by configurations.getting { + extendsFrom(configurations.implementation.get()) +} +val integrationTestRuntimeOnly by configurations.getting + +configurations["integrationTestRuntimeOnly"].extendsFrom(configurations.runtimeOnly.get()) + +val ibmClientJar: Configuration by configurations.creating { + isCanBeResolved = true + isCanBeConsumed = false +} + +dependencies { + api("com.google.code.findbugs:jsr305:3.0.2") + api("io.swagger:swagger-annotations:1.6.16") + api("org.jetbrains:annotations:26.0.2") + api("com.ibm.mq:com.ibm.mq.allclient:9.4.2.1") + api("org.yaml:snakeyaml:2.4") + api("com.fasterxml.jackson.core:jackson-databind:2.19.0") + api("io.opentelemetry:opentelemetry-sdk") + api("io.opentelemetry:opentelemetry-exporter-otlp") + api("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") + api("org.slf4j:slf4j-api:2.0.7") +// api(libs.org.apache.logging.log4j.log4j.api) +// api(libs.org.apache.logging.log4j.log4j.core) +// api(libs.org.apache.logging.log4j.log4j.slf4j2.impl) +// api(libs.org.json.json) +// testImplementation(libs.org.junit.jupiter.junit.jupiter.api) +// testImplementation(libs.org.junit.jupiter.junit.jupiter.params) +// testImplementation(libs.org.mockito.mockito.core) +// testImplementation(libs.org.mockito.mockito.junit.jupiter) +// testImplementation(libs.org.assertj.assertj.core) +// testImplementation(libs.io.opentelemetry.opentelemetry.sdk.testing) +// testImplementation(libs.com.ibm.mq.com.ibm.mq.jakarta.client) +// testImplementation(libs.jakarta.jms.jakarta.jms.api) +// testImplementation(libs.org.junit.jupiter.junit.jupiter.engine) +// testRuntimeOnly(libs.org.junit.platform.junit.platform.launcher) +// integrationTestImplementation(libs.org.assertj.assertj.core) +// integrationTestImplementation(libs.org.junit.jupiter.junit.jupiter.api) +// integrationTestImplementation(libs.io.opentelemetry.opentelemetry.sdk.testing) +// integrationTestImplementation(libs.com.ibm.mq.com.ibm.mq.jakarta.client) +// integrationTestImplementation(libs.jakarta.jms.jakarta.jms.api) +// integrationTestImplementation(libs.org.junit.jupiter.junit.jupiter.engine) +// integrationTestRuntimeOnly(libs.org.junit.platform.junit.platform.launcher) + ibmClientJar("com.ibm.mq:com.ibm.mq.allclient:9.4.2.1") { + artifact { + name = "com.ibm.mq.allclient" + extension = "jar" + } + isTransitive = false + } + +} + +tasks.shadowJar { + dependencies { + exclude(dependency("com.ibm.mq:com.ibm.mq.allclient:9.4.2.1")) + } +} + + diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WMQContext.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WMQContext.java new file mode 100644 index 000000000..1c8d407de --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WMQContext.java @@ -0,0 +1,113 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq; + +import com.ibm.mq.constants.CMQC; +import io.opentelemetry.ibm.mq.config.QueueManager; +import java.util.Hashtable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Takes care of websphere mq connection, authentication, SSL, Cipher spec, certificate based + * authorization.
+ * It also validates the arguments passed for various scenarios. + */ +public class WMQContext { + private static final String TRANSPORT_TYPE_CLIENT = "Client"; + private static final String TRANSPORT_TYPE_BINDINGS = "Bindings"; + + public static final Logger logger = LoggerFactory.getLogger(WMQContext.class); + private final QueueManager queueManager; + + public WMQContext(QueueManager queueManager) { + this.queueManager = queueManager; + validateArgs(); + } + + public Hashtable getMQEnvironment() { + Hashtable env = new Hashtable<>(); + addEnvProperty(env, CMQC.HOST_NAME_PROPERTY, queueManager.getHost()); + addEnvProperty(env, CMQC.PORT_PROPERTY, queueManager.getPort()); + addEnvProperty(env, CMQC.CHANNEL_PROPERTY, queueManager.getChannelName()); + addEnvProperty(env, CMQC.USER_ID_PROPERTY, queueManager.getUsername()); + addEnvProperty(env, CMQC.PASSWORD_PROPERTY, queueManager.getPassword()); + addEnvProperty(env, CMQC.SSL_CERT_STORE_PROPERTY, queueManager.getSslKeyRepository()); + addEnvProperty(env, CMQC.SSL_CIPHER_SUITE_PROPERTY, queueManager.getCipherSuite()); + // TODO: investigate on CIPHER_SPEC property No Available in MQ 7.5 Jar + + if (TRANSPORT_TYPE_CLIENT.equalsIgnoreCase(queueManager.getTransportType())) { + addEnvProperty(env, CMQC.TRANSPORT_PROPERTY, CMQC.TRANSPORT_MQSERIES_CLIENT); + } else if (TRANSPORT_TYPE_BINDINGS.equalsIgnoreCase(queueManager.getTransportType())) { + addEnvProperty(env, CMQC.TRANSPORT_PROPERTY, CMQC.TRANSPORT_MQSERIES_BINDINGS); + } else { + addEnvProperty(env, CMQC.TRANSPORT_PROPERTY, CMQC.TRANSPORT_MQSERIES); + } + + if (logger.isDebugEnabled()) { + logger.debug("Transport property is {}", env.get(CMQC.TRANSPORT_PROPERTY)); + } + return env; + } + + @SuppressWarnings({"unused", "unchecked", "rawtypes"}) + private void addEnvProperty(Hashtable env, String propName, Object propVal) { + if (null != propVal) { + if (propVal instanceof String) { + String propString = (String) propVal; + if (propString.isEmpty()) { + return; + } + } + env.put(propName, propVal); + } + } + + private void validateArgs() { + boolean validArgs = true; + StringBuilder errorMsg = new StringBuilder(); + if (queueManager == null) { + validArgs = false; + errorMsg.append("Queue manager cannot be null"); + } else { + if (TRANSPORT_TYPE_CLIENT.equalsIgnoreCase(queueManager.getTransportType())) { + if (queueManager.getHost() == null || queueManager.getHost().trim().isEmpty()) { + validArgs = false; + errorMsg.append("Host cannot be null or empty for client type connection. "); + } + if (queueManager.getPort() == -1) { + validArgs = false; + errorMsg.append("port should be set for client type connection. "); + } + if (queueManager.getChannelName() == null + || queueManager.getChannelName().trim().isEmpty()) { + validArgs = false; + errorMsg.append("Channel cannot be null or empty for client type connection. "); + } + } + if (TRANSPORT_TYPE_BINDINGS.equalsIgnoreCase(queueManager.getTransportType())) { + if (queueManager.getName() == null || queueManager.getName().trim().isEmpty()) { + validArgs = false; + errorMsg.append("queuemanager cannot be null or empty for bindings type connection. "); + } + } + } + + if (!validArgs) { + throw new IllegalArgumentException(errorMsg.toString()); + } + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WMQMonitor.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WMQMonitor.java new file mode 100644 index 000000000..e169c7269 --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WMQMonitor.java @@ -0,0 +1,220 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ibm.mq.MQQueueManager; +import com.ibm.mq.headers.pcf.PCFMessageAgent; +import io.opentelemetry.ibm.mq.config.QueueManager; +import io.opentelemetry.ibm.mq.metrics.MetricsConfig; +import io.opentelemetry.ibm.mq.metricscollector.*; +import io.opentelemetry.ibm.mq.metricscollector.ChannelMetricsCollector; +import io.opentelemetry.ibm.mq.metricscollector.InquireChannelCmdCollector; +import io.opentelemetry.ibm.mq.metricscollector.InquireQueueManagerCmdCollector; +import io.opentelemetry.ibm.mq.metricscollector.ListenerMetricsCollector; +import io.opentelemetry.ibm.mq.metricscollector.MetricsCollectorContext; +import io.opentelemetry.ibm.mq.metricscollector.PerformanceEventQueueCollector; +import io.opentelemetry.ibm.mq.metricscollector.QueueManagerEventCollector; +import io.opentelemetry.ibm.mq.metricscollector.QueueManagerMetricsCollector; +import io.opentelemetry.ibm.mq.metricscollector.QueueMetricsCollector; +import io.opentelemetry.ibm.mq.metricscollector.ReadConfigurationEventQueueCollector; +import io.opentelemetry.ibm.mq.metricscollector.TopicMetricsCollector; +import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; +import io.opentelemetry.ibm.mq.util.WMQUtil; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongGauge; +import io.opentelemetry.api.metrics.Meter; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.function.Consumer; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class WMQMonitor { + + private static final Logger logger = LoggerFactory.getLogger(WMQMonitor.class); + + private final List queueManagers; + private final List> jobs = new ArrayList<>(); + private final LongGauge heartbeatGauge; + private final ExecutorService threadPool; + private final MetricsConfig metricsConfig; + + public WMQMonitor(ConfigWrapper config, ExecutorService threadPool, Meter meter) { + List> queueManagers = getQueueManagers(config); + ObjectMapper mapper = new ObjectMapper(); + + this.queueManagers = new ArrayList<>(); + + for (Map queueManager : queueManagers) { + try { + QueueManager qManager = mapper.convertValue(queueManager, QueueManager.class); + this.queueManagers.add(qManager); + } catch (Throwable t) { + logger.error("Error preparing queue manager {}", queueManager, t); + } + } + + this.metricsConfig = new MetricsConfig(config); + + this.heartbeatGauge = meter.gaugeBuilder("mq.heartbeat").setUnit("1").ofLongs().build(); + this.threadPool = threadPool; + + jobs.add(new QueueManagerMetricsCollector(meter)); + jobs.add(new InquireQueueManagerCmdCollector(meter)); + jobs.add(new ChannelMetricsCollector(meter)); + jobs.add(new InquireChannelCmdCollector(meter)); + jobs.add(new QueueMetricsCollector(meter, threadPool, config)); + jobs.add(new ListenerMetricsCollector(meter)); + jobs.add(new TopicMetricsCollector(meter)); + jobs.add(new ReadConfigurationEventQueueCollector(meter)); + jobs.add(new PerformanceEventQueueCollector(meter)); + jobs.add(new QueueManagerEventCollector(meter)); + } + + public void run() { + for (QueueManager qm : this.queueManagers) { + run(qm); + } + } + + @NotNull + private List> getQueueManagers(ConfigWrapper config) { + List> queueManagers = config.getQueueManagers(); + if (queueManagers.isEmpty()) { + throw new IllegalStateException( + "The 'queueManagers' section in config.yml is empty or otherwise incorrect."); + } + return queueManagers; + } + + public void run(QueueManager queueManager) { + String queueManagerName = queueManager.getName(); + logger.debug("WMQMonitor thread for queueManager {} started.", queueManagerName); + long startTime = System.currentTimeMillis(); + MQQueueManager ibmQueueManager = null; + PCFMessageAgent agent = null; + int heartBeatMetricValue = 0; + try { + ibmQueueManager = WMQUtil.connectToQueueManager(queueManager); + heartBeatMetricValue = 1; + agent = WMQUtil.initPCFMessageAgent(queueManager, ibmQueueManager); + extractAndReportMetrics(ibmQueueManager, queueManager, agent); + } catch (Exception e) { + logger.error( + "Error connecting to QueueManager {} by thread {}: {}", + queueManagerName, + Thread.currentThread().getName(), + e.getMessage(), + e); + } finally { + if (this.metricsConfig.isMqHeartbeatEnabled()) { + heartbeatGauge.set( + heartBeatMetricValue, + Attributes.of(AttributeKey.stringKey("queue.manager"), queueManagerName)); + } + cleanUp(ibmQueueManager, agent); + long endTime = System.currentTimeMillis() - startTime; + logger.debug( + "WMQMonitor thread for queueManager {} ended. Time taken = {} ms", + queueManagerName, + endTime); + } + } + + private void extractAndReportMetrics( + MQQueueManager mqQueueManager, QueueManager queueManager, PCFMessageAgent agent) { + logger.debug("Queueing {} jobs", jobs.size()); + MetricsCollectorContext context = + new MetricsCollectorContext(queueManager, agent, mqQueueManager, this.metricsConfig); + List> tasks = new ArrayList<>(); + for (Consumer collector : jobs) { + tasks.add( + () -> { + try { + long startTime = System.currentTimeMillis(); + collector.accept(context); + long diffTime = System.currentTimeMillis() - startTime; + if (diffTime > 60000L) { + logger.warn( + "{} Task took {} ms to complete", + collector.getClass().getSimpleName(), + diffTime); + } else { + logger.debug( + "{} Task took {} ms to complete", + collector.getClass().getSimpleName(), + diffTime); + } + } catch (Exception e) { + logger.error( + "Error while running task name = " + collector.getClass().getSimpleName(), e); + } + return null; + }); + } + + try { + this.threadPool.invokeAll(tasks); + } catch (InterruptedException e) { + logger.error("Error while the thread {} is waiting ", Thread.currentThread().getName(), e); + } + } + + /** Destroy the agent and disconnect from queue manager */ + private void cleanUp(MQQueueManager ibmQueueManager, PCFMessageAgent agent) { + // Disconnect the agent. + + if (agent != null) { + String qMgrName = agent.getQManagerName(); + try { + agent.disconnect(); + logger.debug( + "PCFMessageAgent disconnected for queueManager {} in thread {}", + qMgrName, + Thread.currentThread().getName()); + } catch (Exception e) { + logger.error( + "Error occurred while disconnecting PCFMessageAgent for queueManager {} in thread {}", + qMgrName, + Thread.currentThread().getName(), + e); + } + } + + // Disconnect queue manager + if (ibmQueueManager != null) { + String name = ""; + try { + name = ibmQueueManager.getName(); + ibmQueueManager.disconnect(); + // logger.debug("Connection disconnected for queue manager {} in thread {}", + // ibmQueueManager.getName(), Thread.currentThread().getName()); + } catch (Exception e) { + logger.error( + "Error occurred while disconnecting queueManager {} in thread {}", + name, + Thread.currentThread().getName(), + e); + } + } + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/ExcludeFilters.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/ExcludeFilters.java new file mode 100644 index 000000000..bac0d3232 --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/ExcludeFilters.java @@ -0,0 +1,93 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.config; + +import io.opentelemetry.ibm.mq.metricscollector.FilterType; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +public class ExcludeFilters { + + private String type; + private Set values = new HashSet<>(); + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Set getValues() { + return values; + } + + public void setValues(Set values) { + this.values = values; + } + + public static boolean isExcluded(String resourceName, Collection excludeFilters) { + if (excludeFilters == null) { + return false; + } + for (ExcludeFilters filter : excludeFilters) { + if (filter.isExcluded(resourceName)) { + return true; + } + } + return false; + } + + public boolean isExcluded(String resourceName) { + if (resourceName == null || resourceName.isEmpty()) { + return true; + } + switch (FilterType.valueOf(type)) { + case CONTAINS: + for (String filterValue : values) { + if (resourceName.contains(filterValue)) { + return true; + } + } + break; + case STARTSWITH: + for (String filterValue : values) { + if (resourceName.startsWith(filterValue)) { + return true; + } + } + break; + case NONE: + return false; + case EQUALS: + for (String filterValue : values) { + if (resourceName.equals(filterValue)) { + return true; + } + } + break; + case ENDSWITH: + for (String filterValue : values) { + if (resourceName.endsWith(filterValue)) { + return true; + } + } + } + return false; + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/QueueManager.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/QueueManager.java new file mode 100644 index 000000000..8a64928c1 --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/QueueManager.java @@ -0,0 +1,258 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.config; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class QueueManager { + + private String host; + private int port = -1; + private String name; + private String channelName; + private String transportType; + private String username; + private String password; + private String sslKeyRepository; + private int ccsid = Integer.MIN_VALUE; + private int encoding = Integer.MIN_VALUE; + private String cipherSuite; + private String cipherSpec; + private String replyQueuePrefix; + private String modelQueueName; + private String configurationQueueName = "SYSTEM.ADMIN.CONFIG.EVENT"; + private String performanceEventsQueueName = "SYSTEM.ADMIN.PERFM.EVENT"; + private String queueManagerEventsQueueName = "SYSTEM.ADMIN.QMGR.EVENT"; + private long consumeConfigurationEventInterval; + private boolean refreshQueueManagerConfigurationEnabled; + // Config default is 100. + // https://www.ibm.com/docs/en/ibm-mq/9.3.x?topic=qmini-channels-stanza-file + private int maxActiveChannels = 100; + + private ResourceFilters queueFilters; + private ResourceFilters channelFilters; + private ResourceFilters listenerFilters; + private ResourceFilters topicFilters; + + List writeStatsDirectory; + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getChannelName() { + return channelName; + } + + public void setChannelName(String channelName) { + this.channelName = channelName; + } + + public String getTransportType() { + return transportType; + } + + public void setTransportType(String transportType) { + this.transportType = transportType; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public ResourceFilters getQueueFilters() { + if (queueFilters == null) { + return new ResourceFilters(); + } + return queueFilters; + } + + public void setQueueFilters(ResourceFilters queueFilters) { + this.queueFilters = queueFilters; + } + + public String getSslKeyRepository() { + return sslKeyRepository; + } + + public void setSslKeyRepository(String sslKeyRepository) { + this.sslKeyRepository = sslKeyRepository; + } + + public String getCipherSuite() { + return cipherSuite; + } + + public void setCipherSuite(String cipherSuite) { + this.cipherSuite = cipherSuite; + } + + public String getCipherSpec() { + return cipherSpec; + } + + public void setCipherSpec(String cipherSpec) { + this.cipherSpec = cipherSpec; + } + + public ResourceFilters getChannelFilters() { + if (channelFilters == null) { + return new ResourceFilters(); + } + return channelFilters; + } + + public void setChannelFilters(ResourceFilters channelFilters) { + this.channelFilters = channelFilters; + } + + public String getReplyQueuePrefix() { + return replyQueuePrefix; + } + + public void setReplyQueuePrefix(String replyQueuePrefix) { + this.replyQueuePrefix = replyQueuePrefix; + } + + public String getModelQueueName() { + return modelQueueName; + } + + public void setModelQueueName(String modelQueueName) { + this.modelQueueName = modelQueueName; + } + + public ResourceFilters getListenerFilters() { + if (listenerFilters == null) { + return new ResourceFilters(); + } + return listenerFilters; + } + + public void setListenerFilters(ResourceFilters listenerFilters) { + this.listenerFilters = listenerFilters; + } + + public int getCcsid() { + return ccsid; + } + + public void setCcsid(int ccsid) { + this.ccsid = ccsid; + } + + public int getEncoding() { + return encoding; + } + + public void setEncoding(int encoding) { + this.encoding = encoding; + } + + public ResourceFilters getTopicFilters() { + if (topicFilters == null) { + return new ResourceFilters(); + } + return topicFilters; + } + + public void setTopicFilters(ResourceFilters topicFilters) { + this.topicFilters = topicFilters; + } + + public String getConfigurationQueueName() { + return this.configurationQueueName; + } + + public void setConfigurationQueueName(String configurationQueueName) { + this.configurationQueueName = configurationQueueName; + } + + public long getConsumeConfigurationEventInterval() { + return this.consumeConfigurationEventInterval; + } + + public void setConsumeConfigurationEventInterval(long consumeConfigurationEventInterval) { + this.consumeConfigurationEventInterval = consumeConfigurationEventInterval; + } + + public boolean isRefreshQueueManagerConfigurationEnabled() { + return refreshQueueManagerConfigurationEnabled; + } + + public void setRefreshQueueManagerConfigurationEnabled( + boolean refreshQueueManagerConfigurationEnabled) { + this.refreshQueueManagerConfigurationEnabled = refreshQueueManagerConfigurationEnabled; + } + + public String getPerformanceEventsQueueName() { + return performanceEventsQueueName; + } + + public void setPerformanceEventsQueueName(String performanceEventsQueueName) { + this.performanceEventsQueueName = performanceEventsQueueName; + } + + public String getQueueManagerEventsQueueName() { + return this.queueManagerEventsQueueName; + } + + public void setQueueManagerEventsQueueName(String queueManagerEventsQueueName) { + this.queueManagerEventsQueueName = queueManagerEventsQueueName; + } + + public int getMaxActiveChannels() { + return maxActiveChannels; + } + + public void setMaxActiveChannels(int maxActiveChannels) { + this.maxActiveChannels = maxActiveChannels; + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/ResourceFilters.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/ResourceFilters.java new file mode 100644 index 000000000..77e475d2c --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/ResourceFilters.java @@ -0,0 +1,41 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.config; + +import java.util.HashSet; +import java.util.Set; + +public class ResourceFilters { + + private Set include = new HashSet<>(); + private Set exclude = new HashSet<>(); + + public Set getInclude() { + return include; + } + + public void setInclude(Set include) { + this.include = include; + } + + public Set getExclude() { + return exclude; + } + + public void setExclude(Set exclude) { + this.exclude = exclude; + } +} 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 new file mode 100644 index 000000000..2aa6e839c --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metrics/Metrics.java @@ -0,0 +1,430 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metrics; + +import io.opentelemetry.api.metrics.LongCounter; +import io.opentelemetry.api.metrics.LongGauge; +import io.opentelemetry.api.metrics.Meter; + +// This file is generated using weaver. Do not edit manually. + +/** Metric definitions generated from a Weaver model. Do not edit manually. */ +public class Metrics { + + public static LongGauge createMqMessageRetryCount(Meter meter) { + return meter + .gaugeBuilder("mq.message.retry.count") + .ofLongs() + .setUnit("{messages}") + .setDescription("Number of message retries") + .build(); + } + + public static LongGauge createMqStatus(Meter meter) { + return meter + .gaugeBuilder("mq.status") + .ofLongs() + .setUnit("1") + .setDescription("Channel status") + .build(); + } + + public static LongGauge createMqMaxSharingConversations(Meter meter) { + return meter + .gaugeBuilder("mq.max.sharing.conversations") + .ofLongs() + .setUnit("{conversations}") + .setDescription("Maximum number of conversations permitted on this channel instance.") + .build(); + } + + public static LongGauge createMqCurrentSharingConversations(Meter meter) { + return meter + .gaugeBuilder("mq.current.sharing.conversations") + .ofLongs() + .setUnit("{conversations}") + .setDescription("Current number of conversations permitted on this channel instance.") + .build(); + } + + public static LongGauge createMqByteReceived(Meter meter) { + return meter + .gaugeBuilder("mq.byte.received") + .ofLongs() + .setUnit("{bytes}") + .setDescription("Number of bytes received") + .build(); + } + + public static LongGauge createMqByteSent(Meter meter) { + return meter + .gaugeBuilder("mq.byte.sent") + .ofLongs() + .setUnit("{bytes}") + .setDescription("Number of bytes sent") + .build(); + } + + public static LongGauge createMqBuffersReceived(Meter meter) { + return meter + .gaugeBuilder("mq.buffers.received") + .ofLongs() + .setUnit("{buffers}") + .setDescription("Buffers received") + .build(); + } + + public static LongGauge createMqBuffersSent(Meter meter) { + return meter + .gaugeBuilder("mq.buffers.sent") + .ofLongs() + .setUnit("{buffers}") + .setDescription("Buffers sent") + .build(); + } + + public static LongGauge createMqMessageCount(Meter meter) { + return meter + .gaugeBuilder("mq.message.count") + .ofLongs() + .setUnit("{messages}") + .setDescription("Message count") + .build(); + } + + public static LongGauge createMqOpenInputCount(Meter meter) { + return meter + .gaugeBuilder("mq.open.input.count") + .ofLongs() + .setUnit("{applications}") + .setDescription("Count of applications sending messages to the queue") + .build(); + } + + public static LongGauge createMqOpenOutputCount(Meter meter) { + return meter + .gaugeBuilder("mq.open.output.count") + .ofLongs() + .setUnit("{applications}") + .setDescription("Count of applications consuming messages from the queue") + .build(); + } + + public static LongGauge createMqHighQueueDepth(Meter meter) { + return meter + .gaugeBuilder("mq.high.queue.depth") + .ofLongs() + .setUnit("{percent}") + .setDescription("The current high queue depth") + .build(); + } + + public static LongGauge createMqServiceInterval(Meter meter) { + return meter + .gaugeBuilder("mq.service.interval") + .ofLongs() + .setUnit("{percent}") + .setDescription("The queue service interval") + .build(); + } + + public static LongCounter createMqQueueDepthFullEvent(Meter meter) { + return meter + .counterBuilder("mq.queue.depth.full.event") + .setUnit("{events}") + .setDescription("The number of full queue events") + .build(); + } + + public static LongCounter createMqQueueDepthHighEvent(Meter meter) { + return meter + .counterBuilder("mq.queue.depth.high.event") + .setUnit("{events}") + .setDescription("The number of high queue events") + .build(); + } + + public static LongCounter createMqQueueDepthLowEvent(Meter meter) { + return meter + .counterBuilder("mq.queue.depth.low.event") + .setUnit("{events}") + .setDescription("The number of low queue events") + .build(); + } + + public static LongGauge createMqUncommittedMessages(Meter meter) { + return meter + .gaugeBuilder("mq.uncommitted.messages") + .ofLongs() + .setUnit("{messages}") + .setDescription("Number of uncommitted messages") + .build(); + } + + public static LongGauge createMqOldestMsgAge(Meter meter) { + return meter + .gaugeBuilder("mq.oldest.msg.age") + .ofLongs() + .setUnit("microseconds") + .setDescription("Queue message oldest age") + .build(); + } + + public static LongGauge createMqCurrentMaxQueueFilesize(Meter meter) { + return meter + .gaugeBuilder("mq.current.max.queue.filesize") + .ofLongs() + .setUnit("mib") + .setDescription("Current maximum queue file size") + .build(); + } + + public static LongGauge createMqCurrentQueueFilesize(Meter meter) { + return meter + .gaugeBuilder("mq.current.queue.filesize") + .ofLongs() + .setUnit("mib") + .setDescription("Current queue file size") + .build(); + } + + public static LongGauge createMqInstancesPerClient(Meter meter) { + return meter + .gaugeBuilder("mq.instances.per.client") + .ofLongs() + .setUnit("{instances}") + .setDescription("Instances per client") + .build(); + } + + public static LongGauge createMqMessageDeqCount(Meter meter) { + return meter + .gaugeBuilder("mq.message.deq.count") + .ofLongs() + .setUnit("{messages}") + .setDescription("Message dequeue count") + .build(); + } + + public static LongGauge createMqMessageEnqCount(Meter meter) { + return meter + .gaugeBuilder("mq.message.enq.count") + .ofLongs() + .setUnit("{messages}") + .setDescription("Message enqueue count") + .build(); + } + + public static LongGauge createMqQueueDepth(Meter meter) { + return meter + .gaugeBuilder("mq.queue.depth") + .ofLongs() + .setUnit("{messages}") + .setDescription("Current queue depth") + .build(); + } + + public static LongGauge createMqServiceIntervalEvent(Meter meter) { + return meter + .gaugeBuilder("mq.service.interval.event") + .ofLongs() + .setUnit("1") + .setDescription("Queue service interval event") + .build(); + } + + public static LongGauge createMqReusableLogSize(Meter meter) { + return meter + .gaugeBuilder("mq.reusable.log.size") + .ofLongs() + .setUnit("mib") + .setDescription( + "The amount of space occupied, in megabytes, by log extents available to be reused.") + .build(); + } + + public static LongGauge createMqManagerActiveChannels(Meter meter) { + return meter + .gaugeBuilder("mq.manager.active.channels") + .ofLongs() + .setUnit("{channels}") + .setDescription("The queue manager active maximum channels limit") + .build(); + } + + public static LongGauge createMqRestartLogSize(Meter meter) { + return meter + .gaugeBuilder("mq.restart.log.size") + .ofLongs() + .setUnit("mib") + .setDescription("Size of the log data required for restart recovery in megabytes.") + .build(); + } + + public static LongGauge createMqMaxQueueDepth(Meter meter) { + return meter + .gaugeBuilder("mq.max.queue.depth") + .ofLongs() + .setUnit("{messages}") + .setDescription("Maximum queue depth") + .build(); + } + + public static LongGauge createMqOnqtime1(Meter meter) { + return meter + .gaugeBuilder("mq.onqtime.1") + .ofLongs() + .setUnit("microseconds") + .setDescription( + "Amount of time, in microseconds, that a message spent on the queue, over a short period") + .build(); + } + + public static LongGauge createMqOnqtime2(Meter meter) { + return meter + .gaugeBuilder("mq.onqtime.2") + .ofLongs() + .setUnit("microseconds") + .setDescription( + "Amount of time, in microseconds, that a message spent on the queue, over a longer period") + .build(); + } + + public static LongGauge createMqMessageReceivedCount(Meter meter) { + return meter + .gaugeBuilder("mq.message.received.count") + .ofLongs() + .setUnit("{messages}") + .setDescription("Number of messages received") + .build(); + } + + public static LongGauge createMqMessageSentCount(Meter meter) { + return meter + .gaugeBuilder("mq.message.sent.count") + .ofLongs() + .setUnit("{messages}") + .setDescription("Number of messages sent") + .build(); + } + + public static LongGauge createMqMaxInstances(Meter meter) { + return meter + .gaugeBuilder("mq.max.instances") + .ofLongs() + .setUnit("{instances}") + .setDescription("Max channel instances") + .build(); + } + + public static LongGauge createMqConnectionCount(Meter meter) { + return meter + .gaugeBuilder("mq.connection.count") + .ofLongs() + .setUnit("{connections}") + .setDescription("Active connections count") + .build(); + } + + public static LongGauge createMqManagerStatus(Meter meter) { + return meter + .gaugeBuilder("mq.manager.status") + .ofLongs() + .setUnit("1") + .setDescription("Queue manager status") + .build(); + } + + public static LongGauge createMqHeartbeat(Meter meter) { + return meter + .gaugeBuilder("mq.heartbeat") + .ofLongs() + .setUnit("1") + .setDescription("Queue manager heartbeat") + .build(); + } + + public static LongGauge createMqArchiveLogSize(Meter meter) { + return meter + .gaugeBuilder("mq.archive.log.size") + .ofLongs() + .setUnit("mib") + .setDescription("Queue manager archive log size") + .build(); + } + + public static LongGauge createMqManagerMaxActiveChannels(Meter meter) { + return meter + .gaugeBuilder("mq.manager.max.active.channels") + .ofLongs() + .setUnit("{channels}") + .setDescription("Queue manager max active channels") + .build(); + } + + public static LongGauge createMqManagerStatisticsInterval(Meter meter) { + return meter + .gaugeBuilder("mq.manager.statistics.interval") + .ofLongs() + .setUnit("1") + .setDescription("Queue manager statistics interval") + .build(); + } + + public static LongGauge createMqPublishCount(Meter meter) { + return meter + .gaugeBuilder("mq.publish.count") + .ofLongs() + .setUnit("{publications}") + .setDescription("Topic publication count") + .build(); + } + + public static LongGauge createMqSubscriptionCount(Meter meter) { + return meter + .gaugeBuilder("mq.subscription.count") + .ofLongs() + .setUnit("{subscriptions}") + .setDescription("Topic subscription count") + .build(); + } + + public static LongGauge createMqListenerStatus(Meter meter) { + return meter + .gaugeBuilder("mq.listener.status") + .ofLongs() + .setUnit("1") + .setDescription("Listener status") + .build(); + } + + public static LongCounter createMqUnauthorizedEvent(Meter meter) { + return meter + .counterBuilder("mq.unauthorized.event") + .setUnit("{events}") + .setDescription("Number of authentication error events") + .build(); + } + + public static LongGauge createMqManagerMaxHandles(Meter meter) { + return meter + .gaugeBuilder("mq.manager.max.handles") + .ofLongs() + .setUnit("{events}") + .setDescription("Max open handles") + .build(); + } +} 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 new file mode 100644 index 000000000..b42543680 --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metrics/MetricsConfig.java @@ -0,0 +1,224 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metrics; + +import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; +import java.util.Map; + +// This file is generated using weaver. Do not edit manually. + +/** Configuration of metrics as defined in config.yml. */ +public class MetricsConfig { + + private final Map config; + + public MetricsConfig(ConfigWrapper config) { + this.config = config.getMetrics(); + } + + public boolean isMqMessageRetryCountEnabled() { + String key = "mq.message.retry.count"; + return isEnabled(key); + } + + public boolean isMqStatusEnabled() { + return isEnabled("mq.status"); + } + + public boolean isMqMaxSharingConversationsEnabled() { + return isEnabled("mq.max.sharing.conversations"); + } + + public boolean isMqCurrentSharingConversationsEnabled() { + return isEnabled("mq.current.sharing.conversations"); + } + + public boolean isMqByteReceivedEnabled() { + return isEnabled("mq.byte.received"); + } + + public boolean isMqByteSentEnabled() { + return isEnabled("mq.byte.sent"); + } + + public boolean isMqBuffersReceivedEnabled() { + return isEnabled("mq.buffers.received"); + } + + public boolean isMqBuffersSentEnabled() { + return isEnabled("mq.buffers.sent"); + } + + public boolean isMqMessageCountEnabled() { + return isEnabled("mq.message.count"); + } + + public boolean isMqOpenInputCountEnabled() { + return isEnabled("mq.open.input.count"); + } + + public boolean isMqOpenOutputCountEnabled() { + return isEnabled("mq.open.output.count"); + } + + public boolean isMqHighQueueDepthEnabled() { + return isEnabled("mq.high.queue.depth"); + } + + public boolean isMqServiceIntervalEnabled() { + return isEnabled("mq.service.interval"); + } + + public boolean isMqQueueDepthFullEventEnabled() { + return isEnabled("mq.queue.depth.full.event"); + } + + public boolean isMqQueueDepthHighEventEnabled() { + return isEnabled("mq.queue.depth.high.event"); + } + + public boolean isMqQueueDepthLowEventEnabled() { + return isEnabled("mq.queue.depth.low.event"); + } + + public boolean isMqUncommittedMessagesEnabled() { + return isEnabled("mq.uncommitted.messages"); + } + + public boolean isMqOldestMsgAgeEnabled() { + return isEnabled("mq.oldest.msg.age"); + } + + public boolean isMqCurrentMaxQueueFilesizeEnabled() { + return isEnabled("mq.current.max.queue.filesize"); + } + + public boolean isMqCurrentQueueFilesizeEnabled() { + return isEnabled("mq.current.queue.filesize"); + } + + public boolean isMqInstancesPerClientEnabled() { + return isEnabled("mq.instances.per.client"); + } + + public boolean isMqMessageDeqCountEnabled() { + return isEnabled("mq.message.deq.count"); + } + + public boolean isMqMessageEnqCountEnabled() { + return isEnabled("mq.message.enq.count"); + } + + public boolean isMqQueueDepthEnabled() { + return isEnabled("mq.queue.depth"); + } + + public boolean isMqServiceIntervalEventEnabled() { + return isEnabled("mq.service.interval.event"); + } + + public boolean isMqReusableLogSizeEnabled() { + return isEnabled("mq.reusable.log.size"); + } + + public boolean isMqManagerActiveChannelsEnabled() { + return isEnabled("mq.manager.active.channels"); + } + + public boolean isMqRestartLogSizeEnabled() { + return isEnabled("mq.restart.log.size"); + } + + public boolean isMqMaxQueueDepthEnabled() { + return isEnabled("mq.max.queue.depth"); + } + + public boolean isMqOnqtime1Enabled() { + return isEnabled("mq.onqtime.1"); + } + + public boolean isMqOnqtime2Enabled() { + return isEnabled("mq.onqtime.2"); + } + + public boolean isMqMessageReceivedCountEnabled() { + return isEnabled("mq.message.received.count"); + } + + public boolean isMqMessageSentCountEnabled() { + return isEnabled("mq.message.sent.count"); + } + + public boolean isMqMaxInstancesEnabled() { + return isEnabled("mq.max.instances"); + } + + public boolean isMqConnectionCountEnabled() { + return isEnabled("mq.connection.count"); + } + + public boolean isMqManagerStatusEnabled() { + return isEnabled("mq.manager.status"); + } + + public boolean isMqHeartbeatEnabled() { + return isEnabled("mq.heartbeat"); + } + + public boolean isMqArchiveLogSizeEnabled() { + return isEnabled("mq.archive.log.size"); + } + + public boolean isMqManagerMaxActiveChannelsEnabled() { + return isEnabled("mq.manager.max.active.channels"); + } + + public boolean isMqManagerStatisticsIntervalEnabled() { + return isEnabled("mq.manager.statistics.interval"); + } + + public boolean isMqPublishCountEnabled() { + return isEnabled("mq.publish.count"); + } + + public boolean isMqSubscriptionCountEnabled() { + return isEnabled("mq.subscription.count"); + } + + public boolean isMqListenerStatusEnabled() { + return isEnabled("mq.listener.status"); + } + + public boolean isMqUnauthorizedEventEnabled() { + return isEnabled("mq.unauthorized.event"); + } + + public boolean isMqManagerMaxHandlesEnabled() { + return isEnabled("mq.manager.max.handles"); + } + + private boolean isEnabled(String key) { + Object metricInfo = config.get(key); + if (!(metricInfo instanceof Map)) { + return false; + } + Object enabled = ((Map) metricInfo).get("enabled"); + if (enabled instanceof Boolean) { + return (Boolean) enabled; + } + return false; + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollector.java new file mode 100644 index 000000000..6da3d335d --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollector.java @@ -0,0 +1,238 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import static com.ibm.mq.constants.CMQC.MQRC_SELECTOR_ERROR; +import static com.ibm.mq.constants.CMQCFC.MQRCCF_CHL_STATUS_NOT_FOUND; + +import com.ibm.mq.constants.CMQC; +import com.ibm.mq.constants.CMQCFC; +import com.ibm.mq.headers.pcf.PCFException; +import com.ibm.mq.headers.pcf.PCFMessage; +import io.opentelemetry.ibm.mq.metrics.Metrics; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongGauge; +import io.opentelemetry.api.metrics.Meter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** This class is responsible for channel metric collection. */ +public final class ChannelMetricsCollector implements Consumer { + + private static final Logger logger = LoggerFactory.getLogger(ChannelMetricsCollector.class); + + private final LongGauge activeChannelsGauge; + private final LongGauge channelStatusGauge; + private final LongGauge messageCountGauge; + private final LongGauge byteSentGauge; + private final LongGauge byteReceivedGauge; + private final LongGauge buffersSentGauge; + private final LongGauge buffersReceivedGauge; + private final LongGauge currentSharingConvsGauge; + private final LongGauge maxSharingConvsGauge; + + /* + * The Channel Status values are mentioned here http://www.ibm.com/support/knowledgecenter/SSFKSJ_7.5.0/com.ibm.mq.ref.dev.doc/q090880_.htm + */ + public ChannelMetricsCollector(Meter meter) { + this.activeChannelsGauge = Metrics.createMqManagerActiveChannels(meter); + this.channelStatusGauge = Metrics.createMqStatus(meter); + this.messageCountGauge = Metrics.createMqMessageCount(meter); + this.byteSentGauge = Metrics.createMqByteSent(meter); + this.byteReceivedGauge = Metrics.createMqByteReceived(meter); + this.buffersSentGauge = Metrics.createMqBuffersSent(meter); + this.buffersReceivedGauge = Metrics.createMqBuffersReceived(meter); + this.currentSharingConvsGauge = Metrics.createMqCurrentSharingConversations(meter); + this.maxSharingConvsGauge = Metrics.createMqMaxSharingConversations(meter); + } + + @Override + public void accept(MetricsCollectorContext context) { + logger.info("Collecting metrics for command MQCMD_INQUIRE_CHANNEL_STATUS"); + long entryTime = System.currentTimeMillis(); + + int[] attrs = + new int[] { + CMQCFC.MQCACH_CHANNEL_NAME, + CMQCFC.MQCACH_CONNECTION_NAME, + CMQCFC.MQIACH_CHANNEL_TYPE, + CMQCFC.MQIACH_MSGS, + CMQCFC.MQIACH_CHANNEL_STATUS, + CMQCFC.MQIACH_BYTES_SENT, + CMQCFC.MQIACH_BYTES_RECEIVED, + CMQCFC.MQIACH_BUFFERS_SENT, + CMQCFC.MQIACH_BUFFERS_RECEIVED, + CMQCFC.MQIACH_CURRENT_SHARING_CONVS, + CMQCFC.MQIACH_MAX_SHARING_CONVS, + CMQCFC.MQCACH_CHANNEL_START_DATE, + CMQCFC.MQCACH_CHANNEL_START_TIME, + CMQCFC.MQCACH_MCA_JOB_NAME + }; + if (logger.isDebugEnabled()) { + logger.debug( + "Attributes being sent along PCF agent request to query channel metrics: {}", + Arrays.toString(attrs)); + } + + Set channelGenericNames = context.getChannelIncludeFilterNames(); + + // + // The MQCMD_INQUIRE_CHANNEL_STATUS command queries the current operational status of channels. + // This includes information about whether a channel is running, stopped, or in another state, + // as well as details about the channel’s performance and usage. + List activeChannels = new ArrayList<>(); + for (String channelGenericName : channelGenericNames) { + PCFMessage request = new PCFMessage(CMQCFC.MQCMD_INQUIRE_CHANNEL_STATUS); + request.addParameter(CMQCFC.MQCACH_CHANNEL_NAME, channelGenericName); + request.addParameter(CMQCFC.MQIACH_CHANNEL_INSTANCE_TYPE, CMQC.MQOT_CURRENT_CHANNEL); + request.addParameter(CMQCFC.MQIACH_CHANNEL_INSTANCE_ATTRS, attrs); + try { + logger.debug( + "sending PCF agent request to query metrics for generic channel {}", + channelGenericName); + long startTime = System.currentTimeMillis(); + List response = context.send(request); + long endTime = System.currentTimeMillis() - startTime; + logger.debug( + "PCF agent queue metrics query response for generic queue {} received in {} milliseconds", + channelGenericName, + endTime); + if (response.isEmpty()) { + logger.debug("Unexpected error while PCFMessage.send(), response is empty"); + return; + } + + List messages = + MessageFilter.ofKind("channel") + .excluding(context.getChannelExcludeFilters()) + .withResourceExtractor(MessageBuddy::channelName) + .filter(response); + + for (PCFMessage message : messages) { + String channelName = MessageBuddy.channelName(message); + String channelType = MessageBuddy.channelType(message); + long channelStartTime = MessageBuddy.channelStartTime(message); + String jobName = MessageBuddy.jobName(message); + + logger.debug("Pulling out metrics for channel name {}", channelName); + updateMetrics( + context, + message, + channelName, + channelType, + channelStartTime, + jobName, + activeChannels); + } + } catch (PCFException pcfe) { + if (pcfe.getReason() == MQRCCF_CHL_STATUS_NOT_FOUND) { + String errorMsg = "Channel- " + channelGenericName + " :"; + errorMsg += + "Could not collect channel information as channel is stopped or inactive: Reason '3065'\n"; + errorMsg += + "If the channel type is MQCHT_RECEIVER, MQCHT_SVRCONN or MQCHT_CLUSRCVR, then the only action is to enable the channel, not start it."; + logger.error(errorMsg, pcfe); + } else if (pcfe.getReason() == MQRC_SELECTOR_ERROR) { + logger.error( + "Invalid metrics passed while collecting channel metrics, check config.yaml: Reason '2067'", + pcfe); + } else { + logger.error(pcfe.getMessage(), pcfe); + } + } catch (Exception e) { + logger.error( + "Unexpected error occurred while collecting metrics for channel " + channelGenericName, + e); + } + } + + logger.info( + "Active Channels in queueManager {} are {}", context.getQueueManagerName(), activeChannels); + activeChannelsGauge.set( + activeChannels.size(), + Attributes.of(AttributeKey.stringKey("queue.manager"), context.getQueueManagerName())); + + long exitTime = System.currentTimeMillis() - entryTime; + logger.debug("Time taken to publish metrics for all channels is {} milliseconds", exitTime); + } + + private void updateMetrics( + MetricsCollectorContext context, + PCFMessage message, + String channelName, + String channelType, + long channelStartTime, + String jobName, + List activeChannels) + throws PCFException { + Attributes attributes = + Attributes.builder() + .put("channel.name", channelName) + .put("channel.type", channelType) + .put("queue.manager", context.getQueueManagerName()) + .put("channel.start.time", channelStartTime) + .put("job.name", jobName) + .build(); + if (context.getMetricsConfig().isMqMessageCountEnabled()) { + int received = message.getIntParameterValue(CMQCFC.MQIACH_MSGS); + messageCountGauge.set(received, attributes); + } + int status = message.getIntParameterValue(CMQCFC.MQIACH_CHANNEL_STATUS); + if (context.getMetricsConfig().isMqStatusEnabled()) { + channelStatusGauge.set(status, attributes); + } + // We follow the definition of active channel as documented in + // https://www.ibm.com/docs/en/ibm-mq/9.2.x?topic=states-current-active + if (status != CMQCFC.MQCHS_RETRYING + && status != CMQCFC.MQCHS_STOPPED + && status != CMQCFC.MQCHS_STARTING) { + activeChannels.add(channelName); + } + if (context.getMetricsConfig().isMqByteSentEnabled()) { + byteSentGauge.set(message.getIntParameterValue(CMQCFC.MQIACH_BYTES_SENT), attributes); + } + if (context.getMetricsConfig().isMqByteReceivedEnabled()) { + byteReceivedGauge.set(message.getIntParameterValue(CMQCFC.MQIACH_BYTES_RECEIVED), attributes); + } + if (context.getMetricsConfig().isMqBuffersSentEnabled()) { + buffersSentGauge.set(message.getIntParameterValue(CMQCFC.MQIACH_BUFFERS_SENT), attributes); + } + if (context.getMetricsConfig().isMqBuffersReceivedEnabled()) { + buffersReceivedGauge.set( + message.getIntParameterValue(CMQCFC.MQIACH_BUFFERS_RECEIVED), attributes); + } + if (context.getMetricsConfig().isMqCurrentSharingConversationsEnabled()) { + int currentSharingConvs = 0; + if (message.getParameter(CMQCFC.MQIACH_CURRENT_SHARING_CONVS) != null) { + currentSharingConvs = message.getIntParameterValue(CMQCFC.MQIACH_CURRENT_SHARING_CONVS); + } + currentSharingConvsGauge.set(currentSharingConvs, attributes); + } + if (context.getMetricsConfig().isMqMaxSharingConversationsEnabled()) { + int maxSharingConvs = 0; + if (message.getParameter(CMQCFC.MQIACH_MAX_SHARING_CONVS) != null) { + maxSharingConvs = message.getIntParameterValue(CMQCFC.MQIACH_MAX_SHARING_CONVS); + } + maxSharingConvsGauge.set(maxSharingConvs, attributes); + } + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/FilterType.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/FilterType.java new file mode 100644 index 000000000..8d8d83839 --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/FilterType.java @@ -0,0 +1,24 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +public enum FilterType { + STARTSWITH, + EQUALS, + ENDSWITH, + CONTAINS, + NONE +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollector.java new file mode 100644 index 000000000..92ec77f67 --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollector.java @@ -0,0 +1,155 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import com.ibm.mq.constants.CMQCFC; +import com.ibm.mq.constants.MQConstants; +import com.ibm.mq.headers.pcf.MQCFIL; +import com.ibm.mq.headers.pcf.PCFException; +import com.ibm.mq.headers.pcf.PCFMessage; +import io.opentelemetry.ibm.mq.metrics.Metrics; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongGauge; +import io.opentelemetry.api.metrics.Meter; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** This class is responsible for channel inquiry metric collection. */ +public final class InquireChannelCmdCollector implements Consumer { + + public static final Logger logger = LoggerFactory.getLogger(InquireChannelCmdCollector.class); + private final LongGauge maxClientsGauge; + private final LongGauge instancesPerClientGauge; + private final LongGauge messageRetryCountGauge; + private final LongGauge messageReceivedCountGauge; + private final LongGauge messageSentCountGauge; + + public InquireChannelCmdCollector(Meter meter) { + this.maxClientsGauge = Metrics.createMqMaxInstances(meter); + this.instancesPerClientGauge = Metrics.createMqInstancesPerClient(meter); + this.messageRetryCountGauge = Metrics.createMqMessageRetryCount(meter); + this.messageReceivedCountGauge = Metrics.createMqMessageReceivedCount(meter); + this.messageSentCountGauge = Metrics.createMqMessageSentCount(meter); + } + + @Override + public void accept(MetricsCollectorContext context) { + long entryTime = System.currentTimeMillis(); + + Set channelGenericNames = context.getChannelIncludeFilterNames(); + + for (String channelGenericName : channelGenericNames) { + PCFMessage request = new PCFMessage(CMQCFC.MQCMD_INQUIRE_CHANNEL); + request.addParameter(CMQCFC.MQCACH_CHANNEL_NAME, channelGenericName); + request.addParameter( + new MQCFIL(MQConstants.MQIACF_CHANNEL_ATTRS, new int[] {MQConstants.MQIACF_ALL})); + try { + logger.debug( + "sending PCF agent request to query metrics for generic channel {}", + channelGenericName); + long startTime = System.currentTimeMillis(); + List response = context.send(request); + long endTime = System.currentTimeMillis() - startTime; + logger.debug( + "PCF agent queue metrics query response for generic queue {} received in {} milliseconds", + channelGenericName, + endTime); + if (response.isEmpty()) { + logger.warn("Unexpected error while PCFMessage.send(), response is empty"); + return; + } + + List messages = + MessageFilter.ofKind("channel") + .excluding(context.getChannelExcludeFilters()) + .withResourceExtractor(MessageBuddy::channelName) + .filter(response); + + for (PCFMessage message : messages) { + String channelName = MessageBuddy.channelName(message); + String channelType = MessageBuddy.channelType(message); + logger.debug("Pulling out metrics for channel name {}", channelName); + updateMetrics(message, channelName, channelType, context); + } + } catch (PCFException pcfe) { + if (pcfe.getReason() == MQConstants.MQRCCF_CHL_STATUS_NOT_FOUND) { + String errorMsg = "Channel- " + channelGenericName + " :"; + errorMsg += + "Could not collect channel information as channel is stopped or inactive: Reason '3065'\n"; + errorMsg += + "If the channel type is MQCHT_RECEIVER, MQCHT_SVRCONN or MQCHT_CLUSRCVR, then the only action is to enable the channel, not start it."; + logger.error(errorMsg, pcfe); + } else if (pcfe.getReason() == MQConstants.MQRC_SELECTOR_ERROR) { + logger.error( + "Invalid metrics passed while collecting channel metrics, check config.yaml: Reason '2067'", + pcfe); + } + logger.error(pcfe.getMessage(), pcfe); + } catch (Exception e) { + logger.error( + "Unexpected error while collecting metrics for channel " + channelGenericName, e); + } + } + + long exitTime = System.currentTimeMillis() - entryTime; + logger.debug("Time taken to publish metrics for all channels is {} milliseconds", exitTime); + } + + private void updateMetrics( + PCFMessage message, String channelName, String channelType, MetricsCollectorContext context) + throws PCFException { + Attributes attributes = + Attributes.builder() + .put("channel.name", channelName) + .put("channel.type", channelType) + .put("queue.manager", context.getQueueManagerName()) + .build(); + if (context.getMetricsConfig().isMqMaxInstancesEnabled() + && message.getParameter(CMQCFC.MQIACH_MAX_INSTANCES) != null) { + this.maxClientsGauge.set( + message.getIntParameterValue(CMQCFC.MQIACH_MAX_INSTANCES), attributes); + } + if (context.getMetricsConfig().isMqInstancesPerClientEnabled() + && message.getParameter(CMQCFC.MQIACH_MAX_INSTS_PER_CLIENT) != null) { + this.instancesPerClientGauge.set( + message.getIntParameterValue(CMQCFC.MQIACH_MAX_INSTS_PER_CLIENT), attributes); + } + if (context.getMetricsConfig().isMqMessageRetryCountEnabled()) { + int count = 0; + if (message.getParameter(CMQCFC.MQIACH_MR_COUNT) != null) { + count = message.getIntParameterValue(CMQCFC.MQIACH_MR_COUNT); + } + this.messageRetryCountGauge.set(count, attributes); + } + if (context.getMetricsConfig().isMqInstancesPerClientEnabled()) { + int received = 0; + if (message.getParameter(CMQCFC.MQIACH_MSGS_RECEIVED) != null) { + received = message.getIntParameterValue(CMQCFC.MQIACH_MSGS_RECEIVED); + } + this.messageReceivedCountGauge.set(received, attributes); + } + if (context.getMetricsConfig().isMqMessageSentCountEnabled()) { + int sent = 0; + if (message.getParameter(CMQCFC.MQIACH_MSGS_SENT) != null) { + sent = message.getIntParameterValue(CMQCFC.MQIACH_MSGS_SENT); + } + this.messageSentCountGauge.set(sent, attributes); + } + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQCmdCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQCmdCollector.java new file mode 100644 index 000000000..89973ec65 --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQCmdCollector.java @@ -0,0 +1,79 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import com.ibm.mq.constants.CMQC; +import com.ibm.mq.constants.CMQCFC; +import com.ibm.mq.headers.pcf.PCFMessage; +import java.util.Arrays; +import java.util.Set; +import java.util.function.Consumer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class InquireQCmdCollector implements Consumer { + + private static final Logger logger = LoggerFactory.getLogger(InquireQCmdCollector.class); + + static final int[] ATTRIBUTES = + new int[] { + CMQC.MQCA_Q_NAME, + CMQC.MQIA_USAGE, + CMQC.MQIA_Q_TYPE, + CMQC.MQIA_CURRENT_Q_DEPTH, + CMQC.MQIA_MAX_Q_DEPTH, + CMQC.MQIA_OPEN_INPUT_COUNT, + CMQC.MQIA_OPEN_OUTPUT_COUNT, + CMQC.MQIA_Q_SERVICE_INTERVAL, + CMQC.MQIA_Q_SERVICE_INTERVAL_EVENT + }; + + static final String COMMAND = "MQCMD_INQUIRE_Q"; + private final QueueCollectionBuddy queueBuddy; + + public InquireQCmdCollector(QueueCollectionBuddy queueBuddy) { + this.queueBuddy = queueBuddy; + } + + @Override + public void accept(MetricsCollectorContext context) { + logger.info("Collecting metrics for command {}", COMMAND); + long entryTime = System.currentTimeMillis(); + + logger.debug( + "Attributes being sent along PCF agent request to query queue metrics: {} for command {}", + Arrays.toString(ATTRIBUTES), + COMMAND); + + Set queueGenericNames = context.getQueueIncludeFilterNames(); + for (String queueGenericName : queueGenericNames) { + // list of all metrics extracted through MQCMD_INQUIRE_Q is mentioned here + // https://www.ibm.com/support/knowledgecenter/SSFKSJ_7.5.0/com.ibm.mq.ref.adm.doc/q087810_.htm + PCFMessage request = new PCFMessage(CMQCFC.MQCMD_INQUIRE_Q); + request.addParameter(CMQC.MQCA_Q_NAME, queueGenericName); + request.addParameter(CMQC.MQIA_Q_TYPE, CMQC.MQQT_ALL); + request.addParameter(CMQCFC.MQIACF_Q_ATTRS, ATTRIBUTES); + + queueBuddy.processPCFRequestAndPublishQMetrics( + context, request, queueGenericName, ATTRIBUTES); + } + long exitTime = System.currentTimeMillis() - entryTime; + logger.debug( + "Time taken to publish metrics for all queues is {} milliseconds for command {}", + exitTime, + COMMAND); + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQStatusCmdCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQStatusCmdCollector.java new file mode 100644 index 000000000..98a706616 --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQStatusCmdCollector.java @@ -0,0 +1,84 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import com.ibm.mq.constants.CMQC; +import com.ibm.mq.constants.CMQCFC; +import com.ibm.mq.headers.pcf.PCFMessage; +import java.util.Set; +import java.util.function.Consumer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The InquireQStatusCmdCollector class is responsible for collecting and publishing queue metrics + * using the IBM MQ command `MQCMD_INQUIRE_Q_STATUS`. It extends the QueueMetricsCollector class and + * implements the Runnable interface, enabling execution within a separate thread. + * + *

This class interacts with PCF (Programmable Command Formats) messages to query queue metrics + * based on the configuration provided. It retrieves status information about a queue, such as: • + * The number of messages on the queue • Open handles (how many apps have it open) • Whether the + * queue is in use for input/output • Last get/put timestamps • And other real-time statistics + * + *

Thread Safety: This class is thread-safe, as it operates independently with state shared only + * through immutable or synchronized structures where necessary. + * + *

Usage: - Instantiate this class by providing an existing QueueMetricsCollector instance, a map + * of metrics to report, and shared state. - Invoke the run method to execute the queue metrics + * collection process. + */ +final class InquireQStatusCmdCollector implements Consumer { + + static final int[] ATTRIBUTES = + new int[] { + CMQC.MQCA_Q_NAME, + CMQCFC.MQIACF_CUR_Q_FILE_SIZE, + CMQCFC.MQIACF_CUR_MAX_FILE_SIZE, + CMQCFC.MQIACF_OLDEST_MSG_AGE, + CMQCFC.MQIACF_UNCOMMITTED_MSGS, + CMQCFC.MQIACF_Q_TIME_INDICATOR, + CMQC.MQIA_CURRENT_Q_DEPTH, + }; + + private static final Logger logger = LoggerFactory.getLogger(InquireQStatusCmdCollector.class); + + private final QueueCollectionBuddy queueBuddy; + + InquireQStatusCmdCollector(QueueCollectionBuddy queueBuddy) { + this.queueBuddy = queueBuddy; + } + + @Override + public void accept(MetricsCollectorContext context) { + logger.info("Collecting metrics for command MQCMD_INQUIRE_Q_STATUS"); + long entryTime = System.currentTimeMillis(); + + Set queueGenericNames = context.getQueueIncludeFilterNames(); + for (String queueGenericName : queueGenericNames) { + // list of all metrics extracted through MQCMD_INQUIRE_Q_STATUS is mentioned here + // https://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.ref.adm.doc/q087880_.htm + PCFMessage request = new PCFMessage(CMQCFC.MQCMD_INQUIRE_Q_STATUS); + request.addParameter(CMQC.MQCA_Q_NAME, queueGenericName); + request.addParameter(CMQCFC.MQIACF_Q_STATUS_ATTRS, ATTRIBUTES); + queueBuddy.processPCFRequestAndPublishQMetrics( + context, request, queueGenericName, ATTRIBUTES); + } + long exitTime = System.currentTimeMillis() - entryTime; + logger.debug( + "Time taken to publish metrics for all queues is {} milliseconds for command MQCMD_INQUIRE_Q_STATUS", + exitTime); + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQueueManagerCmdCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQueueManagerCmdCollector.java new file mode 100644 index 000000000..4348396cf --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQueueManagerCmdCollector.java @@ -0,0 +1,86 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import com.ibm.mq.constants.CMQC; +import com.ibm.mq.constants.CMQCFC; +import com.ibm.mq.constants.MQConstants; +import com.ibm.mq.headers.pcf.MQCFIL; +import com.ibm.mq.headers.pcf.PCFMessage; +import io.opentelemetry.ibm.mq.metrics.Metrics; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongGauge; +import io.opentelemetry.api.metrics.Meter; +import java.util.List; +import java.util.function.Consumer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** This class is responsible for queue metric collection. */ +public final class InquireQueueManagerCmdCollector implements Consumer { + + private static final Logger logger = + LoggerFactory.getLogger(InquireQueueManagerCmdCollector.class); + private final LongGauge statisticsIntervalGauge; + + public InquireQueueManagerCmdCollector(Meter meter) { + this.statisticsIntervalGauge = Metrics.createMqManagerStatisticsInterval(meter); + } + + @Override + public void accept(MetricsCollectorContext context) { + long entryTime = System.currentTimeMillis(); + logger.debug( + "publishMetrics entry time for queuemanager {} is {} milliseconds", + context.getQueueManagerName(), + entryTime); + // CMQCFC.MQCMD_INQUIRE_Q_MGR is 2 + PCFMessage request = new PCFMessage(CMQCFC.MQCMD_INQUIRE_Q_MGR); + // request.addParameter(CMQC.MQCA_Q_MGR_NAME, "*"); + // CMQCFC.MQIACF_Q_MGR_STATUS_ATTRS is 1001 + request.addParameter( + new MQCFIL(MQConstants.MQIACF_Q_MGR_ATTRS, new int[] {MQConstants.MQIACF_ALL})); + try { + // Note that agent.send() method is synchronized + logger.debug( + "sending PCF agent request to query queuemanager {}", context.getQueueManagerName()); + long startTime = System.currentTimeMillis(); + List responses = context.send(request); + long endTime = System.currentTimeMillis() - startTime; + logger.debug( + "PCF agent queuemanager metrics query response for {} received in {} milliseconds", + context.getQueueManagerName(), + endTime); + if (responses.isEmpty()) { + logger.debug("Unexpected error while PCFMessage.send(), response is either null or empty"); + return; + } + if (context.getMetricsConfig().isMqManagerStatisticsIntervalEnabled()) { + int interval = responses.get(0).getIntParameterValue(CMQC.MQIA_STATISTICS_INTERVAL); + statisticsIntervalGauge.set( + interval, + Attributes.of(AttributeKey.stringKey("queue.manager"), context.getQueueManagerName())); + } + } catch (Exception e) { + logger.error("Error collecting QueueManagerCmd metrics", e); + throw new RuntimeException(e); + } finally { + long exitTime = System.currentTimeMillis() - entryTime; + logger.debug("Time taken to publish metrics for queuemanager is {} milliseconds", exitTime); + } + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireTStatusCmdCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireTStatusCmdCollector.java new file mode 100644 index 000000000..92ad1f884 --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireTStatusCmdCollector.java @@ -0,0 +1,144 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import com.ibm.mq.constants.CMQC; +import com.ibm.mq.constants.CMQCFC; +import com.ibm.mq.headers.MQDataException; +import com.ibm.mq.headers.pcf.PCFException; +import com.ibm.mq.headers.pcf.PCFMessage; +import io.opentelemetry.ibm.mq.metrics.Metrics; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongGauge; +import io.opentelemetry.api.metrics.Meter; +import java.io.IOException; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class InquireTStatusCmdCollector implements Consumer { + + private static final Logger logger = LoggerFactory.getLogger(InquireTStatusCmdCollector.class); + + private final LongGauge publishCountGauge; + private final LongGauge subscriptionCountGauge; + + public InquireTStatusCmdCollector(Meter meter) { + this.publishCountGauge = Metrics.createMqPublishCount(meter); + this.subscriptionCountGauge = Metrics.createMqSubscriptionCount(meter); + } + + @Override + public void accept(MetricsCollectorContext context) { + logger.info("Collecting metrics for command MQCMD_INQUIRE_TOPIC_STATUS"); + long entryTime = System.currentTimeMillis(); + + Set topicGenericNames = context.getTopicIncludeFilterNames(); + // to query the current status of topics, which is essential for monitoring and managing the + // publish/subscribe environment in IBM MQ. + for (String topicGenericName : topicGenericNames) { + // Request: + // https://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.ref.adm.doc/q088140_.htm + // list of all metrics extracted through MQCMD_INQUIRE_TOPIC_STATUS is mentioned here + // https://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.ref.adm.doc/q088150_.htm + PCFMessage request = new PCFMessage(CMQCFC.MQCMD_INQUIRE_TOPIC_STATUS); + request.addParameter(CMQC.MQCA_TOPIC_STRING, topicGenericName); + + try { + processPCFRequestAndPublishQMetrics(context, topicGenericName, request); + } catch (PCFException pcfe) { + logger.error( + "PCFException caught while collecting metric for Queue: {} for command MQCMD_INQUIRE_TOPIC_STATUS", + topicGenericName, + pcfe); + PCFMessage[] msgs = (PCFMessage[]) pcfe.exceptionSource; + for (PCFMessage msg : msgs) { + logger.error(msg.toString()); + } + // Don't throw exception as it will stop queue metric colloection + } catch (Exception mqe) { + logger.error("MQException caught", mqe); + // Dont throw exception as it will stop queuemetric colloection + } + } + long exitTime = System.currentTimeMillis() - entryTime; + logger.debug( + "Time taken to publish metrics for all queues is {} milliseconds for command MQCMD_INQUIRE_TOPIC_STATUS", + exitTime); + } + + private void processPCFRequestAndPublishQMetrics( + MetricsCollectorContext context, String topicGenericName, PCFMessage request) + throws IOException, MQDataException { + logger.debug( + "sending PCF agent request to topic metrics for generic topic {} for command MQCMD_INQUIRE_TOPIC_STATUS", + topicGenericName); + long startTime = System.currentTimeMillis(); + List response = context.send(request); + long endTime = System.currentTimeMillis() - startTime; + logger.debug( + "PCF agent topic metrics query response for generic topic {} for command MQCMD_INQUIRE_TOPIC_STATUS received in {} milliseconds", + topicGenericName, + endTime); + if (response.isEmpty()) { + logger.debug( + "Unexpected error while PCFMessage.send() for command MQCMD_INQUIRE_TOPIC_STATUS, response is either null or empty"); + return; + } + + List messages = + MessageFilter.ofKind("topic") + .excluding(context.getTopicExcludeFilters()) + .withResourceExtractor(MessageBuddy::topicName) + .filter(response); + + for (PCFMessage message : messages) { + String topicName = MessageBuddy.topicName(message); + logger.debug( + "Pulling out metrics for topic name {} for command MQCMD_INQUIRE_TOPIC_STATUS", + topicName); + extractMetrics(context, message, topicName); + } + } + + private void extractMetrics( + MetricsCollectorContext context, PCFMessage pcfMessage, String topicString) + throws PCFException { + Attributes attributes = + Attributes.of( + AttributeKey.stringKey("topic.name"), + topicString, + AttributeKey.stringKey("queue.manager"), + context.getQueueManagerName()); + if (context.getMetricsConfig().isMqPublishCountEnabled()) { + int publisherCount = 0; + if (pcfMessage.getParameter(CMQC.MQIA_PUB_COUNT) != null) { + publisherCount = pcfMessage.getIntParameterValue(CMQC.MQIA_PUB_COUNT); + } + publishCountGauge.set(publisherCount, attributes); + } + if (context.getMetricsConfig().isMqSubscriptionCountEnabled()) { + int subscriberCount = 0; + if (pcfMessage.getParameter(CMQC.MQIA_SUB_COUNT) != null) { + subscriberCount = pcfMessage.getIntParameterValue(CMQC.MQIA_SUB_COUNT); + } + subscriptionCountGauge.set(subscriberCount, attributes); + } + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollector.java new file mode 100644 index 000000000..0815bcc53 --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollector.java @@ -0,0 +1,121 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import com.ibm.mq.constants.CMQCFC; +import com.ibm.mq.headers.pcf.PCFException; +import com.ibm.mq.headers.pcf.PCFMessage; +import io.opentelemetry.ibm.mq.metrics.Metrics; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongGauge; +import io.opentelemetry.api.metrics.Meter; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * ListenerMetricsCollector is a specialized implementation of the MetricsCollector that is + * responsible for collecting and publishing metrics related to IBM MQ Listeners. + * + *

This class interacts with PCFMessageAgent to query metrics for specific listeners, applies + * "include:" and "exclude:" listenerFilters defined in config yaml, and uses MetricWriteHelper to + * publish the collected metrics in the required format. + * + *

Key functionalities include: • query using PCF Command: MQCMD_INQUIRE_LISTENER_STATUS to get + * the status of one or more listeners on a queue manager. • retrieve tcp/ip listeners runtime + * information such as: - listener is running or stopped - port number and transport type - last + * error codes - associated command server • + * + *

It utilizes WMQMetricOverride to map metrics from the configuration to their IBM MQ constants. + */ +public final class ListenerMetricsCollector implements Consumer { + + private static final Logger logger = LoggerFactory.getLogger(ListenerMetricsCollector.class); + private final LongGauge listenerStatusGauge; + + public ListenerMetricsCollector(Meter meter) { + this.listenerStatusGauge = Metrics.createMqListenerStatus(meter); + } + + @Override + public void accept(MetricsCollectorContext context) { + long entryTime = System.currentTimeMillis(); + + int[] attrs = new int[] {CMQCFC.MQCACH_LISTENER_NAME, CMQCFC.MQIACH_LISTENER_STATUS}; + logger.debug( + "Attributes being sent along PCF agent request to query channel metrics: " + + Arrays.toString(attrs)); + + Set listenerGenericNames = context.getListenerIncludeFilterNames(); + for (String listenerGenericName : listenerGenericNames) { + PCFMessage request = new PCFMessage(CMQCFC.MQCMD_INQUIRE_LISTENER_STATUS); + request.addParameter(CMQCFC.MQCACH_LISTENER_NAME, listenerGenericName); + request.addParameter(CMQCFC.MQIACF_LISTENER_STATUS_ATTRS, attrs); + try { + logger.debug( + "sending PCF agent request to query metrics for generic listener {}", + listenerGenericName); + long startTime = System.currentTimeMillis(); + List response = context.send(request); + long endTime = System.currentTimeMillis() - startTime; + logger.debug( + "PCF agent listener metrics query response for generic listener {} received in {} milliseconds", + listenerGenericName, + endTime); + if (response.isEmpty()) { + logger.debug("Unexpected error while PCFMessage.send(), response is empty"); + return; + } + + List messages = + MessageFilter.ofKind("listener") + .excluding(context.getListenerExcludeFilters()) + .withResourceExtractor(MessageBuddy::listenerName) + .filter(response); + + for (PCFMessage message : messages) { + String listenerName = MessageBuddy.listenerName(message); + logger.debug("Pulling out metrics for listener name {}", listenerName); + updateMetrics(message, listenerName, context); + } + } catch (Exception e) { + logger.error( + "Unexpected error while collecting metrics for listener " + listenerGenericName, e); + } + } + long exitTime = System.currentTimeMillis() - entryTime; + logger.debug("Time taken to publish metrics for all listener is {} milliseconds", exitTime); + } + + private void updateMetrics( + PCFMessage message, String listenerName, MetricsCollectorContext context) + throws PCFException { + if (context.getMetricsConfig().isMqListenerStatusEnabled()) { + int status = message.getIntParameterValue(CMQCFC.MQIACH_LISTENER_STATUS); + listenerStatusGauge.set( + status, + Attributes.of( + AttributeKey.stringKey("listener.name"), + listenerName, + AttributeKey.stringKey("queue.manager"), + context.getQueueManagerName())); + } + } +} 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 new file mode 100644 index 000000000..0cdeb2657 --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MessageBuddy.java @@ -0,0 +1,85 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import com.ibm.mq.constants.CMQC; +import com.ibm.mq.constants.CMQCFC; +import com.ibm.mq.constants.CMQXC; +import com.ibm.mq.headers.pcf.PCFException; +import com.ibm.mq.headers.pcf.PCFMessage; +import java.time.Instant; + +public class MessageBuddy { + + private MessageBuddy() {} + + static String channelName(PCFMessage message) throws PCFException { + return message.getStringParameterValue(CMQCFC.MQCACH_CHANNEL_NAME).trim(); + } + + static String channelType(PCFMessage message) throws PCFException { + switch (message.getIntParameterValue(CMQCFC.MQIACH_CHANNEL_TYPE)) { + case CMQXC.MQCHT_SENDER: + return "sender"; + case CMQXC.MQCHT_SERVER: + return "server"; + case CMQXC.MQCHT_RECEIVER: + return "receiver"; + case CMQXC.MQCHT_REQUESTER: + return "requester"; + case CMQXC.MQCHT_SVRCONN: + return "server-connection"; + case CMQXC.MQCHT_CLNTCONN: + return "client-connection"; + case CMQXC.MQCHT_CLUSRCVR: + return "cluster-receiver"; + case CMQXC.MQCHT_CLUSSDR: + return "cluster-sender"; + case CMQXC.MQCHT_MQTT: + return "mqtt"; + case CMQXC.MQCHT_AMQP: + return "amqp"; + default: + throw new IllegalArgumentException( + "Unsupported channel type: " + + message.getIntParameterValue(CMQCFC.MQIACH_CHANNEL_TYPE)); + } + } + + static String topicName(PCFMessage message) throws PCFException { + return message.getStringParameterValue(CMQC.MQCA_TOPIC_STRING).trim(); + } + + public static String listenerName(PCFMessage message) throws PCFException { + return message.getStringParameterValue(CMQCFC.MQCACH_LISTENER_NAME).trim(); + } + + public static String queueName(PCFMessage message) throws PCFException { + return message.getStringParameterValue(CMQC.MQCA_Q_NAME).trim(); + } + + public static long channelStartTime(PCFMessage message) throws PCFException { + String date = message.getStringParameterValue(CMQCFC.MQCACH_CHANNEL_START_DATE).trim(); + String time = message.getStringParameterValue(CMQCFC.MQCACH_CHANNEL_START_TIME).trim(); + + Instant parsed = Instant.parse(date + "T" + time.replaceAll("\\.", ":") + "Z"); + return parsed.getEpochSecond(); + } + + public static String jobName(PCFMessage message) throws PCFException { + return message.getStringParameterValue(CMQCFC.MQCACH_MCA_JOB_NAME).trim(); + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MessageFilter.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MessageFilter.java new file mode 100644 index 000000000..60baf9d76 --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MessageFilter.java @@ -0,0 +1,83 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import com.ibm.mq.headers.pcf.PCFException; +import com.ibm.mq.headers.pcf.PCFMessage; +import io.opentelemetry.ibm.mq.config.ExcludeFilters; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** Helps to consolidate repeated exclude/filtering logic. */ +class MessageFilter { + + private static final Logger logger = LoggerFactory.getLogger(MessageFilter.class); + + private final String kind; + private final Collection filters; + private final ResourceExtractor extractor; + + private MessageFilter( + String kind, Collection filters, ResourceExtractor extractor) { + this.kind = kind; + this.filters = filters; + this.extractor = extractor; + } + + static MessageFilterBuilder ofKind(String kind) { + return new MessageFilterBuilder(kind); + } + + public List filter(List messages) throws PCFException { + List result = new ArrayList<>(); + for (PCFMessage message : messages) { + String resourceName = extractor.apply(message); + if (ExcludeFilters.isExcluded(resourceName, filters)) { + logger.debug("{} name = {} is excluded.", kind, resourceName); + } else { + result.add(message); + } + } + return result; + } + + static class MessageFilterBuilder { + + private Collection filters; + private String kind; + + public MessageFilterBuilder(String kind) { + this.kind = kind; + } + + public MessageFilterBuilder excluding(Collection filters) { + this.filters = filters; + return this; + } + + public MessageFilter withResourceExtractor(ResourceExtractor extractor) { + return new MessageFilter(kind, filters, extractor); + } + } + + interface ResourceExtractor { + // Ugh, exceptions everywhere, huh? + String apply(PCFMessage message) throws PCFException; + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MetricsCollectorContext.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MetricsCollectorContext.java new file mode 100644 index 000000000..f4578ba7e --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MetricsCollectorContext.java @@ -0,0 +1,113 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import static java.util.Collections.emptyList; + +import com.ibm.mq.MQQueueManager; +import com.ibm.mq.headers.MQDataException; +import com.ibm.mq.headers.pcf.PCFMessage; +import com.ibm.mq.headers.pcf.PCFMessageAgent; +import io.opentelemetry.ibm.mq.config.ExcludeFilters; +import io.opentelemetry.ibm.mq.config.QueueManager; +import io.opentelemetry.ibm.mq.metrics.MetricsConfig; +import java.io.IOException; +import java.util.*; +import javax.annotation.concurrent.Immutable; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A temporary bundle to contain the collaborators of the original MetricsCollector base class until + * we can finish unwinding things. When done and there are no longer usages of MetricsCollector, we + * could consider renaming this. + */ +@Immutable +public final class MetricsCollectorContext { + + private static final Logger logger = LoggerFactory.getLogger(MetricsCollectorContext.class); + + private final QueueManager queueManager; + private final PCFMessageAgent agent; + private final MQQueueManager mqQueueManager; + private final MetricsConfig metricsConfig; + + public MetricsCollectorContext( + QueueManager queueManager, + PCFMessageAgent agent, + MQQueueManager mqQueueManager, + MetricsConfig metricsConfig) { + this.queueManager = queueManager; + this.agent = agent; + this.mqQueueManager = mqQueueManager; + this.metricsConfig = metricsConfig; + } + + Set getChannelIncludeFilterNames() { + return queueManager.getChannelFilters().getInclude(); + } + + Set getChannelExcludeFilters() { + return queueManager.getChannelFilters().getExclude(); + } + + Set getListenerIncludeFilterNames() { + return queueManager.getListenerFilters().getInclude(); + } + + Set getListenerExcludeFilters() { + return queueManager.getListenerFilters().getExclude(); + } + + Set getTopicIncludeFilterNames() { + return queueManager.getTopicFilters().getInclude(); + } + + Set getTopicExcludeFilters() { + return queueManager.getTopicFilters().getExclude(); + } + + Set getQueueIncludeFilterNames() { + return queueManager.getQueueFilters().getInclude(); + } + + Set getQueueExcludeFilters() { + return queueManager.getQueueFilters().getExclude(); + } + + @NotNull + List send(PCFMessage request) throws IOException, MQDataException { + PCFMessage[] result = agent.send(request); + return result == null ? emptyList() : Arrays.asList(result); + } + + String getQueueManagerName() { + return queueManager.getName(); + } + + QueueManager getQueueManager() { + return queueManager; + } + + public MQQueueManager getMqQueueManager() { + return mqQueueManager; + } + + public MetricsConfig getMetricsConfig() { + return metricsConfig; + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/PerformanceEventQueueCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/PerformanceEventQueueCollector.java new file mode 100644 index 000000000..17936678f --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/PerformanceEventQueueCollector.java @@ -0,0 +1,139 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import com.ibm.mq.MQException; +import com.ibm.mq.MQGetMessageOptions; +import com.ibm.mq.MQMessage; +import com.ibm.mq.MQQueue; +import com.ibm.mq.constants.CMQC; +import com.ibm.mq.constants.MQConstants; +import com.ibm.mq.headers.pcf.PCFException; +import com.ibm.mq.headers.pcf.PCFMessage; +import io.opentelemetry.ibm.mq.metrics.Metrics; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongCounter; +import io.opentelemetry.api.metrics.Meter; +import java.io.IOException; +import java.util.function.Consumer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +// Captures metrics from events logged to the queue manager performance event queue. +public final class PerformanceEventQueueCollector implements Consumer { + + private static final Logger logger = + LoggerFactory.getLogger(PerformanceEventQueueCollector.class); + private final LongCounter fullQueueDepthCounter; + private final LongCounter highQueueDepthCounter; + private final LongCounter lowQueueDepthCounter; + + public PerformanceEventQueueCollector(Meter meter) { + this.fullQueueDepthCounter = Metrics.createMqQueueDepthFullEvent(meter); + this.highQueueDepthCounter = Metrics.createMqQueueDepthHighEvent(meter); + this.lowQueueDepthCounter = Metrics.createMqQueueDepthLowEvent(meter); + } + + private void readEvents(MetricsCollectorContext context, String performanceEventsQueueName) + throws Exception { + + MQQueue queue = null; + int counter = 0; + try { + int queueAccessOptions = MQConstants.MQOO_FAIL_IF_QUIESCING | MQConstants.MQOO_INPUT_SHARED; + queue = + context.getMqQueueManager().accessQueue(performanceEventsQueueName, queueAccessOptions); + // keep going until receiving the exception MQConstants.MQRC_NO_MSG_AVAILABLE + logger.debug("Start reading events from performance queue {}", performanceEventsQueueName); + while (true) { + try { + MQGetMessageOptions getOptions = new MQGetMessageOptions(); + getOptions.options = MQConstants.MQGMO_NO_WAIT | MQConstants.MQGMO_FAIL_IF_QUIESCING; + MQMessage message = new MQMessage(); + + queue.get(message, getOptions); + PCFMessage receivedMsg = new PCFMessage(message); + incrementCounterByEventType(context, receivedMsg); + counter++; + } catch (MQException e) { + if (e.reasonCode != MQConstants.MQRC_NO_MSG_AVAILABLE) { + logger.error(e.getMessage(), e); + } + break; + } catch (IOException e) { + logger.error(e.getMessage(), e); + break; + } + } + } finally { + if (queue != null) { + queue.close(); + } + } + logger.debug("Read {} events from performance queue {}", counter, performanceEventsQueueName); + } + + private void incrementCounterByEventType(MetricsCollectorContext context, PCFMessage receivedMsg) + throws PCFException { + String queueName = receivedMsg.getStringParameterValue(CMQC.MQCA_BASE_OBJECT_NAME).trim(); + Attributes attributes = + Attributes.of( + AttributeKey.stringKey("queue.manager"), + context.getQueueManagerName(), + AttributeKey.stringKey("queue.name"), + queueName); + switch (receivedMsg.getReason()) { + case CMQC.MQRC_Q_FULL: + if (context.getMetricsConfig().isMqQueueDepthFullEventEnabled()) { + fullQueueDepthCounter.add(1, attributes); + } + break; + case CMQC.MQRC_Q_DEPTH_HIGH: + if (context.getMetricsConfig().isMqQueueDepthHighEventEnabled()) { + highQueueDepthCounter.add(1, attributes); + } + break; + case CMQC.MQRC_Q_DEPTH_LOW: + if (context.getMetricsConfig().isMqQueueDepthLowEventEnabled()) { + lowQueueDepthCounter.add(1, attributes); + } + break; + default: + logger.debug("Unknown event reason {}", receivedMsg.getReason()); + } + } + + @Override + public void accept(MetricsCollectorContext context) { + long entryTime = System.currentTimeMillis(); + String performanceEventsQueueName = context.getQueueManager().getPerformanceEventsQueueName(); + logger.info( + "sending PCF agent request to read performance events from queue {}", + performanceEventsQueueName); + try { + readEvents(context, performanceEventsQueueName); + } catch (Exception e) { + logger.error( + "Unexpected error occurred while collecting performance events for queue " + + performanceEventsQueueName, + e); + } + long exitTime = System.currentTimeMillis() - entryTime; + logger.debug( + "Time taken to publish metrics for performance events is {} milliseconds", exitTime); + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java new file mode 100644 index 000000000..d1531dd24 --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java @@ -0,0 +1,303 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import static com.ibm.mq.constants.CMQC.*; + +import com.ibm.mq.constants.CMQC; +import com.ibm.mq.constants.CMQCFC; +import com.ibm.mq.headers.MQDataException; +import com.ibm.mq.headers.pcf.MQCFIL; +import com.ibm.mq.headers.pcf.MQCFIN; +import com.ibm.mq.headers.pcf.PCFException; +import com.ibm.mq.headers.pcf.PCFMessage; +import com.ibm.mq.headers.pcf.PCFParameter; +import io.opentelemetry.ibm.mq.metrics.Metrics; +import io.opentelemetry.ibm.mq.metrics.MetricsConfig; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongGauge; +import io.opentelemetry.api.metrics.Meter; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A collaborator buddy of the queue collectors that helps them to send a message, process the + * response, and generate metrics. + */ +final class QueueCollectionBuddy { + private static final Logger logger = LoggerFactory.getLogger(QueueCollectionBuddy.class); + private Map gauges; + + private final QueueCollectorSharedState sharedState; + private final LongGauge onqtimeShort; + private final LongGauge onqtimeLong; + + @FunctionalInterface + private interface AllowedGauge { + + void set(MetricsCollectorContext context, Integer value, Attributes attributes); + } + + private AllowedGauge createAllowedGauge( + LongGauge gauge, Function allowed) { + return (context, val, attributes) -> { + if (allowed.apply(context.getMetricsConfig())) { + gauge.set(val, attributes); + } + }; + } + + QueueCollectionBuddy(Meter meter, QueueCollectorSharedState sharedState) { + this.sharedState = sharedState; + this.gauges = new HashMap<>(); + gauges.put( + CMQC.MQIA_CURRENT_Q_DEPTH, + createAllowedGauge( + Metrics.createMqQueueDepth(meter), MetricsConfig::isMqQueueDepthEnabled)); + gauges.put( + CMQC.MQIA_MAX_Q_DEPTH, + createAllowedGauge( + Metrics.createMqMaxQueueDepth(meter), MetricsConfig::isMqMaxQueueDepthEnabled)); + gauges.put( + CMQC.MQIA_OPEN_INPUT_COUNT, + createAllowedGauge( + Metrics.createMqOpenInputCount(meter), MetricsConfig::isMqOpenInputCountEnabled)); + gauges.put( + CMQC.MQIA_OPEN_OUTPUT_COUNT, + createAllowedGauge( + Metrics.createMqOpenOutputCount(meter), MetricsConfig::isMqOpenOutputCountEnabled)); + gauges.put( + CMQC.MQIA_Q_SERVICE_INTERVAL, + createAllowedGauge( + Metrics.createMqServiceInterval(meter), MetricsConfig::isMqServiceIntervalEnabled)); + gauges.put( + CMQC.MQIA_Q_SERVICE_INTERVAL_EVENT, + createAllowedGauge( + Metrics.createMqServiceIntervalEvent(meter), + MetricsConfig::isMqServiceIntervalEventEnabled)); + gauges.put( + CMQCFC.MQIACF_OLDEST_MSG_AGE, + createAllowedGauge( + Metrics.createMqOldestMsgAge(meter), MetricsConfig::isMqOldestMsgAgeEnabled)); + gauges.put( + CMQCFC.MQIACF_UNCOMMITTED_MSGS, + createAllowedGauge( + Metrics.createMqUncommittedMessages(meter), + MetricsConfig::isMqUncommittedMessagesEnabled)); + gauges.put( + CMQC.MQIA_MSG_DEQ_COUNT, + createAllowedGauge( + Metrics.createMqMessageDeqCount(meter), MetricsConfig::isMqMessageDeqCountEnabled)); + gauges.put( + CMQC.MQIA_MSG_ENQ_COUNT, + createAllowedGauge( + Metrics.createMqMessageEnqCount(meter), MetricsConfig::isMqMessageEnqCountEnabled)); + gauges.put( + CMQC.MQIA_HIGH_Q_DEPTH, + createAllowedGauge( + Metrics.createMqHighQueueDepth(meter), MetricsConfig::isMqHighQueueDepthEnabled)); + gauges.put( + CMQCFC.MQIACF_CUR_Q_FILE_SIZE, + createAllowedGauge( + Metrics.createMqCurrentQueueFilesize(meter), + MetricsConfig::isMqCurrentQueueFilesizeEnabled)); + gauges.put( + CMQCFC.MQIACF_CUR_MAX_FILE_SIZE, + createAllowedGauge( + Metrics.createMqCurrentMaxQueueFilesize(meter), + MetricsConfig::isMqCurrentMaxQueueFilesizeEnabled)); + + this.onqtimeShort = Metrics.createMqOnqtime1(meter); + this.onqtimeLong = Metrics.createMqOnqtime2(meter); + + initialize(meter); + } + + private void initialize(Meter meter) {} + + /** + * Sends a PCFMessage request, reads the response, and generates metrics from the response. It + * handles all exceptions. + */ + void processPCFRequestAndPublishQMetrics( + MetricsCollectorContext context, PCFMessage request, String queueGenericName, int[] fields) { + try { + doProcessPCFRequestAndPublishQMetrics(context, request, queueGenericName, fields); + } catch (PCFException pcfe) { + logger.error( + "PCFException caught while collecting metric for Queue: {}", queueGenericName, pcfe); + if (pcfe.exceptionSource instanceof PCFMessage[]) { + PCFMessage[] msgs = (PCFMessage[]) pcfe.exceptionSource; + for (PCFMessage msg : msgs) { + logger.error(msg.toString()); + } + } + if (pcfe.exceptionSource instanceof PCFMessage) { + PCFMessage msg = (PCFMessage) pcfe.exceptionSource; + logger.error(msg.toString()); + } + // Don't throw exception as it will stop queue metric collection + } catch (Exception mqe) { + logger.error("MQException caught", mqe); + // Don't throw exception as it will stop queue metric collection + } + } + + private void doProcessPCFRequestAndPublishQMetrics( + MetricsCollectorContext context, PCFMessage request, String queueGenericName, int[] fields) + throws IOException, MQDataException { + logger.debug( + "sending PCF agent request to query metrics for generic queue {}", queueGenericName); + long startTime = System.currentTimeMillis(); + List response = context.send(request); + long endTime = System.currentTimeMillis() - startTime; + logger.debug( + "PCF agent queue metrics query response for generic queue {} received in {} milliseconds", + queueGenericName, + endTime); + if (response.isEmpty()) { + logger.debug("Unexpected error while PCFMessage.send(), response is empty"); + return; + } + + List messages = + MessageFilter.ofKind("queue") + .excluding(context.getQueueExcludeFilters()) + .withResourceExtractor(MessageBuddy::queueName) + .filter(response); + + for (PCFMessage message : messages) { + handleMessage(context, message, fields); + } + } + + private void handleMessage(MetricsCollectorContext context, PCFMessage message, int[] fields) + throws PCFException { + String queueName = MessageBuddy.queueName(message); + String queueType = getQueueTypeFromName(message, queueName); + if (queueType == null) { + logger.info("Unable to determine queue type for queue name = {}", queueName); + return; + } + + logger.debug("Pulling out metrics for queue name {}", queueName); + getMetrics(context, message, queueName, queueType, fields); + } + + private String getQueueTypeFromName(PCFMessage message, String queueName) throws PCFException { + if (message.getParameterValue(CMQC.MQIA_Q_TYPE) == null) { + return sharedState.getType(queueName); + } + + String queueType = getQueueType(message); + sharedState.putQueueType(queueName, queueType); + return queueType; + } + + private static String getQueueType(PCFMessage message) throws PCFException { + String baseQueueType = getBaseQueueType(message); + return maybeAppendUsage(message, baseQueueType); + } + + private static String maybeAppendUsage(PCFMessage message, String baseQueueType) + throws PCFException { + if (message.getParameter(CMQC.MQIA_USAGE) == null) { + return baseQueueType; + } + switch (message.getIntParameterValue(CMQC.MQIA_USAGE)) { + case CMQC.MQUS_NORMAL: + return baseQueueType + "-normal"; + case CMQC.MQUS_TRANSMISSION: + return baseQueueType + "-transmission"; + } + return baseQueueType; + } + + private static String getBaseQueueType(PCFMessage message) throws PCFException { + switch (message.getIntParameterValue(CMQC.MQIA_Q_TYPE)) { + case MQQT_LOCAL: + return "local"; + case MQQT_ALIAS: + return "alias"; + case MQQT_REMOTE: + return "remote"; + case MQQT_CLUSTER: + return "cluster"; + case MQQT_MODEL: + return "model"; + } + logger.warn("Unknown type of queue {}", message.getIntParameterValue(CMQC.MQIA_Q_TYPE)); + return "unknown"; + } + + private void getMetrics( + MetricsCollectorContext context, + PCFMessage pcfMessage, + String queueName, + String queueType, + int[] fields) + throws PCFException { + + for (int field : fields) { + if (field == CMQC.MQCA_Q_NAME || field == CMQC.MQIA_USAGE || field == CMQC.MQIA_Q_TYPE) { + continue; + } + updateMetrics(context, pcfMessage, queueName, queueType, field); + } + } + + private void updateMetrics( + MetricsCollectorContext context, + PCFMessage pcfMessage, + String queueName, + String queueType, + int constantValue) + throws PCFException { + PCFParameter pcfParam = pcfMessage.getParameter(constantValue); + Attributes attributes = + Attributes.of( + AttributeKey.stringKey("queue.name"), + queueName, + AttributeKey.stringKey("queue.type"), + queueType, + AttributeKey.stringKey("queue.manager"), + context.getQueueManagerName()); + + if (pcfParam instanceof MQCFIN) { + AllowedGauge g = this.gauges.get(constantValue); + if (g == null) { + throw new IllegalArgumentException("Unknown constantValue " + constantValue); + } + int metricVal = pcfMessage.getIntParameterValue(constantValue); + g.set(context, metricVal, attributes); + } + if (pcfParam instanceof MQCFIL) { + int[] metricVals = pcfMessage.getIntListParameterValue(constantValue); + if (context.getMetricsConfig().isMqOnqtime1Enabled()) { + onqtimeShort.set(metricVals[0], attributes); + } + if (context.getMetricsConfig().isMqOnqtime2Enabled()) { + onqtimeLong.set(metricVals[1], attributes); + } + } + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectorSharedState.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectorSharedState.java new file mode 100644 index 000000000..66ad0c4f2 --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectorSharedState.java @@ -0,0 +1,35 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import java.util.concurrent.ConcurrentHashMap; +import javax.annotation.Nullable; + +final class QueueCollectorSharedState { + + private final ConcurrentHashMap queueNameToType = new ConcurrentHashMap<>(); + + QueueCollectorSharedState() {} + + public void putQueueType(String name, String value) { + queueNameToType.put(name, value); + } + + @Nullable + public String getType(String name) { + return queueNameToType.get(name); + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerEventCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerEventCollector.java new file mode 100644 index 000000000..167fd9b0f --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerEventCollector.java @@ -0,0 +1,118 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import com.ibm.mq.MQException; +import com.ibm.mq.MQGetMessageOptions; +import com.ibm.mq.MQMessage; +import com.ibm.mq.MQQueue; +import com.ibm.mq.constants.CMQC; +import com.ibm.mq.constants.CMQCFC; +import com.ibm.mq.constants.MQConstants; +import com.ibm.mq.headers.pcf.PCFMessage; +import io.opentelemetry.ibm.mq.metrics.Metrics; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongCounter; +import io.opentelemetry.api.metrics.Meter; +import java.io.IOException; +import java.util.function.Consumer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +// Reads queue manager events and counts them as metrics +public final class QueueManagerEventCollector implements Consumer { + + private static final Logger logger = LoggerFactory.getLogger(QueueManagerEventCollector.class); + private final LongCounter authorityEventCounter; + + public QueueManagerEventCollector(Meter meter) { + this.authorityEventCounter = Metrics.createMqUnauthorizedEvent(meter); + } + + private void readEvents(MetricsCollectorContext context, String queueManagerEventsQueueName) + throws Exception { + + MQQueue queue = null; + try { + int queueAccessOptions = MQConstants.MQOO_FAIL_IF_QUIESCING | MQConstants.MQOO_INPUT_SHARED; + queue = + context.getMqQueueManager().accessQueue(queueManagerEventsQueueName, queueAccessOptions); + // keep going until receiving the exception MQConstants.MQRC_NO_MSG_AVAILABLE + while (true) { + try { + MQGetMessageOptions getOptions = new MQGetMessageOptions(); + getOptions.options = MQConstants.MQGMO_NO_WAIT | MQConstants.MQGMO_FAIL_IF_QUIESCING; + MQMessage message = new MQMessage(); + + queue.get(message, getOptions); + PCFMessage received = new PCFMessage(message); + if (received.getReason() == CMQC.MQRC_NOT_AUTHORIZED) { + + if (context.getMetricsConfig().isMqUnauthorizedEventEnabled()) { + String username = received.getStringParameterValue(CMQCFC.MQCACF_USER_IDENTIFIER); + String applicationName = received.getStringParameterValue(CMQCFC.MQCACF_APPL_NAME); + authorityEventCounter.add( + 1, + Attributes.of( + AttributeKey.stringKey("queue.manager"), + context.getQueueManagerName(), + AttributeKey.stringKey("user.name"), + username, + AttributeKey.stringKey("application.name"), + applicationName)); + } + } else { + logger.debug("Unknown event reason {}", received.getReason()); + } + + } catch (MQException e) { + if (e.reasonCode != MQConstants.MQRC_NO_MSG_AVAILABLE) { + logger.error(e.getMessage(), e); + } + break; + } catch (IOException e) { + logger.error(e.getMessage(), e); + break; + } + } + } finally { + if (queue != null) { + queue.close(); + } + } + } + + @Override + public void accept(MetricsCollectorContext context) { + long entryTime = System.currentTimeMillis(); + String queueManagerEventsQueueName = context.getQueueManager().getQueueManagerEventsQueueName(); + logger.info( + "sending PCF agent request to read queue manager events from queue {}", + queueManagerEventsQueueName); + try { + readEvents(context, queueManagerEventsQueueName); + } catch (Exception e) { + logger.error( + "Unexpected error occurred while collecting queue manager events for queue " + + queueManagerEventsQueueName, + e); + } + long exitTime = System.currentTimeMillis() - entryTime; + logger.debug( + "Time taken to publish metrics for queue manager events is {} milliseconds", exitTime); + } +} 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 new file mode 100644 index 000000000..42932724a --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerMetricsCollector.java @@ -0,0 +1,121 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import com.ibm.mq.constants.CMQCFC; +import com.ibm.mq.headers.pcf.PCFMessage; +import io.opentelemetry.ibm.mq.metrics.Metrics; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongGauge; +import io.opentelemetry.api.metrics.Meter; +import java.util.List; +import java.util.function.Consumer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** This class is responsible for queue manager metric collection. */ +public final class QueueManagerMetricsCollector implements Consumer { + + private static final Logger logger = LoggerFactory.getLogger(QueueManagerMetricsCollector.class); + + private final LongGauge statusGauge; + private final LongGauge connectionCountGauge; + private final LongGauge restartLogSizeGauge; + private final LongGauge reuseLogSizeGauge; + private final LongGauge archiveLogSizeGauge; + private final LongGauge maxActiveChannelsGauge; + + public QueueManagerMetricsCollector(Meter meter) { + this.statusGauge = Metrics.createMqManagerStatus(meter); + this.connectionCountGauge = Metrics.createMqConnectionCount(meter); + this.restartLogSizeGauge = Metrics.createMqRestartLogSize(meter); + this.reuseLogSizeGauge = Metrics.createMqReusableLogSize(meter); + this.archiveLogSizeGauge = Metrics.createMqArchiveLogSize(meter); + this.maxActiveChannelsGauge = Metrics.createMqManagerMaxActiveChannels(meter); + } + + @Override + public void accept(MetricsCollectorContext context) { + long entryTime = System.currentTimeMillis(); + logger.debug( + "publishMetrics entry time for queuemanager {} is {} milliseconds", + context.getQueueManagerName(), + entryTime); + // CMQCFC.MQCMD_INQUIRE_Q_MGR_STATUS is 161 + PCFMessage request = new PCFMessage(CMQCFC.MQCMD_INQUIRE_Q_MGR_STATUS); + // CMQCFC.MQIACF_Q_MGR_STATUS_ATTRS is 1229 + request.addParameter(CMQCFC.MQIACF_Q_MGR_STATUS_ATTRS, new int[] {CMQCFC.MQIACF_ALL}); + try { + // Note that agent.send() method is synchronized + logger.debug( + "sending PCF agent request to query queuemanager {}", context.getQueueManagerName()); + long startTime = System.currentTimeMillis(); + List responses = context.send(request); + long endTime = System.currentTimeMillis() - startTime; + logger.debug( + "PCF agent queuemanager metrics query response for {} received in {} milliseconds", + context.getQueueManagerName(), + endTime); + if (responses.isEmpty()) { + logger.debug("Unexpected error while PCFMessage.send(), response is empty"); + return; + } + if (context.getMetricsConfig().isMqManagerStatusEnabled()) { + int status = responses.get(0).getIntParameterValue(CMQCFC.MQIACF_Q_MGR_STATUS); + statusGauge.set( + status, + Attributes.of(AttributeKey.stringKey("queue.manager"), context.getQueueManagerName())); + } + if (context.getMetricsConfig().isMqConnectionCountEnabled()) { + int count = responses.get(0).getIntParameterValue(CMQCFC.MQIACF_CONNECTION_COUNT); + connectionCountGauge.set( + count, + Attributes.of(AttributeKey.stringKey("queue.manager"), context.getQueueManagerName())); + } + if (context.getMetricsConfig().isMqRestartLogSizeEnabled()) { + int logSize = responses.get(0).getIntParameterValue(CMQCFC.MQIACF_RESTART_LOG_SIZE); + restartLogSizeGauge.set( + logSize, + Attributes.of(AttributeKey.stringKey("queue.manager"), context.getQueueManagerName())); + } + if (context.getMetricsConfig().isMqReusableLogSizeEnabled()) { + int logSize = responses.get(0).getIntParameterValue(CMQCFC.MQIACF_REUSABLE_LOG_SIZE); + reuseLogSizeGauge.set( + logSize, + Attributes.of(AttributeKey.stringKey("queue.manager"), context.getQueueManagerName())); + } + if (context.getMetricsConfig().isMqArchiveLogSizeEnabled()) { + int logSize = responses.get(0).getIntParameterValue(CMQCFC.MQIACF_ARCHIVE_LOG_SIZE); + archiveLogSizeGauge.set( + logSize, + Attributes.of(AttributeKey.stringKey("queue.manager"), context.getQueueManagerName())); + } + if (context.getMetricsConfig().isMqManagerMaxActiveChannelsEnabled()) { + int maxActiveChannels = context.getQueueManager().getMaxActiveChannels(); + maxActiveChannelsGauge.set( + maxActiveChannels, + Attributes.of(AttributeKey.stringKey("queue.manager"), context.getQueueManagerName())); + } + } catch (Exception e) { + logger.error(e.getMessage()); + throw new RuntimeException(e); + } finally { + long exitTime = System.currentTimeMillis() - entryTime; + logger.debug("Time taken to publish metrics for queuemanager is {} milliseconds", exitTime); + } + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueMetricsCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueMetricsCollector.java new file mode 100644 index 000000000..2f8652f3f --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueMetricsCollector.java @@ -0,0 +1,72 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; +import io.opentelemetry.api.metrics.Meter; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class QueueMetricsCollector implements Consumer { + + private static final Logger logger = LoggerFactory.getLogger(QueueMetricsCollector.class); + + private final List> publishers = new ArrayList<>(); + private final InquireQCmdCollector inquireQueueCmd; + private final ExecutorService threadPool; + private final ConfigWrapper config; + + public QueueMetricsCollector(Meter meter, ExecutorService threadPool, ConfigWrapper config) { + this.threadPool = threadPool; + this.config = config; + QueueCollectionBuddy queueBuddy = + new QueueCollectionBuddy(meter, new QueueCollectorSharedState()); + this.inquireQueueCmd = new InquireQCmdCollector(queueBuddy); + publishers.add(new InquireQStatusCmdCollector(queueBuddy)); + publishers.add(new ResetQStatsCmdCollector(queueBuddy)); + } + + @Override + public void accept(MetricsCollectorContext context) { + logger.info("Collecting queue metrics..."); + + // first collect all queue types. + inquireQueueCmd.accept(context); + + // schedule all other jobs in parallel. + List> taskJobs = new ArrayList<>(); + for (Consumer p : publishers) { + taskJobs.add( + () -> { + p.accept(context); + return null; + }); + } + + try { + int timeout = this.config.getInt("queueMetricsCollectionTimeoutInSeconds", 20); + threadPool.invokeAll(taskJobs, timeout, TimeUnit.SECONDS); + } catch (InterruptedException e) { + logger.error("The thread was interrupted ", e); + } + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ReadConfigurationEventQueueCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ReadConfigurationEventQueueCollector.java new file mode 100644 index 000000000..68f51a144 --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ReadConfigurationEventQueueCollector.java @@ -0,0 +1,151 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import com.ibm.mq.MQException; +import com.ibm.mq.MQGetMessageOptions; +import com.ibm.mq.MQMessage; +import com.ibm.mq.MQQueue; +import com.ibm.mq.constants.CMQC; +import com.ibm.mq.constants.CMQCFC; +import com.ibm.mq.constants.MQConstants; +import com.ibm.mq.headers.pcf.PCFMessage; +import io.opentelemetry.ibm.mq.metrics.Metrics; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongGauge; +import io.opentelemetry.api.metrics.Meter; +import java.io.IOException; +import java.util.function.Consumer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class ReadConfigurationEventQueueCollector + implements Consumer { + + private static final Logger logger = + LoggerFactory.getLogger(ReadConfigurationEventQueueCollector.class); + private final long bootTime; + private final LongGauge maxHandlesGauge; + + public ReadConfigurationEventQueueCollector(Meter meter) { + this.bootTime = System.currentTimeMillis(); + this.maxHandlesGauge = Metrics.createMqManagerMaxHandles(meter); + } + + private PCFMessage findLastUpdate( + MetricsCollectorContext context, long entryTime, String configurationQueueName) + throws Exception { + // find the last update: + PCFMessage candidate = null; + + boolean consumeEvents = + context.getQueueManager().getConsumeConfigurationEventInterval() > 0 + && (entryTime - this.bootTime) + % context.getQueueManager().getConsumeConfigurationEventInterval() + == 0; + + MQQueue queue = null; + try { + int queueAccessOptions = MQConstants.MQOO_FAIL_IF_QUIESCING | MQConstants.MQOO_INPUT_SHARED; + if (!consumeEvents) { + // we are not consuming the events. + queueAccessOptions |= MQConstants.MQOO_BROWSE; + } + queue = context.getMqQueueManager().accessQueue(configurationQueueName, queueAccessOptions); + int maxSequenceNumber = 0; + // keep going until receiving the exception MQConstants.MQRC_NO_MSG_AVAILABLE + while (true) { + try { + MQGetMessageOptions getOptions = new MQGetMessageOptions(); + getOptions.options = MQConstants.MQGMO_NO_WAIT | MQConstants.MQGMO_FAIL_IF_QUIESCING; + if (!consumeEvents) { + getOptions.options |= MQConstants.MQGMO_BROWSE_NEXT; + } + MQMessage message = new MQMessage(); + + queue.get(message, getOptions); + PCFMessage received = new PCFMessage(message); + if (received.getMsgSeqNumber() > maxSequenceNumber) { + maxSequenceNumber = received.getMsgSeqNumber(); + candidate = received; + } + + } catch (MQException e) { + if (e.reasonCode != MQConstants.MQRC_NO_MSG_AVAILABLE) { + logger.error(e.getMessage(), e); + } + break; + } catch (IOException e) { + logger.error(e.getMessage(), e); + break; + } + } + } finally { + if (queue != null) { + queue.close(); + } + } + return candidate; + } + + @Override + public void accept(MetricsCollectorContext context) { + long entryTime = System.currentTimeMillis(); + String configurationQueueName = context.getQueueManager().getConfigurationQueueName(); + logger.info( + "sending PCF agent request to read configuration events from queue {}", + configurationQueueName); + try { + + PCFMessage candidate = findLastUpdate(context, entryTime, configurationQueueName); + + if (candidate == null) { + if (context.getQueueManager().isRefreshQueueManagerConfigurationEnabled()) { + // no event found. + // we issue a refresh request, which will generate a configuration event on the + // configuration event queue. + // note this may incur a performance cost to the queue manager. + PCFMessage request = new PCFMessage(CMQCFC.MQCMD_REFRESH_Q_MGR); + request.addParameter(CMQCFC.MQIACF_REFRESH_TYPE, CMQCFC.MQRT_CONFIGURATION); + request.addParameter(CMQCFC.MQIACF_OBJECT_TYPE, CMQC.MQOT_Q_MGR); + context.send(request); + // try again: + candidate = findLastUpdate(context, entryTime, configurationQueueName); + } + } + + if (candidate != null) { + if (context.getMetricsConfig().isMqManagerMaxHandlesEnabled()) { + int maxHandles = candidate.getIntParameterValue(CMQC.MQIA_MAX_HANDLES); + maxHandlesGauge.set( + maxHandles, + Attributes.of( + AttributeKey.stringKey("queue.manager"), context.getQueueManager().getName())); + } + } + + } catch (Exception e) { + logger.error( + "Unexpected error occurred while collecting configuration events for queue " + + configurationQueueName, + e); + } + long exitTime = System.currentTimeMillis() - entryTime; + logger.debug( + "Time taken to publish metrics for configuration events is {} milliseconds", exitTime); + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ResetQStatsCmdCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ResetQStatsCmdCollector.java new file mode 100644 index 000000000..203c9bc81 --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ResetQStatsCmdCollector.java @@ -0,0 +1,66 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import com.ibm.mq.constants.CMQC; +import com.ibm.mq.constants.CMQCFC; +import com.ibm.mq.headers.pcf.PCFMessage; +import java.util.Arrays; +import java.util.Set; +import java.util.function.Consumer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class ResetQStatsCmdCollector implements Consumer { + + static final int[] ATTRIBUTES = + new int[] {CMQC.MQIA_HIGH_Q_DEPTH, CMQC.MQIA_MSG_DEQ_COUNT, CMQC.MQIA_MSG_ENQ_COUNT}; + + private static final Logger logger = LoggerFactory.getLogger(ResetQStatsCmdCollector.class); + + static final String COMMAND = "MQCMD_RESET_Q_STATS"; + private final QueueCollectionBuddy queueBuddy; + + ResetQStatsCmdCollector(QueueCollectionBuddy queueBuddy) { + this.queueBuddy = queueBuddy; + } + + @Override + public void accept(MetricsCollectorContext context) { + logger.info("Collecting metrics for command {}", COMMAND); + long entryTime = System.currentTimeMillis(); + + logger.debug( + "Attributes being sent along PCF agent request to query queue metrics: {} for command {}", + Arrays.toString(ATTRIBUTES), + COMMAND); + + Set queueGenericNames = context.getQueueIncludeFilterNames(); + for (String queueGenericName : queueGenericNames) { + // list of all metrics extracted through MQCMD_RESET_Q_STATS is mentioned here + // https://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.ref.adm.doc/q088310_.htm + PCFMessage request = new PCFMessage(CMQCFC.MQCMD_RESET_Q_STATS); + request.addParameter(CMQC.MQCA_Q_NAME, queueGenericName); + queueBuddy.processPCFRequestAndPublishQMetrics( + context, request, queueGenericName, ATTRIBUTES); + } + long exitTime = System.currentTimeMillis() - entryTime; + logger.debug( + "Time taken to publish metrics for all queues is {} milliseconds for command {}", + exitTime, + COMMAND); + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/TopicMetricsCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/TopicMetricsCollector.java new file mode 100644 index 000000000..4f47d850a --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/TopicMetricsCollector.java @@ -0,0 +1,36 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import io.opentelemetry.api.metrics.Meter; +import java.util.function.Consumer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class TopicMetricsCollector implements Consumer { + private static final Logger logger = LoggerFactory.getLogger(TopicMetricsCollector.class); + private final InquireTStatusCmdCollector inquireTStatusCmdCollector; + + public TopicMetricsCollector(Meter meter) { + this.inquireTStatusCmdCollector = new InquireTStatusCmdCollector(meter); + } + + @Override + public void accept(MetricsCollectorContext context) { + logger.info("Collecting Topic metrics..."); + inquireTStatusCmdCollector.accept(context); + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Config.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Config.java new file mode 100644 index 000000000..531bdee09 --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Config.java @@ -0,0 +1,91 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.opentelemetry; + +import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** Utilities reading configuration and create domain objects */ +class Config { + + private static final Logger logger = LoggerFactory.getLogger(Config.class); + + static void setUpSSLConnection(Map config) { + getConfigValueAndSetSystemProperty(config, "keyStorePath", "javax.net.ssl.keyStore"); + getConfigValueAndSetSystemProperty( + config, "keyStorePassword", "javax.net.ssl.keyStorePassword"); + getConfigValueAndSetSystemProperty(config, "trustStorePath", "javax.net.ssl.trustStorePath"); + getConfigValueAndSetSystemProperty( + config, "trustStorePassword", "javax.net.ssl.trustStorePassword"); + } + + private static void getConfigValueAndSetSystemProperty( + Map otlpConfig, String configKey, String systemKey) { + Object configValue = otlpConfig.get(configKey); + if (configValue instanceof String && !((String) configValue).trim().isEmpty()) { + System.setProperty(systemKey, (String) configValue); + } + } + + static void configureSecurity(ConfigWrapper config) { + Map sslConnection = config.getSslConnection(); + if (sslConnection.isEmpty()) { + logger.debug( + "ssl truststore and keystore are not configured in config.yml, if SSL is enabled, pass them as jvm args"); + return; + } + + configureTrustStore(sslConnection); + configureKeyStore(sslConnection); + } + + private static void configureTrustStore(Map sslConnection) { + String trustStorePath = sslConnection.get("trustStorePath"); + if (trustStorePath == null || trustStorePath.isEmpty()) { + logger.debug( + "trustStorePath is not set in config.yml, ignoring setting trustStorePath as system property"); + return; + } + + System.setProperty("javax.net.ssl.trustStore", trustStorePath); + logger.debug("System property set for javax.net.ssl.trustStore is {}", trustStorePath); + + String trustStorePassword = sslConnection.get("trustStorePassword"); + + if (trustStorePassword != null && !trustStorePassword.isEmpty()) { + System.setProperty("javax.net.ssl.trustStorePassword", trustStorePassword); + logger.debug("System property set for javax.net.ssl.trustStorePassword is xxxxx"); + } + } + + private static void configureKeyStore(Map sslConnection) { + String keyStorePath = sslConnection.get("keyStorePath"); + if (keyStorePath == null || keyStorePath.isEmpty()) { + logger.debug( + "keyStorePath is not set in config.yml, ignoring setting keyStorePath as system property"); + return; + } + + System.setProperty("javax.net.ssl.keyStore", keyStorePath); + logger.debug("System property set for javax.net.ssl.keyStore is {}", keyStorePath); + String keyStorePassword = sslConnection.get("keyStorePassword"); + if (keyStorePassword != null && !keyStorePassword.isEmpty()) { + System.setProperty("javax.net.ssl.keyStorePassword", keyStorePassword); + logger.debug("System property set for javax.net.ssl.keyStorePassword is xxxxx"); + } + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapper.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapper.java new file mode 100644 index 000000000..24d1d4609 --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapper.java @@ -0,0 +1,136 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.opentelemetry; + +import static java.util.Collections.emptyList; + +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.time.Duration; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.yaml.snakeyaml.Yaml; + +/** Low-fi domain-specific yaml wrapper. */ +public final class ConfigWrapper { + + private static final Logger logger = LoggerFactory.getLogger(ConfigWrapper.class); + + private static final int DEFAULT_THREADS = 20; + private static final int DEFAULT_DELAY_SECONDS = 60; + private static final int DEFAULT_INITIAL_DELAY = 0; + + private final Map config; + + private ConfigWrapper(Map config) { + this.config = config; + } + + public static ConfigWrapper parse(String configFile) throws FileNotFoundException { + Yaml yaml = new Yaml(); + Map config = yaml.load(new FileReader(configFile)); + return new ConfigWrapper(config); + } + + public int getNumberOfThreads() { + int value = defaultedInt(getTaskSchedule(), "numberOfThreads", DEFAULT_THREADS); + if (value < DEFAULT_THREADS) { + logger.warn( + "numberOfThreads {} is less than the minimum number of threads allowed. Using {} instead.", + value, + DEFAULT_THREADS); + value = DEFAULT_THREADS; + } + return value; + } + + int getTaskDelaySeconds() { + return defaultedInt(getTaskSchedule(), "taskDelaySeconds", DEFAULT_DELAY_SECONDS); + } + + Duration getTaskDelay() { + return Duration.ofSeconds(getTaskDelaySeconds()); + } + + int getTaskInitialDelaySeconds() { + return defaultedInt(getTaskSchedule(), "initialDelaySeconds", DEFAULT_INITIAL_DELAY); + } + + @NotNull + @SuppressWarnings("unchecked") + List getQueueManagerNames() { + return getQueueManagers().stream() + .map(o -> (Map) o) + .map(x -> x.get("name")) + .collect(Collectors.toList()); + } + + @NotNull + @SuppressWarnings("unchecked") + public List> getQueueManagers() { + List> result = (List>) config.get("queueManagers"); + if (result == null) { + return emptyList(); + } + return result; + } + + @NotNull + @SuppressWarnings("unchecked") + public Map getSslConnection() { + Map result = (Map) config.get("sslConnection"); + if (result == null) { + return Collections.emptyMap(); + } + return result; + } + + public int getInt(String key, int defaultValue) { + Object result = config.get(key); + if (result == null) { + return defaultValue; + } + return (Integer) result; + } + + @NotNull + @SuppressWarnings("unchecked") + public Map getMetrics() { + Object metrics = config.get("metrics"); + if (!(metrics instanceof Map)) { + throw new IllegalArgumentException("config metrics section is missing"); + } + return (Map) metrics; + } + + private int defaultedInt(Map section, String key, int defaultValue) { + Object val = section.get(key); + return val instanceof Integer ? (Integer) val : defaultValue; + } + + @SuppressWarnings("unchecked") + private Map getTaskSchedule() { + if (config.get("taskSchedule") instanceof Map) { + return (Map) config.get("taskSchedule"); + } + return Collections.emptyMap(); + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java new file mode 100644 index 000000000..60e80e231 --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java @@ -0,0 +1,96 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.opentelemetry; + +import io.opentelemetry.ibm.mq.WMQMonitor; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.metrics.MeterProvider; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; +import io.opentelemetry.sdk.resources.Resource; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import org.jetbrains.annotations.VisibleForTesting; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Main { + + private static final Logger logger = LoggerFactory.getLogger(Main.class); + + public static void main(String[] args) throws Exception { + if (args.length == 0) { + System.err.println("Usage: Main "); + System.exit(1); + } + + try { + Main.class.getClassLoader().loadClass("com.ibm.mq.headers.MQDataException"); + } catch (ClassNotFoundException e) { + System.err.println("IBM MQ jar is missing from classpath."); + System.exit(1); + } + + String configFile = args[0]; + + ConfigWrapper config = ConfigWrapper.parse(configFile); + + Thread.UncaughtExceptionHandler handler = + (t, e) -> logger.error("Unhandled exception in thread pool", e); + logger.debug("Initializing thread pool with {} threads", config.getNumberOfThreads()); + ScheduledExecutorService service = + Executors.newScheduledThreadPool( + config.getNumberOfThreads(), + r -> { + Thread thread = new Thread(r); + thread.setUncaughtExceptionHandler(handler); + return thread; + }); + + Config.configureSecurity(config); + Config.setUpSSLConnection(config.getSslConnection()); + + run(config, service); + } + + public static void run(ConfigWrapper config, final ScheduledExecutorService service) { + + AutoConfiguredOpenTelemetrySdk sdk = + AutoConfiguredOpenTelemetrySdk.builder() + .addMeterProviderCustomizer( + (builder, configProps) -> builder.setResource(Resource.empty())) + .build(); + + OpenTelemetrySdk otel = sdk.getOpenTelemetrySdk(); + + run(config, service, otel); + } + + @VisibleForTesting + public static void run( + ConfigWrapper config, ScheduledExecutorService service, OpenTelemetry otel) { + MeterProvider meterProvider = otel.getMeterProvider(); + + Runtime.getRuntime().addShutdownHook(new Thread(service::shutdown)); + WMQMonitor monitor = new WMQMonitor(config, service, meterProvider.get("websphere/mq")); + service.scheduleAtFixedRate( + monitor::run, + config.getTaskInitialDelaySeconds(), + config.getTaskDelaySeconds(), + TimeUnit.SECONDS); + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/AuthorityEventCreator.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/AuthorityEventCreator.java new file mode 100644 index 000000000..0784a163e --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/AuthorityEventCreator.java @@ -0,0 +1,88 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.util; + +import com.ibm.mq.MQException; +import com.ibm.msg.client.jms.JmsConnectionFactory; +import com.ibm.msg.client.jms.JmsFactoryFactory; +import com.ibm.msg.client.wmq.WMQConstants; +import javax.jms.JMSContext; +import javax.jms.JMSException; +import javax.jms.JMSRuntimeException; + +/** + * Application that tries to log in to a queue manager to create authority events. + * + *

You can run it with + * + *

+ * java -cp ibm-mq-monitoring--all.jar:com.ibm.mq.allclient.jar com.splunk.ibm.mq.util.AuthorityEventCreator       
+ * 
+ */ +public class AuthorityEventCreator { + + public static void main(String[] args) { + String host, port, queueManagerName, channelName, username, password; + if (args.length < 6) { + throw new IllegalArgumentException("Need 6 arguments"); + } + host = args[0]; + port = args[1]; + queueManagerName = args[2]; + channelName = args[3]; + username = args[4]; + password = args[5]; + + JMSContext context = null; + try { + // Create a connection factory + JmsFactoryFactory ff = JmsFactoryFactory.getInstance(WMQConstants.JAKARTA_WMQ_PROVIDER); + JmsConnectionFactory cf = ff.createConnectionFactory(); + + // Set the properties + cf.setStringProperty(WMQConstants.WMQ_HOST_NAME, host); + cf.setIntProperty(WMQConstants.WMQ_PORT, Integer.parseInt(port)); + cf.setStringProperty(WMQConstants.WMQ_CHANNEL, channelName); + cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT); + cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, queueManagerName); + cf.setStringProperty(WMQConstants.WMQ_APPLICATIONNAME, "Bad Password"); + cf.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP, true); + cf.setStringProperty(WMQConstants.USERID, username); + cf.setStringProperty(WMQConstants.PASSWORD, password); + // cf.setStringProperty(WMQConstants.WMQ_SSL_CIPHER_SUITE, "*TLS12ORHIGHER"); + // cf.setIntProperty(MQConstants.CERTIFICATE_VALIDATION_POLICY, + // MQConstants.MQ_CERT_VAL_POLICY_NONE); + + // Create Jakarta objects + context = cf.createContext(); + } catch (JMSException e) { + throw new RuntimeException(e); + } catch (JMSRuntimeException e) { + if (e.getCause() instanceof MQException) { + MQException mqe = (MQException) e.getCause(); + if (mqe.getReason() == 2035) { // bad password + System.out.println("Error 2035 returned"); + return; + } + } + throw new RuntimeException(e); + } finally { + if (context != null) { + context.close(); + } + } + } +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/WMQUtil.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/WMQUtil.java new file mode 100644 index 000000000..20d6902bb --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/WMQUtil.java @@ -0,0 +1,87 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.util; + +import com.ibm.mq.MQException; +import com.ibm.mq.MQQueueManager; +import com.ibm.mq.headers.MQDataException; +import com.ibm.mq.headers.pcf.PCFMessageAgent; +import io.opentelemetry.ibm.mq.WMQContext; +import io.opentelemetry.ibm.mq.config.QueueManager; +import java.util.Hashtable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class WMQUtil { + + private static final Logger logger = LoggerFactory.getLogger(WMQUtil.class); + + private WMQUtil() {} + + public static PCFMessageAgent initPCFMessageAgent( + QueueManager queueManager, MQQueueManager ibmQueueManager) { + try { + PCFMessageAgent agent; + if (isNotNullOrEmpty(queueManager.getModelQueueName()) + && isNotNullOrEmpty(queueManager.getReplyQueuePrefix())) { + logger.debug("Initializing the PCF agent for model queue and reply queue prefix."); + agent = new PCFMessageAgent(); + agent.setModelQueueName(queueManager.getModelQueueName()); + agent.setReplyQueuePrefix(queueManager.getReplyQueuePrefix()); + logger.debug("Connecting to queueManager to set the modelQueueName and replyQueuePrefix."); + agent.connect(ibmQueueManager); + } else { + agent = new PCFMessageAgent(ibmQueueManager); + } + if (queueManager.getCcsid() != Integer.MIN_VALUE) { + agent.setCharacterSet(queueManager.getCcsid()); + } + + if (queueManager.getEncoding() != Integer.MIN_VALUE) { + agent.setEncoding(queueManager.getEncoding()); + } + logger.debug( + "Initialized PCFMessageAgent for queueManager {} in thread {}", + agent.getQManagerName(), + Thread.currentThread().getName()); + return agent; + } catch (MQDataException mqe) { + logger.error(mqe.getMessage(), mqe); + throw new RuntimeException(mqe); + } + } + + @SuppressWarnings("rawtypes") + public static MQQueueManager connectToQueueManager(QueueManager queueManager) { + WMQContext auth = new WMQContext(queueManager); + Hashtable env = auth.getMQEnvironment(); + try { + MQQueueManager ibmQueueManager = new MQQueueManager(queueManager.getName(), env); + logger.debug( + "MQQueueManager connection initiated for queueManager {} in thread {}", + queueManager.getName(), + Thread.currentThread().getName()); + return ibmQueueManager; + } catch (MQException mqe) { + logger.error(mqe.getMessage(), mqe); + throw new RuntimeException(mqe.getMessage()); + } + } + + private static boolean isNotNullOrEmpty(String str) { + return str != null && !str.isEmpty(); + } +} diff --git a/ibm-mq-metrics/src/main/resources/log4j2.xml b/ibm-mq-metrics/src/main/resources/log4j2.xml new file mode 100644 index 000000000..98ee41146 --- /dev/null +++ b/ibm-mq-metrics/src/main/resources/log4j2.xml @@ -0,0 +1,59 @@ + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n + logs + otel_ibm_mq + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollectorTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollectorTest.java new file mode 100644 index 000000000..5ec98554a --- /dev/null +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollectorTest.java @@ -0,0 +1,236 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import static com.ibm.mq.constants.CMQC.MQRC_SELECTOR_ERROR; +import static com.ibm.mq.constants.CMQCFC.MQRCCF_CHL_STATUS_NOT_FOUND; +import static io.opentelemetry.ibm.mq.metricscollector.MetricAssert.assertThatMetric; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.params.provider.Arguments.arguments; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.when; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ibm.mq.constants.CMQCFC; +import com.ibm.mq.headers.pcf.PCFException; +import com.ibm.mq.headers.pcf.PCFMessage; +import com.ibm.mq.headers.pcf.PCFMessageAgent; +import io.opentelemetry.ibm.mq.config.QueueManager; +import io.opentelemetry.ibm.mq.metrics.MetricsConfig; +import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class ChannelMetricsCollectorTest { + + @RegisterExtension + static final OpenTelemetryExtension otelTesting = OpenTelemetryExtension.create(); + + ChannelMetricsCollector classUnderTest; + QueueManager queueManager; + MetricsCollectorContext context; + Meter meter; + @Mock PCFMessageAgent pcfMessageAgent; + + @BeforeEach + void setup() throws Exception { + ConfigWrapper config = ConfigWrapper.parse("src/test/resources/conf/config.yml"); + ObjectMapper mapper = new ObjectMapper(); + queueManager = mapper.convertValue(config.getQueueManagers().get(0), QueueManager.class); + meter = otelTesting.getOpenTelemetry().getMeter("opentelemetry.io/mq"); + context = + new MetricsCollectorContext(queueManager, pcfMessageAgent, null, new MetricsConfig(config)); + } + + @Test + void testPublishMetrics() throws Exception { + when(pcfMessageAgent.send(any(PCFMessage.class))) + .thenReturn(createPCFResponseForInquireChannelStatusCmd()); + classUnderTest = new ChannelMetricsCollector(meter); + + classUnderTest.accept(context); + + List metricsList = + new ArrayList<>( + List.of( + "mq.message.count", + "mq.status", + "mq.byte.sent", + "mq.byte.received", + "mq.buffers.sent", + "mq.buffers.received")); + + for (MetricData metric : otelTesting.getMetrics()) { + if (metricsList.remove(metric.getName())) { + if (metric.getName().equals("mq.message.count")) { + assertThat(metric.getLongGaugeData().getPoints().iterator().next().getValue()) + .isEqualTo(17); + } + + if (metric.getName().equals("mq.status")) { + assertThat(metric.getLongGaugeData().getPoints().iterator().next().getValue()) + .isEqualTo(3); + } + if (metric.getName().equals("mq.byte.sent")) { + assertThat(metric.getLongGaugeData().getPoints().iterator().next().getValue()) + .isEqualTo(6984); + } + if (metric.getName().equals("mq.byte.received")) { + assertThat(metric.getLongGaugeData().getPoints().iterator().next().getValue()) + .isEqualTo(5772); + } + if (metric.getName().equals("mq.buffers.sent")) { + assertThat(metric.getLongGaugeData().getPoints().iterator().next().getValue()) + .isEqualTo(19); + } + if (metric.getName().equals("mq.buffers.received")) { + assertThat(metric.getLongGaugeData().getPoints().iterator().next().getValue()) + .isEqualTo(20); + } + } + } + assertThat(metricsList).isEmpty(); + } + + /* + Request + PCFMessage: + MQCFH [type: 1, strucLength: 36, version: 1, command: 42 (MQCMD_INQUIRE_CHANNEL_STATUS), msgSeqNumber: 1, control: 1, compCode: 0, reason: 0, parameterCount: 3] + MQCFST [type: 4, strucLength: 24, parameter: 3501 (MQCACH_FIRST/MQCACH_CHANNEL_NAME), codedCharSetId: 0, stringLength: 1, string: *] + MQCFIN [type: 3, strucLength: 16, parameter: 1523 (MQIACH_CHANNEL_INSTANCE_TYPE), value: 1011] + MQCFIL [type: 5, strucLength: 48, parameter: 1524 (MQIACH_CHANNEL_INSTANCE_ATTRS), count: 8, values: {3501, 3506, 1527, 1534, 1538, 1535, 1539, 1536}] + + Response + PCFMessage: + MQCFH [type: 2, strucLength: 36, version: 1, command: 42 (MQCMD_INQUIRE_CHANNEL_STATUS), msgSeqNumber: 1, control: 1, compCode: 0, reason: 0, parameterCount: 11] + MQCFST [type: 4, strucLength: 40, parameter: 3501 (MQCACH_FIRST/MQCACH_CHANNEL_NAME), codedCharSetId: 819, stringLength: 20, string: DEV.ADMIN.SVRCONN ] + MQCFIN [type: 3, strucLength: 16, parameter: 1511 (MQIACH_CHANNEL_TYPE), value: 7] + MQCFIN [type: 3, strucLength: 16, parameter: 1539 (MQIACH_BUFFERS_RCVD/MQIACH_BUFFERS_RECEIVED), value: 20] + MQCFIN [type: 3, strucLength: 16, parameter: 1538 (MQIACH_BUFFERS_SENT), value: 19] + MQCFIN [type: 3, strucLength: 16, parameter: 1536 (MQIACH_BYTES_RCVD/MQIACH_BYTES_RECEIVED), value: 5772] + MQCFIN [type: 3, strucLength: 16, parameter: 1535 (MQIACH_BYTES_SENT), value: 6984] + MQCFST [type: 4, strucLength: 284, parameter: 3506 (MQCACH_CONNECTION_NAME), codedCharSetId: 819, stringLength: 264, string: 172.17.0.1] + MQCFIN [type: 3, strucLength: 16, parameter: 1523 (MQIACH_CHANNEL_INSTANCE_TYPE), value: 1011] + MQCFIN [type: 3, strucLength: 16, parameter: 1534 (MQIACH_MSGS), value: 17] + MQCFIN [type: 3, strucLength: 16, parameter: 1527 (MQIACH_CHANNEL_STATUS), value: 3] + MQCFIN [type: 3, strucLength: 16, parameter: 1609 (MQIACH_CHANNEL_SUBSTATE), value: 300] + */ + + private PCFMessage[] createPCFResponseForInquireChannelStatusCmd() { + PCFMessage response1 = new PCFMessage(2, CMQCFC.MQCMD_INQUIRE_CHANNEL_STATUS, 1, true); + response1.addParameter(CMQCFC.MQCACH_CHANNEL_NAME, "DEV.ADMIN.SVRCONN"); + response1.addParameter(CMQCFC.MQIACH_CHANNEL_TYPE, 7); + response1.addParameter(CMQCFC.MQIACH_BUFFERS_RECEIVED, 20); + response1.addParameter(CMQCFC.MQIACH_BUFFERS_SENT, 19); + response1.addParameter(CMQCFC.MQIACH_BYTES_RECEIVED, 5772); + response1.addParameter(CMQCFC.MQIACH_BYTES_SENT, 6984); + response1.addParameter(CMQCFC.MQCACH_CONNECTION_NAME, "172.17.0.1 "); + response1.addParameter(CMQCFC.MQIACH_CHANNEL_INSTANCE_TYPE, 1011); + response1.addParameter(CMQCFC.MQIACH_MSGS, 17); + response1.addParameter(CMQCFC.MQIACH_CHANNEL_STATUS, 3); + response1.addParameter(CMQCFC.MQIACH_CHANNEL_SUBSTATE, 300); + response1.addParameter(CMQCFC.MQCACH_CHANNEL_START_DATE, "2012-01-03"); + response1.addParameter(CMQCFC.MQCACH_CHANNEL_START_TIME, "22.33.44"); + response1.addParameter(CMQCFC.MQCACH_MCA_JOB_NAME, "000042040000000C"); + + PCFMessage response2 = new PCFMessage(2, CMQCFC.MQCMD_INQUIRE_CHANNEL_STATUS, 2, true); + response2.addParameter(CMQCFC.MQCACH_CHANNEL_NAME, "DEV.APP.SVRCONN"); + response2.addParameter(CMQCFC.MQIACH_CHANNEL_TYPE, 7); + response2.addParameter(CMQCFC.MQIACH_BUFFERS_RECEIVED, 20); + response2.addParameter(CMQCFC.MQIACH_BUFFERS_SENT, 19); + response2.addParameter(CMQCFC.MQIACH_BYTES_RECEIVED, 5772); + response2.addParameter(CMQCFC.MQIACH_BYTES_SENT, 6984); + response2.addParameter(CMQCFC.MQCACH_CONNECTION_NAME, "172.17.0.2 "); + response2.addParameter(CMQCFC.MQIACH_CHANNEL_INSTANCE_TYPE, 1011); + response2.addParameter(CMQCFC.MQIACH_MSGS, 17); + response2.addParameter(CMQCFC.MQIACH_CHANNEL_STATUS, 3); + response2.addParameter(CMQCFC.MQIACH_CHANNEL_SUBSTATE, 300); + response2.addParameter(CMQCFC.MQCACH_CHANNEL_START_DATE, "2012-01-04"); + response2.addParameter(CMQCFC.MQCACH_CHANNEL_START_TIME, "22.33.45"); + response2.addParameter(CMQCFC.MQCACH_MCA_JOB_NAME, "000042040000000D"); + + PCFMessage response3 = new PCFMessage(2, CMQCFC.MQCMD_INQUIRE_CHANNEL_STATUS, 2, true); + response3.addParameter(CMQCFC.MQCACH_CHANNEL_NAME, "TEST.APP.SVRCONN"); + response3.addParameter(CMQCFC.MQIACH_CHANNEL_TYPE, 7); + response3.addParameter(CMQCFC.MQIACH_BUFFERS_RECEIVED, 20); + response3.addParameter(CMQCFC.MQIACH_BUFFERS_SENT, 19); + response3.addParameter(CMQCFC.MQIACH_BYTES_RECEIVED, 5772); + response3.addParameter(CMQCFC.MQIACH_BYTES_SENT, 6984); + response3.addParameter(CMQCFC.MQCACH_CONNECTION_NAME, "172.17.0.2 "); + response3.addParameter(CMQCFC.MQIACH_CHANNEL_INSTANCE_TYPE, 1011); + response3.addParameter(CMQCFC.MQIACH_MSGS, 17); + response3.addParameter(CMQCFC.MQIACH_CHANNEL_STATUS, 3); + response3.addParameter(CMQCFC.MQIACH_CHANNEL_SUBSTATE, 300); + response3.addParameter(CMQCFC.MQCACH_CHANNEL_START_DATE, "2012-01-05"); + response3.addParameter(CMQCFC.MQCACH_CHANNEL_START_TIME, "22.33.46"); + response3.addParameter(CMQCFC.MQCACH_MCA_JOB_NAME, "000042040000000E"); + + return new PCFMessage[] {response1, response2, response3}; + } + + @Test + void testPublishMetrics_nullResponse() throws Exception { + when(pcfMessageAgent.send(any(PCFMessage.class))).thenReturn(null); + classUnderTest = new ChannelMetricsCollector(meter); + + classUnderTest.accept(context); + assertThat(otelTesting.getMetrics()).isEmpty(); + } + + @Test + void testPublishMetrics_emptyResponse() throws Exception { + when(pcfMessageAgent.send(any(PCFMessage.class))).thenReturn(new PCFMessage[] {}); + classUnderTest = new ChannelMetricsCollector(meter); + + classUnderTest.accept(context); + assertThat(otelTesting.getMetrics()).isEmpty(); + } + + @ParameterizedTest + @MethodSource("exceptionsToThrow") + void testPublishMetrics_pfException(Exception exceptionToThrow) throws Exception { + when(pcfMessageAgent.send(any(PCFMessage.class))).thenThrow(exceptionToThrow); + classUnderTest = new ChannelMetricsCollector(meter); + + classUnderTest.accept(context); + + List exported = otelTesting.getMetrics(); + assertThat(exported.get(0).getLongGaugeData().getPoints()).hasSize(1); + assertThatMetric(exported.get(0), 0).hasName("mq.manager.active.channels").hasValue(0); + } + + static Stream exceptionsToThrow() { + return Stream.of( + arguments(new RuntimeException("KBAOOM")), + arguments(new PCFException(91, MQRCCF_CHL_STATUS_NOT_FOUND, "flimflam")), + arguments(new PCFException(4, MQRC_SELECTOR_ERROR, "shazbot")), + arguments(new PCFException(4, 42, "boz"))); + } +} diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollectorTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollectorTest.java new file mode 100644 index 000000000..cd7b3b3ae --- /dev/null +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollectorTest.java @@ -0,0 +1,106 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ibm.mq.constants.CMQCFC; +import com.ibm.mq.constants.CMQXC; +import com.ibm.mq.headers.pcf.PCFMessage; +import com.ibm.mq.headers.pcf.PCFMessageAgent; +import io.opentelemetry.ibm.mq.config.QueueManager; +import io.opentelemetry.ibm.mq.metrics.MetricsConfig; +import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class InquireChannelCmdCollectorTest { + + @RegisterExtension + static final OpenTelemetryExtension otelTesting = OpenTelemetryExtension.create(); + + InquireChannelCmdCollector classUnderTest; + + MetricsCollectorContext context; + Meter meter; + @Mock PCFMessageAgent pcfMessageAgent; + + @BeforeEach + public void setup() throws Exception { + ConfigWrapper config = ConfigWrapper.parse("src/test/resources/conf/config.yml"); + ObjectMapper mapper = new ObjectMapper(); + QueueManager queueManager = + mapper.convertValue(config.getQueueManagers().get(0), QueueManager.class); + meter = otelTesting.getOpenTelemetry().getMeter("opentelemetry.io/mq"); + context = + new MetricsCollectorContext(queueManager, pcfMessageAgent, null, new MetricsConfig(config)); + } + + @Test + public void testProcessPCFRequestAndPublishQMetricsForInquireQStatusCmd() throws Exception { + when(pcfMessageAgent.send(any(PCFMessage.class))) + .thenReturn(createPCFResponseForInquireChannelCmd()); + classUnderTest = new InquireChannelCmdCollector(meter); + classUnderTest.accept(context); + List metricsList = + new ArrayList<>( + List.of( + "mq.message.retry.count", "mq.message.received.count", "mq.message.sent.count")); + for (MetricData metric : otelTesting.getMetrics()) { + if (metricsList.remove(metric.getName())) { + if (metric.getName().equals("mq.message.retry.count")) { + assertThat(metric.getLongGaugeData().getPoints().iterator().next().getValue()) + .isEqualTo(22); + } + if (metric.getName().equals("mq.message.received.count")) { + assertThat(metric.getLongGaugeData().getPoints().iterator().next().getValue()) + .isEqualTo(42); + } + if (metric.getName().equals("mq.message.sent.count")) { + assertThat(metric.getLongGaugeData().getPoints().iterator().next().getValue()) + .isEqualTo(64); + } + } + } + assertThat(metricsList).isEmpty(); + } + + private PCFMessage[] createPCFResponseForInquireChannelCmd() { + PCFMessage response1 = new PCFMessage(2, CMQCFC.MQCMD_INQUIRE_CHANNEL, 1, true); + response1.addParameter(CMQCFC.MQCACH_CHANNEL_NAME, "my.channel"); + response1.addParameter(CMQCFC.MQIACH_CHANNEL_TYPE, CMQXC.MQCHT_SVRCONN); + response1.addParameter(CMQCFC.MQIACH_MR_COUNT, 22); + response1.addParameter(CMQCFC.MQIACH_MSGS_RECEIVED, 42); + response1.addParameter(CMQCFC.MQIACH_MSGS_SENT, 64); + response1.addParameter(CMQCFC.MQIACH_MAX_INSTANCES, 3); + response1.addParameter(CMQCFC.MQIACH_MAX_INSTS_PER_CLIENT, 3); + + return new PCFMessage[] {response1}; + } +} diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollectorTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollectorTest.java new file mode 100644 index 000000000..f1e05435c --- /dev/null +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollectorTest.java @@ -0,0 +1,112 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.when; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ibm.mq.constants.CMQCFC; +import com.ibm.mq.headers.pcf.PCFMessage; +import com.ibm.mq.headers.pcf.PCFMessageAgent; +import io.opentelemetry.ibm.mq.config.QueueManager; +import io.opentelemetry.ibm.mq.metrics.MetricsConfig; +import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; +import io.opentelemetry.sdk.metrics.data.LongPointData; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class ListenerMetricsCollectorTest { + @RegisterExtension + static final OpenTelemetryExtension otelTesting = OpenTelemetryExtension.create(); + + ListenerMetricsCollector classUnderTest; + QueueManager queueManager; + ConfigWrapper config; + @Mock private PCFMessageAgent pcfMessageAgent; + + @BeforeEach + public void setup() throws Exception { + config = ConfigWrapper.parse("src/test/resources/conf/config.yml"); + ObjectMapper mapper = new ObjectMapper(); + queueManager = mapper.convertValue(config.getQueueManagers().get(0), QueueManager.class); + } + + @Test + public void testPublishMetrics() throws Exception { + when(pcfMessageAgent.send(any(PCFMessage.class))) + .thenReturn(createPCFResponseForInquireListenerStatusCmd()); + + MetricsCollectorContext context = + new MetricsCollectorContext(queueManager, pcfMessageAgent, null, new MetricsConfig(config)); + classUnderTest = + new ListenerMetricsCollector( + otelTesting.getOpenTelemetry().getMeter("opentelemetry.io/mq")); + classUnderTest.accept(context); + + MetricData metric = otelTesting.getMetrics().get(0); + assertThat(metric.getName()).isEqualTo("mq.listener.status"); + Set values = new HashSet<>(); + values.add(2L); + values.add(3L); + assertThat( + metric.getLongGaugeData().getPoints().stream() + .map(LongPointData::getValue) + .collect(Collectors.toSet())) + .isEqualTo(values); + } + + /* + Request + PCFMessage: + MQCFH [type: 1, strucLength: 36, version: 1, command: 98 (MQCMD_INQUIRE_LISTENER_STATUS), msgSeqNumber: 1, control: 1, compCode: 0, reason: 0, parameterCount: 2] + MQCFST [type: 4, strucLength: 24, parameter: 3554 (MQCACH_LISTENER_NAME), codedCharSetId: 0, stringLength: 1, string: *] + MQCFIL [type: 5, strucLength: 24, parameter: 1223 (MQIACF_LISTENER_STATUS_ATTRS), count: 2, values: {3554, 1599}] + + Response + PCFMessage: + MQCFH [type: 2, strucLength: 36, version: 1, command: 98 (MQCMD_INQUIRE_LISTENER_STATUS), msgSeqNumber: 1, control: 1, compCode: 0, reason: 0, parameterCount: 2] + MQCFST [type: 4, strucLength: 48, parameter: 3554 (MQCACH_LISTENER_NAME), codedCharSetId: 819, stringLength: 27, string: SYSTEM.DEFAULT.LISTENER.TCP] + MQCFIN [type: 3, strucLength: 16, parameter: 1599 (MQIACH_LISTENER_STATUS), value: 2] + */ + + private PCFMessage[] createPCFResponseForInquireListenerStatusCmd() { + PCFMessage response1 = new PCFMessage(2, CMQCFC.MQCMD_INQUIRE_LISTENER_STATUS, 1, true); + response1.addParameter(CMQCFC.MQCACH_LISTENER_NAME, "DEV.DEFAULT.LISTENER.TCP"); + response1.addParameter(CMQCFC.MQIACH_LISTENER_STATUS, 2); + + PCFMessage response2 = new PCFMessage(2, CMQCFC.MQCMD_INQUIRE_LISTENER_STATUS, 2, true); + response2.addParameter(CMQCFC.MQCACH_LISTENER_NAME, "DEV.LISTENER.TCP"); + response2.addParameter(CMQCFC.MQIACH_LISTENER_STATUS, 3); + + PCFMessage response3 = new PCFMessage(2, CMQCFC.MQCMD_INQUIRE_LISTENER_STATUS, 3, true); + response3.addParameter(CMQCFC.MQCACH_LISTENER_NAME, "SYSTEM.LISTENER.TCP"); + response3.addParameter(CMQCFC.MQIACH_LISTENER_STATUS, 1); + + return new PCFMessage[] {response1, response2, response3}; + } +} diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/MetricAssert.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/MetricAssert.java new file mode 100644 index 000000000..b4bbbe6f6 --- /dev/null +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/MetricAssert.java @@ -0,0 +1,48 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import io.opentelemetry.sdk.metrics.data.LongPointData; +import io.opentelemetry.sdk.metrics.data.MetricData; +import org.assertj.core.api.Assertions; + +public class MetricAssert { + + private final MetricData metric; + private final int pointOffset; + + public MetricAssert(MetricData metric, int pointOffset) { + this.metric = metric; + this.pointOffset = pointOffset; + } + + static MetricAssert assertThatMetric(MetricData metric, int pointOffset) { + return new MetricAssert(metric, pointOffset); + } + + MetricAssert hasName(String name) { + Assertions.assertThat(metric.getName()).isEqualTo(name); + return this; + } + + MetricAssert hasValue(long value) { + Assertions.assertThat( + ((LongPointData) metric.getLongGaugeData().getPoints().toArray()[this.pointOffset]) + .getValue()) + .isEqualTo(value); + return this; + } +} diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java new file mode 100644 index 000000000..21476871a --- /dev/null +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java @@ -0,0 +1,364 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ibm.mq.constants.CMQC; +import com.ibm.mq.constants.CMQCFC; +import com.ibm.mq.headers.pcf.PCFMessage; +import com.ibm.mq.headers.pcf.PCFMessageAgent; +import io.opentelemetry.ibm.mq.config.QueueManager; +import io.opentelemetry.ibm.mq.metrics.MetricsConfig; +import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.sdk.metrics.data.LongPointData; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class QueueCollectionBuddyTest { + @RegisterExtension + static final OpenTelemetryExtension otelTesting = OpenTelemetryExtension.create(); + + QueueCollectionBuddy classUnderTest; + QueueManager queueManager; + MetricsCollectorContext collectorContext; + Meter meter; + @Mock private PCFMessageAgent pcfMessageAgent; + + @BeforeEach + void setup() throws Exception { + ConfigWrapper config = ConfigWrapper.parse("src/test/resources/conf/config.yml"); + ObjectMapper mapper = new ObjectMapper(); + queueManager = mapper.convertValue(config.getQueueManagers().get(0), QueueManager.class); + meter = otelTesting.getOpenTelemetry().getMeter("opentelemetry.io/mq"); + collectorContext = + new MetricsCollectorContext(queueManager, pcfMessageAgent, null, new MetricsConfig(config)); + } + + @Test + void testProcessPCFRequestAndPublishQMetricsForInquireQStatusCmd() throws Exception { + QueueCollectorSharedState sharedState = new QueueCollectorSharedState(); + sharedState.putQueueType("AMQ.5AF1608820C7D76E", "local-transmission"); + sharedState.putQueueType("DEV.DEAD.LETTER.QUEUE", "local-transmission"); + sharedState.putQueueType("DEV.QUEUE.1", "local-transmission"); + PCFMessage request = createPCFRequestForInquireQStatusCmd(); + when(pcfMessageAgent.send(request)).thenReturn(createPCFResponseForInquireQStatusCmd()); + + classUnderTest = new QueueCollectionBuddy(meter, sharedState); + classUnderTest.processPCFRequestAndPublishQMetrics( + collectorContext, request, "*", InquireQStatusCmdCollector.ATTRIBUTES); + + Map> expectedValues = + new HashMap>() { + { + put( + "DEV.DEAD.LETTER.QUEUE", + new HashMap() { + { + put("mq.oldest.msg.age", -1L); + put("mq.uncommitted.messages", 0L); + put("mq.onqtime.1", -1L); + put("mq.onqtime.2", -1L); + put("mq.queue.depth", 0L); + } + }); + put( + "DEV.QUEUE.1", + new HashMap() { + { + put("mq.oldest.msg.age", -1L); + put("mq.uncommitted.messages", 10L); + put("mq.onqtime.1", -1L); + put("mq.onqtime.2", -1L); + put("mq.queue.depth", 1L); + } + }); + } + }; + + for (MetricData metric : otelTesting.getMetrics()) { + for (LongPointData d : metric.getLongGaugeData().getPoints()) { + String queueName = d.getAttributes().get(AttributeKey.stringKey("queue.name")); + Long expectedValue = expectedValues.get(queueName).remove(metric.getName()); + assertThat(d.getValue()).isEqualTo(expectedValue); + } + } + + for (Map metrics : expectedValues.values()) { + assertThat(metrics).isEmpty(); + } + } + + @Test + void testProcessPCFRequestAndPublishQMetricsForInquireQCmd() throws Exception { + PCFMessage request = createPCFRequestForInquireQCmd(); + when(pcfMessageAgent.send(request)).thenReturn(createPCFResponseForInquireQCmd()); + classUnderTest = new QueueCollectionBuddy(meter, new QueueCollectorSharedState()); + classUnderTest.processPCFRequestAndPublishQMetrics( + collectorContext, request, "*", InquireQCmdCollector.ATTRIBUTES); + + Map> expectedValues = + new HashMap>() { + { + put( + "DEV.DEAD.LETTER.QUEUE", + new HashMap() { + { + put("mq.queue.depth", 2L); + put("mq.max.queue.depth", 5000L); + put("mq.open.input.count", 2L); + put("mq.open.output.count", 2L); + } + }); + put( + "DEV.QUEUE.1", + new HashMap() { + { + put("mq.queue.depth", 3L); + put("mq.max.queue.depth", 5000L); + put("mq.open.input.count", 3L); + put("mq.open.output.count", 3L); + } + }); + } + }; + + for (MetricData metric : otelTesting.getMetrics()) { + for (LongPointData d : metric.getLongGaugeData().getPoints()) { + String queueName = d.getAttributes().get(AttributeKey.stringKey("queue.name")); + Long expectedValue = expectedValues.get(queueName).remove(metric.getName()); + assertThat(d.getValue()).isEqualTo(expectedValue); + } + } + + for (Map metrics : expectedValues.values()) { + assertThat(metrics).isEmpty(); + } + } + + @Test + void testProcessPCFRequestAndPublishQMetricsForResetQStatsCmd() throws Exception { + QueueCollectorSharedState sharedState = new QueueCollectorSharedState(); + sharedState.putQueueType("AMQ.5AF1608820C7D76E", "local-transmission"); + sharedState.putQueueType("DEV.DEAD.LETTER.QUEUE", "local-transmission"); + sharedState.putQueueType("DEV.QUEUE.1", "local-transmission"); + PCFMessage request = createPCFRequestForResetQStatsCmd(); + when(pcfMessageAgent.send(request)).thenReturn(createPCFResponseForResetQStatsCmd()); + classUnderTest = new QueueCollectionBuddy(meter, sharedState); + classUnderTest.processPCFRequestAndPublishQMetrics( + collectorContext, request, "*", ResetQStatsCmdCollector.ATTRIBUTES); + + for (MetricData metric : otelTesting.getMetrics()) { + Iterator iterator = metric.getLongGaugeData().getPoints().iterator(); + if (metric.getName().equals("mq.high.queue.depth")) { + assertThat(iterator.next().getValue()).isEqualTo(10); + } else if (metric.getName().equals("mq.message.deq.count")) { + assertThat(iterator.next().getValue()).isEqualTo(0); + } else if (metric.getName().equals("mq.message.enq.count")) { + assertThat(iterator.next().getValue()).isEqualTo(3); + } + } + } + + /* + PCFMessage: + MQCFH [type: 1, strucLength: 36, version: 1, command: 41 (MQCMD_INQUIRE_Q_STATUS), msgSeqNumber: 1, control: 1, compCode: 0, reason: 0, parameterCount: 2] + MQCFST [type: 4, strucLength: 24, parameter: 2016 (MQCA_Q_NAME), codedCharSetId: 0, stringLength: 1, string: *] + MQCFIL [type: 5, strucLength: 32, parameter: 1026 (MQIACF_Q_STATUS_ATTRS), count: 4, values: {2016, 1226, 1227, 1027}] + */ + private PCFMessage createPCFRequestForInquireQStatusCmd() { + PCFMessage request = new PCFMessage(CMQCFC.MQCMD_INQUIRE_Q_STATUS); + request.addParameter(CMQC.MQCA_Q_NAME, "*"); + request.addParameter(CMQCFC.MQIACF_Q_STATUS_ATTRS, new int[] {2016, 1226, 1227, 1027}); + return request; + } + + /* + 0 = {PCFMessage@6026} "PCFMessage: + MQCFH [type: 2, strucLength: 36, version: 2, command: 41 (MQCMD_INQUIRE_Q_STATUS), msgSeqNumber: 1, control: 0, compCode: 0, reason: 0, parameterCount: 6] + MQCFST [type: 4, strucLength: 68, parameter: 2016 (MQCA_Q_NAME), codedCharSetId: 819, stringLength: 48, string: AMQ.5AF1608820C7D76E ] + MQCFIN [type: 3, strucLength: 16, parameter: 1103 (MQIACF_Q_STATUS_TYPE), value: 1105] + MQCFIN [type: 3, strucLength: 16, parameter: 3 (MQIA_CURRENT_Q_DEPTH), value: 12] + MQCFIN [type: 3, strucLength: 16, parameter: 1227 (MQIACF_OLDEST_MSG_AGE), value: -1] + MQCFIL [type: 5, strucLength: 24, parameter: 1226 (MQIACF_Q_TIME_INDICATOR), count: 2, values: {-1, -1}] + MQCFIN [type: 3, strucLength: 16, parameter: 1027 (MQIACF_UNCOMMITTED_MSGS), value: 0]" + + 1 = {PCFMessage@6029} "PCFMessage: + MQCFH [type: 2, strucLength: 36, version: 2, command: 41 (MQCMD_INQUIRE_Q_STATUS), msgSeqNumber: 2, control: 0, compCode: 0, reason: 0, parameterCount: 6] + MQCFST [type: 4, strucLength: 68, parameter: 2016 (MQCA_Q_NAME), codedCharSetId: 819, stringLength: 48, string: DEV.DEAD.LETTER.QUEUE ] + MQCFIN [type: 3, strucLength: 16, parameter: 1103 (MQIACF_Q_STATUS_TYPE), value: 1105] + MQCFIN [type: 3, strucLength: 16, parameter: 3 (MQIA_CURRENT_Q_DEPTH), value: 0] + MQCFIN [type: 3, strucLength: 16, parameter: 1227 (MQIACF_OLDEST_MSG_AGE), value: -1] + MQCFIL [type: 5, strucLength: 24, parameter: 1226 (MQIACF_Q_TIME_INDICATOR), count: 2, values: {-1, -1}] + MQCFIN [type: 3, strucLength: 16, parameter: 1027 (MQIACF_UNCOMMITTED_MSGS), value: 0]" + + 2 = {PCFMessage@6030} "PCFMessage: + MQCFH [type: 2, strucLength: 36, version: 2, command: 41 (MQCMD_INQUIRE_Q_STATUS), msgSeqNumber: 3, control: 0, compCode: 0, reason: 0, parameterCount: 6] + MQCFST [type: 4, strucLength: 68, parameter: 2016 (MQCA_Q_NAME), codedCharSetId: 819, stringLength: 48, string: DEV.QUEUE.1 ] + MQCFIN [type: 3, strucLength: 16, parameter: 1103 (MQIACF_Q_STATUS_TYPE), value: 1105] + MQCFIN [type: 3, strucLength: 16, parameter: 3 (MQIA_CURRENT_Q_DEPTH), value: 1] + MQCFIN [type: 3, strucLength: 16, parameter: 1227 (MQIACF_OLDEST_MSG_AGE), value: -1] + MQCFIL [type: 5, strucLength: 24, parameter: 1226 (MQIACF_Q_TIME_INDICATOR), count: 2, values: {-1, -1}] + MQCFIN [type: 3, strucLength: 16, parameter: 1027 (MQIACF_UNCOMMITTED_MSGS), value: 0]" + */ + private PCFMessage[] createPCFResponseForInquireQStatusCmd() { + PCFMessage response1 = new PCFMessage(2, CMQCFC.MQCMD_INQUIRE_Q_STATUS, 1, false); + response1.addParameter(CMQC.MQCA_Q_NAME, "AMQ.5AF1608820C7D76E"); + response1.addParameter(CMQCFC.MQIACF_Q_STATUS_TYPE, 1105); + response1.addParameter(CMQC.MQIA_CURRENT_Q_DEPTH, 12); + response1.addParameter(CMQCFC.MQIACF_OLDEST_MSG_AGE, -1); + response1.addParameter(CMQCFC.MQIACF_Q_TIME_INDICATOR, new int[] {-1, -1}); + response1.addParameter(CMQCFC.MQIACF_UNCOMMITTED_MSGS, 0); + + PCFMessage response2 = new PCFMessage(2, CMQCFC.MQCMD_INQUIRE_Q_STATUS, 2, false); + response2.addParameter(CMQC.MQCA_Q_NAME, "DEV.DEAD.LETTER.QUEUE"); + response2.addParameter(CMQCFC.MQIACF_Q_STATUS_TYPE, 1105); + response2.addParameter(CMQC.MQIA_CURRENT_Q_DEPTH, 0); + response2.addParameter(CMQCFC.MQIACF_OLDEST_MSG_AGE, -1); + response2.addParameter(CMQCFC.MQIACF_Q_TIME_INDICATOR, new int[] {-1, -1}); + response2.addParameter(CMQCFC.MQIACF_UNCOMMITTED_MSGS, 0); + + PCFMessage response3 = new PCFMessage(2, CMQCFC.MQCMD_INQUIRE_Q_STATUS, 1, false); + response3.addParameter(CMQC.MQCA_Q_NAME, "DEV.QUEUE.1"); + response3.addParameter(CMQCFC.MQIACF_Q_STATUS_TYPE, 1105); + response3.addParameter(CMQC.MQIA_CURRENT_Q_DEPTH, 1); + response3.addParameter(CMQCFC.MQIACF_OLDEST_MSG_AGE, -1); + response3.addParameter(CMQCFC.MQIACF_Q_TIME_INDICATOR, new int[] {-1, -1}); + response3.addParameter(CMQCFC.MQIACF_UNCOMMITTED_MSGS, 10); + + return new PCFMessage[] {response1, response2, response3}; + } + + /* + PCFMessage: + MQCFH [type: 1, strucLength: 36, version: 1, command: 13 (MQCMD_INQUIRE_Q), msgSeqNumber: 1, control: 1, compCode: 0, reason: 0, parameterCount: 3] + MQCFST [type: 4, strucLength: 24, parameter: 2016 (MQCA_Q_NAME), codedCharSetId: 0, stringLength: 1, string: *] + MQCFIN [type: 3, strucLength: 16, parameter: 20 (MQIA_Q_TYPE), value: 1001] + MQCFIL [type: 5, strucLength: 36, parameter: 1002 (MQIACF_Q_ATTRS), count: 5, values: {2016, 15, 3, 17, 18}] + */ + private PCFMessage createPCFRequestForInquireQCmd() { + PCFMessage request = new PCFMessage(CMQCFC.MQCMD_INQUIRE_Q); + request.addParameter(CMQC.MQCA_Q_NAME, "*"); + request.addParameter(CMQC.MQIA_Q_TYPE, CMQC.MQQT_ALL); + request.addParameter(CMQCFC.MQIACF_Q_ATTRS, new int[] {2016, 15, 3, 17, 18}); + return request; + } + + /* + 0 = {PCFMessage@6059} "PCFMessage: + MQCFH [type: 2, strucLength: 36, version: 1, command: 13 (MQCMD_INQUIRE_Q), msgSeqNumber: 1, control: 0, compCode: 0, reason: 0, parameterCount: 6] + MQCFST [type: 4, strucLength: 68, parameter: 2016 (MQCA_Q_NAME), codedCharSetId: 819, stringLength: 48, string: AMQ.5AF1608820C76D80 ] + MQCFIN [type: 3, strucLength: 16, parameter: 20 (MQIA_Q_TYPE), value: 1] + MQCFIN [type: 3, strucLength: 16, parameter: 3 (MQIA_CURRENT_Q_DEPTH), value: 0] + MQCFIN [type: 3, strucLength: 16, parameter: 17 (MQIA_OPEN_INPUT_COUNT), value: 1] + MQCFIN [type: 3, strucLength: 16, parameter: 15 (MQIA_MAX_Q_DEPTH), value: 5000] + MQCFIN [type: 3, strucLength: 16, parameter: 18 (MQIA_OPEN_OUTPUT_COUNT), value: 1]" + + 1 = {PCFMessage@6060} "PCFMessage: + MQCFH [type: 2, strucLength: 36, version: 1, command: 13 (MQCMD_INQUIRE_Q), msgSeqNumber: 2, control: 0, compCode: 0, reason: 0, parameterCount: 6] + MQCFST [type: 4, strucLength: 68, parameter: 2016 (MQCA_Q_NAME), codedCharSetId: 819, stringLength: 48, string: DEV.DEAD.LETTER.QUEUE ] + MQCFIN [type: 3, strucLength: 16, parameter: 20 (MQIA_Q_TYPE), value: 1] + MQCFIN [type: 3, strucLength: 16, parameter: 3 (MQIA_CURRENT_Q_DEPTH), value: 0] + MQCFIN [type: 3, strucLength: 16, parameter: 17 (MQIA_OPEN_INPUT_COUNT), value: 0] + MQCFIN [type: 3, strucLength: 16, parameter: 15 (MQIA_MAX_Q_DEPTH), value: 5000] + MQCFIN [type: 3, strucLength: 16, parameter: 18 (MQIA_OPEN_OUTPUT_COUNT), value: 0]" + + 2 = {PCFMessage@6061} "PCFMessage: + MQCFH [type: 2, strucLength: 36, version: 1, command: 13 (MQCMD_INQUIRE_Q), msgSeqNumber: 3, control: 0, compCode: 0, reason: 0, parameterCount: 6] + MQCFST [type: 4, strucLength: 68, parameter: 2016 (MQCA_Q_NAME), codedCharSetId: 819, stringLength: 48, string: DEV.QUEUE.1 ] + MQCFIN [type: 3, strucLength: 16, parameter: 20 (MQIA_Q_TYPE), value: 1] + MQCFIN [type: 3, strucLength: 16, parameter: 3 (MQIA_CURRENT_Q_DEPTH), value: 0] + MQCFIN [type: 3, strucLength: 16, parameter: 17 (MQIA_OPEN_INPUT_COUNT), value: 0] + MQCFIN [type: 3, strucLength: 16, parameter: 15 (MQIA_MAX_Q_DEPTH), value: 5000] + MQCFIN [type: 3, strucLength: 16, parameter: 18 (MQIA_OPEN_OUTPUT_COUNT), value: 0]" + */ + + private PCFMessage[] createPCFResponseForInquireQCmd() { + PCFMessage response1 = new PCFMessage(2, CMQCFC.MQCMD_INQUIRE_Q, 1, false); + response1.addParameter(CMQC.MQCA_Q_NAME, "AMQ.5AF1608820C76D80"); + response1.addParameter(CMQC.MQIA_Q_TYPE, 1); + response1.addParameter(CMQC.MQIA_CURRENT_Q_DEPTH, 1); + response1.addParameter(CMQC.MQIA_OPEN_INPUT_COUNT, 1); + response1.addParameter(CMQC.MQIA_MAX_Q_DEPTH, 5000); + response1.addParameter(CMQC.MQIA_OPEN_OUTPUT_COUNT, 1); + response1.addParameter(CMQC.MQIA_USAGE, CMQC.MQUS_NORMAL); + + PCFMessage response2 = new PCFMessage(2, CMQCFC.MQCMD_INQUIRE_Q, 2, false); + response2.addParameter(CMQC.MQCA_Q_NAME, "DEV.DEAD.LETTER.QUEUE"); + response2.addParameter(CMQC.MQIA_Q_TYPE, 1); + response2.addParameter(CMQC.MQIA_CURRENT_Q_DEPTH, 2); + response2.addParameter(CMQC.MQIA_OPEN_INPUT_COUNT, 2); + response2.addParameter(CMQC.MQIA_MAX_Q_DEPTH, 5000); + response2.addParameter(CMQC.MQIA_OPEN_OUTPUT_COUNT, 2); + response2.addParameter(CMQC.MQIA_USAGE, CMQC.MQUS_TRANSMISSION); + + PCFMessage response3 = new PCFMessage(2, CMQCFC.MQCMD_INQUIRE_Q, 3, false); + response3.addParameter(CMQC.MQCA_Q_NAME, "DEV.QUEUE.1"); + response3.addParameter(CMQC.MQIA_Q_TYPE, 1); + response3.addParameter(CMQC.MQIA_CURRENT_Q_DEPTH, 3); + response3.addParameter(CMQC.MQIA_OPEN_INPUT_COUNT, 3); + response3.addParameter(CMQC.MQIA_MAX_Q_DEPTH, 5000); + response3.addParameter(CMQC.MQIA_OPEN_OUTPUT_COUNT, 3); + response3.addParameter(CMQC.MQIA_USAGE, CMQC.MQUS_TRANSMISSION); + + return new PCFMessage[] {response1, response2, response3}; + } + + /* + PCFMessage: + MQCFH [type: 1, strucLength: 36, version: 1, command: 17 (MQCMD_RESET_Q_STATS), msgSeqNumber: 1, control: 1, compCode: 0, reason: 0, parameterCount: 1] + MQCFST [type: 4, strucLength: 24, parameter: 2016 (MQCA_Q_NAME), codedCharSetId: 0, stringLength: 1, string: *] + */ + private PCFMessage createPCFRequestForResetQStatsCmd() { + PCFMessage request = new PCFMessage(CMQCFC.MQCMD_RESET_Q_STATS); + request.addParameter(CMQC.MQCA_Q_NAME, "*"); + return request; + } + + /* + 0 = {PCFMessage@6144} "PCFMessage: + MQCFH [type: 2, strucLength: 36, version: 1, command: 17 (MQCMD_RESET_Q_STATS), msgSeqNumber: 1, control: 0, compCode: 0, reason: 0, parameterCount: 5] + MQCFST [type: 4, strucLength: 68, parameter: 2016 (MQCA_Q_NAME), codedCharSetId: 819, stringLength: 48, string: DEV.DEAD.LETTER.QUEUE ] + MQCFIN [type: 3, strucLength: 16, parameter: 37 (MQIA_MSG_ENQ_COUNT), value: 0] + MQCFIN [type: 3, strucLength: 16, parameter: 38 (MQIA_MSG_DEQ_COUNT), value: 0] + MQCFIN [type: 3, strucLength: 16, parameter: 36 (MQIA_HIGH_Q_DEPTH), value: 0] + MQCFIN [type: 3, strucLength: 16, parameter: 35 (MQIA_TIME_SINCE_RESET), value: 65]" + */ + private PCFMessage[] createPCFResponseForResetQStatsCmd() { + PCFMessage response1 = new PCFMessage(2, CMQCFC.MQCMD_RESET_Q_STATS, 1, false); + response1.addParameter(CMQC.MQCA_Q_NAME, "DEV.DEAD.LETTER.QUEUE"); + response1.addParameter(CMQC.MQIA_MSG_ENQ_COUNT, 3); + response1.addParameter(CMQC.MQIA_MSG_DEQ_COUNT, 0); + response1.addParameter(CMQC.MQIA_HIGH_Q_DEPTH, 10); + response1.addParameter(CMQC.MQIA_TIME_SINCE_RESET, 65); + + return new PCFMessage[] {response1}; + } +} diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerMetricsCollectorTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerMetricsCollectorTest.java new file mode 100644 index 000000000..f5d2d3793 --- /dev/null +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerMetricsCollectorTest.java @@ -0,0 +1,130 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.when; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ibm.mq.constants.CMQC; +import com.ibm.mq.constants.CMQCFC; +import com.ibm.mq.headers.pcf.PCFMessage; +import com.ibm.mq.headers.pcf.PCFMessageAgent; +import io.opentelemetry.ibm.mq.config.QueueManager; +import io.opentelemetry.ibm.mq.metrics.MetricsConfig; +import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class QueueManagerMetricsCollectorTest { + + @RegisterExtension + static final OpenTelemetryExtension otelTesting = OpenTelemetryExtension.create(); + + QueueManagerMetricsCollector classUnderTest; + QueueManager queueManager; + MetricsCollectorContext context; + @Mock PCFMessageAgent pcfMessageAgent; + + @BeforeEach + public void setup() throws Exception { + + ConfigWrapper config = ConfigWrapper.parse("src/test/resources/conf/config.yml"); + ObjectMapper mapper = new ObjectMapper(); + queueManager = mapper.convertValue(config.getQueueManagers().get(0), QueueManager.class); + context = + new MetricsCollectorContext(queueManager, pcfMessageAgent, null, new MetricsConfig(config)); + } + + @Test + public void testProcessPCFRequestAndPublishQMetricsForInquireQStatusCmd() throws Exception { + when(pcfMessageAgent.send(any(PCFMessage.class))) + .thenReturn(createPCFResponseForInquireQMgrStatusCmd()); + classUnderTest = + new QueueManagerMetricsCollector( + otelTesting.getOpenTelemetry().getMeter("opentelemetry.io/mq")); + classUnderTest.accept(context); + List metricsList = new ArrayList<>(List.of("mq.manager.status")); + + for (MetricData metric : otelTesting.getMetrics()) { + if (metricsList.remove(metric.getName())) { + assertThat(metric.getLongGaugeData().getPoints().iterator().next().getValue()).isEqualTo(2); + } + } + assertThat(metricsList).isEmpty(); + } + + /* Request + PCFMessage: + MQCFH [type: 1, strucLength: 36, version: 1, command: 161 (MQCMD_INQUIRE_Q_MGR_STATUS), msgSeqNumber: 1, control: 1, compCode: 0, reason: 0, parameterCount: 1] + MQCFIL [type: 5, strucLength: 20, parameter: 1229 (MQIACF_Q_MGR_STATUS_ATTRS), count: 1, values: {1009}] + + Response + PCFMessage: + MQCFH [type: 2, strucLength: 36, version: 1, command: 161 (MQCMD_INQUIRE_Q_MGR_STATUS), msgSeqNumber: 1, control: 1, compCode: 0, reason: 0, parameterCount: 23] + MQCFST [type: 4, strucLength: 68, parameter: 2015 (MQCA_Q_MGR_NAME), codedCharSetId: 819, stringLength: 48, string: QM1 ] + MQCFIN [type: 3, strucLength: 16, parameter: 1149 (MQIACF_Q_MGR_STATUS), value: 2] + MQCFST [type: 4, strucLength: 20, parameter: 3208 (null), codedCharSetId: 819, stringLength: 0, string: ] + MQCFIN [type: 3, strucLength: 16, parameter: 1416 (null), value: 0] + MQCFIN [type: 3, strucLength: 16, parameter: 1232 (MQIACF_CHINIT_STATUS), value: 2] + MQCFIN [type: 3, strucLength: 16, parameter: 1233 (MQIACF_CMD_SERVER_STATUS), value: 2] + MQCFIN [type: 3, strucLength: 16, parameter: 1230 (MQIACF_CONNECTION_COUNT), value: 23] + MQCFST [type: 4, strucLength: 20, parameter: 3071 (MQCACF_CURRENT_LOG_EXTENT_NAME), codedCharSetId: 819, stringLength: 0, string: ] + MQCFST [type: 4, strucLength: 20, parameter: 2115 (null), codedCharSetId: 819, stringLength: 0, string: ] + MQCFST [type: 4, strucLength: 36, parameter: 2116 (null), codedCharSetId: 819, stringLength: 13, string: Installation1] + MQCFST [type: 4, strucLength: 28, parameter: 2117 (null), codedCharSetId: 819, stringLength: 8, string: /opt/mqm] + MQCFIN [type: 3, strucLength: 16, parameter: 1409 (null), value: 0] + MQCFIN [type: 3, strucLength: 16, parameter: 1420 (null), value: 9] + MQCFST [type: 4, strucLength: 44, parameter: 3074 (MQCACF_LOG_PATH), codedCharSetId: 819, stringLength: 24, string: /var/mqm/log/QM1/active/] + MQCFIN [type: 3, strucLength: 16, parameter: 1421 (null), value: 9] + MQCFST [type: 4, strucLength: 20, parameter: 3073 (MQCACF_MEDIA_LOG_EXTENT_NAME), codedCharSetId: 819, stringLength: 0, string: ] + MQCFIN [type: 3, strucLength: 16, parameter: 1417 (null), value: 0] + MQCFST [type: 4, strucLength: 20, parameter: 3072 (MQCACF_RESTART_LOG_EXTENT_NAME), codedCharSetId: 819, stringLength: 0, string: ] + MQCFIN [type: 3, strucLength: 16, parameter: 1418 (null), value: 1] + MQCFIN [type: 3, strucLength: 16, parameter: 1419 (null), value: 0] + MQCFIN [type: 3, strucLength: 16, parameter: 1325 (null), value: 0] + MQCFST [type: 4, strucLength: 32, parameter: 3175 (null), codedCharSetId: 819, stringLength: 12, string: 2018-05-08 ] + MQCFST [type: 4, strucLength: 28, parameter: 3176 (null), codedCharSetId: 819, stringLength: 8, string: 08.32.08] + */ + + private PCFMessage[] createPCFResponseForInquireQMgrStatusCmd() { + PCFMessage response1 = new PCFMessage(2, CMQCFC.MQCMD_INQUIRE_Q_MGR_STATUS, 1, true); + response1.addParameter(CMQC.MQCA_Q_MGR_NAME, "QM1"); + response1.addParameter(CMQCFC.MQIACF_Q_MGR_STATUS, 2); + response1.addParameter(CMQCFC.MQIACF_CHINIT_STATUS, 2); + response1.addParameter(CMQCFC.MQIACF_CMD_SERVER_STATUS, 2); + response1.addParameter(CMQCFC.MQIACF_CONNECTION_COUNT, 23); + response1.addParameter(CMQCFC.MQCACF_CURRENT_LOG_EXTENT_NAME, ""); + response1.addParameter(CMQCFC.MQCACF_LOG_PATH, "/var/mqm/log/QM1/active/"); + response1.addParameter(CMQCFC.MQCACF_MEDIA_LOG_EXTENT_NAME, ""); + response1.addParameter(CMQCFC.MQCACF_RESTART_LOG_EXTENT_NAME, ""); + response1.addParameter(CMQCFC.MQIACF_RESTART_LOG_SIZE, 42); + response1.addParameter(CMQCFC.MQIACF_REUSABLE_LOG_SIZE, 42); + response1.addParameter(CMQCFC.MQIACF_ARCHIVE_LOG_SIZE, 42); + + return new PCFMessage[] {response1}; + } +} diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/TopicMetricsCollectorTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/TopicMetricsCollectorTest.java new file mode 100644 index 000000000..738e50300 --- /dev/null +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/TopicMetricsCollectorTest.java @@ -0,0 +1,121 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.metricscollector; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.*; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ibm.mq.constants.CMQC; +import com.ibm.mq.constants.CMQCFC; +import com.ibm.mq.headers.pcf.PCFMessage; +import com.ibm.mq.headers.pcf.PCFMessageAgent; +import io.opentelemetry.ibm.mq.config.QueueManager; +import io.opentelemetry.ibm.mq.metrics.MetricsConfig; +import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; +import io.opentelemetry.sdk.metrics.data.LongPointData; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class TopicMetricsCollectorTest { + @RegisterExtension + static final OpenTelemetryExtension otelTesting = OpenTelemetryExtension.create(); + + TopicMetricsCollector classUnderTest; + QueueManager queueManager; + ConfigWrapper config; + @Mock private PCFMessageAgent pcfMessageAgent; + + @BeforeEach + void setup() throws Exception { + config = ConfigWrapper.parse("src/test/resources/conf/config.yml"); + ObjectMapper mapper = new ObjectMapper(); + queueManager = mapper.convertValue(config.getQueueManagers().get(0), QueueManager.class); + } + + @Test + void testPublishMetrics() throws Exception { + MetricsCollectorContext context = + new MetricsCollectorContext(queueManager, pcfMessageAgent, null, new MetricsConfig(config)); + classUnderTest = + new TopicMetricsCollector(otelTesting.getOpenTelemetry().getMeter("opentelemetry.io/mq")); + + when(pcfMessageAgent.send(any(PCFMessage.class))) + .thenReturn(createPCFResponseForInquireTopicStatusCmd()); + + classUnderTest.accept(context); + + List metricsList = + new ArrayList<>(List.of("mq.publish.count", "mq.subscription.count")); + + for (MetricData metric : otelTesting.getMetrics()) { + if (metricsList.remove(metric.getName())) { + if (metric.getName().equals("mq.publish.count")) { + Set values = new HashSet<>(); + values.add(2L); + values.add(3L); + assertThat( + metric.getLongGaugeData().getPoints().stream() + .map(LongPointData::getValue) + .collect(Collectors.toSet())) + .isEqualTo(values); + } + if (metric.getName().equals("mq.subscription.count")) { + Set values = new HashSet<>(); + values.add(3L); + values.add(4L); + assertThat( + metric.getLongGaugeData().getPoints().stream() + .map(LongPointData::getValue) + .collect(Collectors.toSet())) + .isEqualTo(values); + } + } + } + assertThat(metricsList).isEmpty(); + } + + private PCFMessage[] createPCFResponseForInquireTopicStatusCmd() { + PCFMessage response1 = new PCFMessage(2, CMQCFC.MQCMD_INQUIRE_TOPIC_STATUS, 1, false); + response1.addParameter(CMQC.MQCA_TOPIC_STRING, "test"); + response1.addParameter(CMQC.MQIA_PUB_COUNT, 2); + response1.addParameter(CMQC.MQIA_SUB_COUNT, 3); + + PCFMessage response2 = new PCFMessage(2, CMQCFC.MQCMD_INQUIRE_TOPIC_STATUS, 2, false); + response2.addParameter(CMQC.MQCA_TOPIC_STRING, "dev"); + response2.addParameter(CMQC.MQIA_PUB_COUNT, 3); + response2.addParameter(CMQC.MQIA_SUB_COUNT, 4); + + PCFMessage response3 = new PCFMessage(2, CMQCFC.MQCMD_INQUIRE_TOPIC_STATUS, 3, false); + response3.addParameter(CMQC.MQCA_TOPIC_STRING, "system"); + response3.addParameter(CMQC.MQIA_PUB_COUNT, 5); + response3.addParameter(CMQC.MQIA_SUB_COUNT, 6); + + return new PCFMessage[] {response1, response2, response3}; + } +} diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigTest.java new file mode 100644 index 000000000..9abc81dbf --- /dev/null +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigTest.java @@ -0,0 +1,65 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.opentelemetry; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class ConfigTest { + + private Properties systemProperties; + + @BeforeEach + public void cacheSystemProperties() { + systemProperties = new Properties(); + for (Map.Entry entry : System.getProperties().entrySet()) { + systemProperties.put(entry.getKey().toString(), entry.getValue().toString()); + } + } + + @Test + void testSSLConnection() { + Config.setUpSSLConnection( + new HashMap() { + { + put("keyStorePath", "foo"); + put("trustStorePath", "bar"); + put("keyStorePassword", "password"); + put("trustStorePassword", "password1"); + } + }); + + assertThat(System.getProperties().get("javax.net.ssl.keyStore")).isEqualTo("foo"); + assertThat(System.getProperties().get("javax.net.ssl.trustStorePath")).isEqualTo("bar"); + assertThat(System.getProperties().get("javax.net.ssl.keyStorePassword")).isEqualTo("password"); + assertThat(System.getProperties().get("javax.net.ssl.trustStorePassword")) + .isEqualTo("password1"); + } + + @AfterEach + public void resetSystemProperties() { + System.getProperties().clear(); + for (Map.Entry entry : systemProperties.entrySet()) { + System.setProperty(entry.getKey().toString(), entry.getValue().toString()); + } + } +} diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java new file mode 100644 index 000000000..973d3d7b9 --- /dev/null +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java @@ -0,0 +1,59 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.opentelemetry.ibm.mq.opentelemetry; + +import static java.util.Collections.singletonList; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import java.io.FileNotFoundException; +import java.time.Duration; +import java.time.temporal.ChronoUnit; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class ConfigWrapperTest { + + String file; + + @BeforeEach + void setUp() { + file = ConfigWrapperTest.class.getResource("/conf/config.yml").getFile(); + } + + @Test + void testQueueManagerNames() throws FileNotFoundException { + ConfigWrapper config = ConfigWrapper.parse(file); + assertThat(config.getQueueManagerNames()).isEqualTo(singletonList("QM1")); + } + + @Test + void testNumberOfThreads() throws FileNotFoundException { + ConfigWrapper config = ConfigWrapper.parse(file); + assertThat(config.getNumberOfThreads()).isEqualTo(20); + } + + @Test + void testTaskDelay() throws FileNotFoundException { + ConfigWrapper config = ConfigWrapper.parse(file); + assertThat(config.getTaskDelay()).isEqualTo(Duration.of(27, ChronoUnit.SECONDS)); + } + + @Test + void testTaskInitialDelay() throws FileNotFoundException { + ConfigWrapper config = ConfigWrapper.parse(file); + assertThat(config.getTaskInitialDelaySeconds()).isEqualTo(0); + } +} diff --git a/ibm-mq-metrics/src/test/resources/conf/config.yml b/ibm-mq-metrics/src/test/resources/conf/config.yml new file mode 100644 index 000000000..c53550cb8 --- /dev/null +++ b/ibm-mq-metrics/src/test/resources/conf/config.yml @@ -0,0 +1,217 @@ +#This is the timeout on queue metrics and channel metrics threads.Default value is 20 seconds. +#No need to change the default unless you know what you are doing. +#queueMetricsCollectionTimeoutInSeconds: 40 +#channelMetricsCollectionTimeoutInSeconds: 40 +#topicMetricsCollectionTimeoutInSeconds: 40 + +queueManagers: + - name: "QM1" + host: "localhost" + port: 1414 + + #The transport type for the queue manager connection, the default is "Bindings" for a binding type connection + #For bindings type, connection WMQ extension (i.e machine agent) need to be on the same machine on which WebbsphereMQ server is running + #For client type, connection change it to "Client". + transportType: "Client" + + #Channel name of the queue manager, channel should be server-conn type. + #This field is not required in case of transportType: Bindings + channelName: "DEV.ADMIN.SVRCONN" + + #for user access level, please check "Access Permissions" section on the extensions page + #comment out the username and password in case of transportType: Bindings. + username: "app" + password: "passw0rd" + + #PCF requests are always sent to SYSTEM.ADMIN.COMMAND.QUEUE. The PCF responses to these requests are sent to the default reply-to queue called + #SYSTEM.DEFAULT.MODEL.QUEUE. However, you can override this behavior and send it to a temporary dynamic queue by changing the modelQueueName and replyQueuePrefix fields. + #For more details around this https://www.ibm.com/support/knowledgecenter/SSFKSJ_7.5.0/com.ibm.mq.ref.adm.doc/q083240_.htm & https://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.adm.doc/q020010_.htm + #modelQueueName: "" + #replyQueuePrefix: "" + + # Name of the temporary dynamic queue holding the configuration events. This queue contains information regarding the configuration of the queue manager, notable MaxChannels and MaxActiveChannels. + # If unset, the default queue name `SYSTEM.ADMIN.CONFIG.EVENT` is applied. + # Configuration events need to be enabled explicitly in the queue manager configuration. See https://www.ibm.com/docs/en/ibm-mq/9.4.x?topic=monitoring-configuration-events for reference. + #configurationQueueName: "SYSTEM.ADMIN.CONFIG.EVENT" + + # Interval in milliseconds at which the configuration events in the configuration queue can be consumed. + # By default, no events are consumed. + #consumeConfigurationEventInterval: 600000 # 10 minutes + + # Enable running a queue manager refresh request to reload its configuration and create a configuration event. + # This action is only executed if no configuration events are found when reading the configuration queue.name: + # By default, this action is disabled. + #refreshQueueManagerConfigurationEnabled: false + + #Sets the CCSID used in the message descriptor of request and response messages. The default value is MQC.MQCCSI_Q_MGR. + #To set this, please use the integer value. + #ccsid: + + #Sets the encoding used in the message descriptor of request and response messages. The default value is MQC.MQENC_NATIVE. + #To set this, please use the integer value. + #encoding: + + # IBM Cipher Suite e.g. "SSL_RSA_WITH_AES_128_CBC_SHA256".. + # For translation to IBM Cipher http://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.dev.doc/q113210_.htm + # A cipher working for IBM Cloud MQ and Temurin JDK 8 is TLS_AES_128_GCM_SHA256 + #cipherSuite: "" + + + queueFilters: + #Can provide complete queue name or generic names. A generic name is a character string followed by an asterisk (*), + #for example ABC*, and it selects all objects having names that start with the selected character string. + #An asterisk on its own matches all possible names. + include: ["*"] + exclude: + #type value: STARTSWITH, EQUALS, ENDSWITH, CONTAINS + - type: "STARTSWITH" + #The name of the queue or queue name pattern as per queue filter, comma separated values + values: ["SYSTEM","AMQ"] + + + channelFilters: + #Can provide complete channel name or generic names. A generic name is a character string followed by an asterisk (*), + #for example ABC*, and it selects all objects having names that start with the selected character string. + #An asterisk on its own matches all possible names. + include: ["*"] + exclude: + #type value: STARTSWITH, EQUALS, ENDSWITH, CONTAINS + - type: "STARTSWITH" + #The name of the queue or queue name pattern as per queue filter, comma separated values + values: ["SYSTEM", "TEST"] + + listenerFilters: + #Can provide complete channel name or generic names. A generic name is a character string followed by an asterisk (*), + #for example ABC*, and it selects all objects having names that start with the selected character string. + #An asterisk on its own matches all possible names. + include: ["*"] + exclude: + #type value: STARTSWITH, EQUALS, ENDSWITH, CONTAINS + - type: "STARTSWITH" + #The name of the queue or queue name pattern as per queue filter, comma separated values + values: ["SYSTEM"] + + topicFilters: + # For topics, IBM MQ uses the topic wildcard characters ('#' and '+') and does not treat a trailing asterisk as a wildcard + # https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.5.0/com.ibm.mq.pla.doc/q005020_.htm + include: ["#"] + exclude: + #type value: STARTSWITH, EQUALS, ENDSWITH, CONTAINS + - type: "EQUALS" + #The name of the queue or queue name pattern as per queue filter, comma separated values + values: ["system","$SYS"] + +metrics: + "mq.message.retry.count": # Number of message retries + enabled: true + "mq.status": # Channel status + enabled: true + "mq.max.sharing.conversations": # Maximum number of conversations permitted on this channel instance. + enabled: true + "mq.current.sharing.conversations": # Current number of conversations permitted on this channel instance. + enabled: true + "mq.byte.received": # Number of bytes received + enabled: true + "mq.byte.sent": # Number of bytes sent + enabled: true + "mq.buffers.received": # Buffers received + enabled: true + "mq.buffers.sent": # Buffers sent + enabled: true + "mq.message.count": # Message count + enabled: true + "mq.open.input.count": # Count of applications sending messages to the queue + enabled: true + "mq.open.output.count": # Count of applications consuming messages from the queue + enabled: true + "mq.high.queue.depth": # The current high queue depth + enabled: true + "mq.service.interval": # The queue service interval + enabled: true + "mq.queue.depth.full.event": # The number of full queue events + enabled: true + "mq.queue.depth.high.event": # The number of high queue events + enabled: true + "mq.queue.depth.low.event": # The number of low queue events + enabled: true + "mq.uncommitted.messages": # Number of uncommitted messages + enabled: true + "mq.oldest.msg.age": # Queue message oldest age + enabled: true + "mq.current.max.queue.filesize": # Current maximum queue file size + enabled: true + "mq.current.queue.filesize": # Current queue file size + enabled: true + "mq.instances.per.client": # Instances per client + enabled: true + "mq.message.deq.count": # Message dequeue count + enabled: true + "mq.message.enq.count": # Message enqueue count + enabled: true + "mq.queue.depth": # Current queue depth + enabled: true + "mq.service.interval.event": # Queue service interval event + enabled: true + "mq.reusable.log.size": # The amount of space occupied, in megabytes, by log extents available to be reused. + enabled: true + "mq.manager.active.channels": # The queue manager active maximum channels limit + enabled: true + "mq.restart.log.size": # Size of the log data required for restart recovery in megabytes. + enabled: true + "mq.max.queue.depth": # Maximum queue depth + enabled: true + "mq.onqtime.1": # Amount of time, in microseconds, that a message spent on the queue, over a short period + enabled: true + "mq.onqtime.2": # Amount of time, in microseconds, that a message spent on the queue, over a longer period + enabled: true + "mq.message.received.count": # Number of messages received + enabled: true + "mq.message.sent.count": # Number of messages sent + enabled: true + "mq.max.instances": # Max channel instances + enabled: true + "mq.connection.count": # Active connections count + enabled: true + "mq.manager.status": # Queue manager status + enabled: true + "mq.heartbeat": # Queue manager heartbeat + enabled: true + "mq.archive.log.size": # Queue manager archive log size + enabled: true + "mq.manager.max.active.channels": # Queue manager max active channels + enabled: true + "mq.manager.statistics.interval": # Queue manager statistics interval + enabled: true + "mq.publish.count": # Topic publication count + enabled: true + "mq.subscription.count": # Topic subscription count + enabled: true + "mq.listener.status": # Listener status + enabled: true + "mq.unauthorized.event": # Number of authentication error events + enabled: true + "mq.manager.max.handles": # Max open handles + enabled: true + +#Run it as a scheduled task instead of running every minute. +#If you want to run this every minute, comment this out +taskSchedule: + numberOfThreads: 1 + taskDelaySeconds: 27 + + +sslConnection: + trustStorePath: "" + trustStorePassword: "" + + keyStorePath: "" + keyStorePassword: "" + + +# Configure the OTLP exporter using system properties keys following the specification https://opentelemetry.io/docs/languages/java/configuration/ +otlpExporter: + otel.exporter.otlp.endpoint: https://localhost:4318 + otel.exporter.otlp.protocol: http/protobuf + otel.metric.export.interval: 5s + otel.logs.exporter: none + otel.traces.exporter: none diff --git a/ibm-mq-metrics/src/test/resources/log4j.xml b/ibm-mq-metrics/src/test/resources/log4j.xml new file mode 100644 index 000000000..1fe17d69c --- /dev/null +++ b/ibm-mq-metrics/src/test/resources/log4j.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/settings.gradle.kts b/settings.gradle.kts index 27db34c41..90b8d7c0b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -46,6 +46,7 @@ include(":consistent-sampling") include(":dependencyManagement") include(":disk-buffering") include(":example") +include(":ibm-mq-metrics") include(":jfr-events") include(":jfr-connection") include(":jmx-metrics") From 90e0f5fad0840829e70c294c1925d8a2f1fd83e8 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 13 Jun 2025 13:31:05 -0700 Subject: [PATCH 02/66] cleanup and spotless --- ibm-mq-metrics/build.gradle.kts | 3 -- .../io/opentelemetry/ibm/mq/WMQContext.java | 22 +++------ .../io/opentelemetry/ibm/mq/WMQMonitor.java | 28 ++++------- .../ibm/mq/config/ExcludeFilters.java | 16 ++----- .../ibm/mq/config/QueueManager.java | 16 ++----- .../ibm/mq/config/ResourceFilters.java | 16 ++----- .../opentelemetry/ibm/mq/metrics/Metrics.java | 20 +++----- .../ibm/mq/metrics/MetricsConfig.java | 16 ++----- .../ChannelMetricsCollector.java | 18 ++----- .../ibm/mq/metricscollector/FilterType.java | 16 ++----- .../InquireChannelCmdCollector.java | 18 ++----- .../InquireQCmdCollector.java | 16 ++----- .../InquireQStatusCmdCollector.java | 16 ++----- .../InquireQueueManagerCmdCollector.java | 18 ++----- .../InquireTStatusCmdCollector.java | 18 ++----- .../ListenerMetricsCollector.java | 18 ++----- .../ibm/mq/metricscollector/MessageBuddy.java | 16 ++----- .../mq/metricscollector/MessageFilter.java | 16 ++----- .../MetricsCollectorContext.java | 16 ++----- .../PerformanceEventQueueCollector.java | 18 ++----- .../QueueCollectionBuddy.java | 20 ++------ .../QueueCollectorSharedState.java | 16 ++----- .../QueueManagerEventCollector.java | 18 ++----- .../QueueManagerMetricsCollector.java | 18 ++----- .../QueueMetricsCollector.java | 18 ++----- .../ReadConfigurationEventQueueCollector.java | 18 ++----- .../ResetQStatsCmdCollector.java | 16 ++----- .../TopicMetricsCollector.java | 16 ++----- .../ibm/mq/opentelemetry/Config.java | 18 ++----- .../ibm/mq/opentelemetry/ConfigWrapper.java | 29 +++++------ .../ibm/mq/opentelemetry/Main.java | 18 ++----- .../ibm/mq/util/AuthorityEventCreator.java | 16 ++----- .../io/opentelemetry/ibm/mq/util/WMQUtil.java | 16 ++----- .../ChannelMetricsCollectorTest.java | 18 ++----- .../InquireChannelCmdCollectorTest.java | 18 ++----- .../ListenerMetricsCollectorTest.java | 16 ++----- .../ibm/mq/metricscollector/MetricAssert.java | 16 ++----- .../QueueCollectionBuddyTest.java | 20 ++------ .../QueueManagerMetricsCollectorTest.java | 16 ++----- .../TopicMetricsCollectorTest.java | 16 ++----- .../ibm/mq/opentelemetry/ConfigTest.java | 16 ++----- .../mq/opentelemetry/ConfigWrapperTest.java | 16 ++----- .../templates/registry/java/Metrics.java.j2 | 33 +++++++++++++ .../registry/java/MetricsConfig.java.j2 | 48 +++++++++++++++++++ .../templates/registry/java/weaver.yaml | 7 +++ 45 files changed, 250 insertions(+), 568 deletions(-) create mode 100644 ibm-mq-metrics/templates/registry/java/Metrics.java.j2 create mode 100644 ibm-mq-metrics/templates/registry/java/MetricsConfig.java.j2 create mode 100644 ibm-mq-metrics/templates/registry/java/weaver.yaml diff --git a/ibm-mq-metrics/build.gradle.kts b/ibm-mq-metrics/build.gradle.kts index 00f3e8274..9e0d06b37 100644 --- a/ibm-mq-metrics/build.gradle.kts +++ b/ibm-mq-metrics/build.gradle.kts @@ -67,7 +67,6 @@ dependencies { } isTransitive = false } - } tasks.shadowJar { @@ -75,5 +74,3 @@ tasks.shadowJar { exclude(dependency("com.ibm.mq:com.ibm.mq.allclient:9.4.2.1")) } } - - diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WMQContext.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WMQContext.java index 1c8d407de..de8f8de8f 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WMQContext.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WMQContext.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq; import com.ibm.mq.constants.CMQC; @@ -38,8 +28,10 @@ public WMQContext(QueueManager queueManager) { validateArgs(); } - public Hashtable getMQEnvironment() { - Hashtable env = new Hashtable<>(); + /** Note: This Hashtable type is needed for IBM client classes. */ + @SuppressWarnings("JdkObsolete") + public Hashtable getMQEnvironment() { + Hashtable env = new Hashtable<>(); addEnvProperty(env, CMQC.HOST_NAME_PROPERTY, queueManager.getHost()); addEnvProperty(env, CMQC.PORT_PROPERTY, queueManager.getPort()); addEnvProperty(env, CMQC.CHANNEL_PROPERTY, queueManager.getChannelName()); diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WMQMonitor.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WMQMonitor.java index e169c7269..3b913b49a 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WMQMonitor.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WMQMonitor.java @@ -1,23 +1,17 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq; import com.fasterxml.jackson.databind.ObjectMapper; import com.ibm.mq.MQQueueManager; import com.ibm.mq.headers.pcf.PCFMessageAgent; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongGauge; +import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.ibm.mq.config.QueueManager; import io.opentelemetry.ibm.mq.metrics.MetricsConfig; import io.opentelemetry.ibm.mq.metricscollector.*; @@ -34,10 +28,6 @@ import io.opentelemetry.ibm.mq.metricscollector.TopicMetricsCollector; import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; import io.opentelemetry.ibm.mq.util.WMQUtil; -import io.opentelemetry.api.common.AttributeKey; -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.metrics.LongGauge; -import io.opentelemetry.api.metrics.Meter; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -97,7 +87,7 @@ public void run() { } @NotNull - private List> getQueueManagers(ConfigWrapper config) { + private static List> getQueueManagers(ConfigWrapper config) { List> queueManagers = config.getQueueManagers(); if (queueManagers.isEmpty()) { throw new IllegalStateException( @@ -180,7 +170,7 @@ private void extractAndReportMetrics( } /** Destroy the agent and disconnect from queue manager */ - private void cleanUp(MQQueueManager ibmQueueManager, PCFMessageAgent agent) { + private static void cleanUp(MQQueueManager ibmQueueManager, PCFMessageAgent agent) { // Disconnect the agent. if (agent != null) { diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/ExcludeFilters.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/ExcludeFilters.java index bac0d3232..3f8ec8390 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/ExcludeFilters.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/ExcludeFilters.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.config; import io.opentelemetry.ibm.mq.metricscollector.FilterType; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/QueueManager.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/QueueManager.java index 8a64928c1..7e366cfb7 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/QueueManager.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/QueueManager.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.config; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/ResourceFilters.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/ResourceFilters.java index 77e475d2c..72a3a9f42 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/ResourceFilters.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/ResourceFilters.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.config; import java.util.HashSet; 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 2aa6e839c..e512881e1 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 @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metrics; import io.opentelemetry.api.metrics.LongCounter; @@ -22,7 +12,9 @@ // This file is generated using weaver. Do not edit manually. /** Metric definitions generated from a Weaver model. Do not edit manually. */ -public class Metrics { +public final class Metrics { + + private Metrics() {} public static LongGauge createMqMessageRetryCount(Meter meter) { return meter 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 b42543680..72305ef90 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 @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metrics; import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollector.java index 6da3d335d..7182e9daf 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollector.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import static com.ibm.mq.constants.CMQC.MQRC_SELECTOR_ERROR; @@ -22,11 +12,11 @@ import com.ibm.mq.constants.CMQCFC; import com.ibm.mq.headers.pcf.PCFException; import com.ibm.mq.headers.pcf.PCFMessage; -import io.opentelemetry.ibm.mq.metrics.Metrics; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.LongGauge; import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.ibm.mq.metrics.Metrics; import java.util.ArrayList; import java.util.Arrays; import java.util.List; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/FilterType.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/FilterType.java index 8d8d83839..668ba2ac0 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/FilterType.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/FilterType.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; public enum FilterType { diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollector.java index 92ec77f67..59444d3fd 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollector.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import com.ibm.mq.constants.CMQCFC; @@ -20,10 +10,10 @@ import com.ibm.mq.headers.pcf.MQCFIL; import com.ibm.mq.headers.pcf.PCFException; import com.ibm.mq.headers.pcf.PCFMessage; -import io.opentelemetry.ibm.mq.metrics.Metrics; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.LongGauge; import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.ibm.mq.metrics.Metrics; import java.util.List; import java.util.Set; import java.util.function.Consumer; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQCmdCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQCmdCollector.java index 89973ec65..25a3e9354 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQCmdCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQCmdCollector.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import com.ibm.mq.constants.CMQC; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQStatusCmdCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQStatusCmdCollector.java index 98a706616..f5b372feb 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQStatusCmdCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQStatusCmdCollector.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import com.ibm.mq.constants.CMQC; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQueueManagerCmdCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQueueManagerCmdCollector.java index 4348396cf..15c803d8a 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQueueManagerCmdCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQueueManagerCmdCollector.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import com.ibm.mq.constants.CMQC; @@ -20,11 +10,11 @@ import com.ibm.mq.constants.MQConstants; import com.ibm.mq.headers.pcf.MQCFIL; import com.ibm.mq.headers.pcf.PCFMessage; -import io.opentelemetry.ibm.mq.metrics.Metrics; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.LongGauge; import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.ibm.mq.metrics.Metrics; import java.util.List; import java.util.function.Consumer; import org.slf4j.Logger; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireTStatusCmdCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireTStatusCmdCollector.java index 92ad1f884..0a3ec157c 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireTStatusCmdCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireTStatusCmdCollector.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import com.ibm.mq.constants.CMQC; @@ -20,11 +10,11 @@ import com.ibm.mq.headers.MQDataException; import com.ibm.mq.headers.pcf.PCFException; import com.ibm.mq.headers.pcf.PCFMessage; -import io.opentelemetry.ibm.mq.metrics.Metrics; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.LongGauge; import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.ibm.mq.metrics.Metrics; import java.io.IOException; import java.util.List; import java.util.Set; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollector.java index 0815bcc53..f643d7c33 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollector.java @@ -1,28 +1,18 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import com.ibm.mq.constants.CMQCFC; import com.ibm.mq.headers.pcf.PCFException; import com.ibm.mq.headers.pcf.PCFMessage; -import io.opentelemetry.ibm.mq.metrics.Metrics; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.LongGauge; import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.ibm.mq.metrics.Metrics; import java.util.Arrays; import java.util.List; import java.util.Set; 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 0cdeb2657..6ed74dad9 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 @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import com.ibm.mq.constants.CMQC; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MessageFilter.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MessageFilter.java index 60baf9d76..ffcc5ba3c 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MessageFilter.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MessageFilter.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import com.ibm.mq.headers.pcf.PCFException; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MetricsCollectorContext.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MetricsCollectorContext.java index f4578ba7e..774f39b10 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MetricsCollectorContext.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MetricsCollectorContext.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import static java.util.Collections.emptyList; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/PerformanceEventQueueCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/PerformanceEventQueueCollector.java index 17936678f..9d5151d98 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/PerformanceEventQueueCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/PerformanceEventQueueCollector.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import com.ibm.mq.MQException; @@ -23,11 +13,11 @@ import com.ibm.mq.constants.MQConstants; import com.ibm.mq.headers.pcf.PCFException; import com.ibm.mq.headers.pcf.PCFMessage; -import io.opentelemetry.ibm.mq.metrics.Metrics; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.LongCounter; import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.ibm.mq.metrics.Metrics; import java.io.IOException; import java.util.function.Consumer; import org.slf4j.Logger; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java index d1531dd24..9a3694961 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import static com.ibm.mq.constants.CMQC.*; @@ -25,12 +15,12 @@ import com.ibm.mq.headers.pcf.PCFException; import com.ibm.mq.headers.pcf.PCFMessage; import com.ibm.mq.headers.pcf.PCFParameter; -import io.opentelemetry.ibm.mq.metrics.Metrics; -import io.opentelemetry.ibm.mq.metrics.MetricsConfig; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.LongGauge; import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.ibm.mq.metrics.Metrics; +import io.opentelemetry.ibm.mq.metrics.MetricsConfig; import java.io.IOException; import java.util.HashMap; import java.util.List; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectorSharedState.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectorSharedState.java index 66ad0c4f2..94fcc7788 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectorSharedState.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectorSharedState.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import java.util.concurrent.ConcurrentHashMap; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerEventCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerEventCollector.java index 167fd9b0f..cd5f0b94e 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerEventCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerEventCollector.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import com.ibm.mq.MQException; @@ -23,11 +13,11 @@ import com.ibm.mq.constants.CMQCFC; import com.ibm.mq.constants.MQConstants; import com.ibm.mq.headers.pcf.PCFMessage; -import io.opentelemetry.ibm.mq.metrics.Metrics; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.LongCounter; import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.ibm.mq.metrics.Metrics; import java.io.IOException; import java.util.function.Consumer; import org.slf4j.Logger; 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 42932724a..e04bb6f2d 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 @@ -1,27 +1,17 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import com.ibm.mq.constants.CMQCFC; import com.ibm.mq.headers.pcf.PCFMessage; -import io.opentelemetry.ibm.mq.metrics.Metrics; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.LongGauge; import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.ibm.mq.metrics.Metrics; import java.util.List; import java.util.function.Consumer; import org.slf4j.Logger; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueMetricsCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueMetricsCollector.java index 2f8652f3f..35370fb73 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueMetricsCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueMetricsCollector.java @@ -1,22 +1,12 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; -import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ReadConfigurationEventQueueCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ReadConfigurationEventQueueCollector.java index 68f51a144..f5ab9293c 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ReadConfigurationEventQueueCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ReadConfigurationEventQueueCollector.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import com.ibm.mq.MQException; @@ -23,11 +13,11 @@ import com.ibm.mq.constants.CMQCFC; import com.ibm.mq.constants.MQConstants; import com.ibm.mq.headers.pcf.PCFMessage; -import io.opentelemetry.ibm.mq.metrics.Metrics; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.LongGauge; import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.ibm.mq.metrics.Metrics; import java.io.IOException; import java.util.function.Consumer; import org.slf4j.Logger; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ResetQStatsCmdCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ResetQStatsCmdCollector.java index 203c9bc81..0c0c3595b 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ResetQStatsCmdCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ResetQStatsCmdCollector.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import com.ibm.mq.constants.CMQC; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/TopicMetricsCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/TopicMetricsCollector.java index 4f47d850a..76ff2a957 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/TopicMetricsCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/TopicMetricsCollector.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import io.opentelemetry.api.metrics.Meter; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Config.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Config.java index 531bdee09..ed27ad831 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Config.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Config.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.opentelemetry; import java.util.Map; @@ -34,7 +24,7 @@ static void setUpSSLConnection(Map config) { } private static void getConfigValueAndSetSystemProperty( - Map otlpConfig, String configKey, String systemKey) { + Map otlpConfig, String configKey, String systemKey) { Object configValue = otlpConfig.get(configKey); if (configValue instanceof String && !((String) configValue).trim().isEmpty()) { System.setProperty(systemKey, (String) configValue); diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapper.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapper.java index 24d1d4609..5f1d71e65 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapper.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapper.java @@ -1,24 +1,16 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.opentelemetry; import static java.util.Collections.emptyList; -import java.io.FileNotFoundException; -import java.io.FileReader; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Paths; import java.time.Duration; import java.util.Collections; import java.util.List; @@ -44,9 +36,10 @@ private ConfigWrapper(Map config) { this.config = config; } - public static ConfigWrapper parse(String configFile) throws FileNotFoundException { + public static ConfigWrapper parse(String configFile) throws IOException { Yaml yaml = new Yaml(); - Map config = yaml.load(new FileReader(configFile)); + Map config = + yaml.load(Files.newBufferedReader(Paths.get(configFile), Charset.defaultCharset())); return new ConfigWrapper(config); } @@ -121,7 +114,7 @@ public int getInt(String key, int defaultValue) { return (Map) metrics; } - private int defaultedInt(Map section, String key, int defaultValue) { + private static int defaultedInt(Map section, String key, int defaultValue) { Object val = section.get(key); return val instanceof Integer ? (Integer) val : defaultValue; } diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java index 60e80e231..d795f2faf 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java @@ -1,23 +1,13 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.opentelemetry; -import io.opentelemetry.ibm.mq.WMQMonitor; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.metrics.MeterProvider; +import io.opentelemetry.ibm.mq.WMQMonitor; import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; import io.opentelemetry.sdk.resources.Resource; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/AuthorityEventCreator.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/AuthorityEventCreator.java index 0784a163e..3b3e71bd3 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/AuthorityEventCreator.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/AuthorityEventCreator.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.util; import com.ibm.mq.MQException; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/WMQUtil.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/WMQUtil.java index 20d6902bb..07f7da104 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/WMQUtil.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/WMQUtil.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.util; import com.ibm.mq.MQException; diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollectorTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollectorTest.java index 5ec98554a..fd1d5e516 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollectorTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollectorTest.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import static com.ibm.mq.constants.CMQC.MQRC_SELECTOR_ERROR; @@ -28,10 +18,10 @@ import com.ibm.mq.headers.pcf.PCFException; import com.ibm.mq.headers.pcf.PCFMessage; import com.ibm.mq.headers.pcf.PCFMessageAgent; +import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.ibm.mq.config.QueueManager; import io.opentelemetry.ibm.mq.metrics.MetricsConfig; import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; -import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension; import java.util.ArrayList; diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollectorTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollectorTest.java index cd7b3b3ae..0c787ceb3 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollectorTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollectorTest.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import static org.assertj.core.api.Assertions.assertThat; @@ -24,10 +14,10 @@ import com.ibm.mq.constants.CMQXC; import com.ibm.mq.headers.pcf.PCFMessage; import com.ibm.mq.headers.pcf.PCFMessageAgent; +import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.ibm.mq.config.QueueManager; import io.opentelemetry.ibm.mq.metrics.MetricsConfig; import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; -import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension; import java.util.ArrayList; diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollectorTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollectorTest.java index f1e05435c..b6cca0c09 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollectorTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollectorTest.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import static org.assertj.core.api.Assertions.assertThat; diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/MetricAssert.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/MetricAssert.java index b4bbbe6f6..25d173d3d 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/MetricAssert.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/MetricAssert.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import io.opentelemetry.sdk.metrics.data.LongPointData; diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java index 21476871a..a04728dcc 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import static org.assertj.core.api.Assertions.assertThat; @@ -23,11 +13,11 @@ import com.ibm.mq.constants.CMQCFC; import com.ibm.mq.headers.pcf.PCFMessage; import com.ibm.mq.headers.pcf.PCFMessageAgent; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.ibm.mq.config.QueueManager; import io.opentelemetry.ibm.mq.metrics.MetricsConfig; import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; -import io.opentelemetry.api.common.AttributeKey; -import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.sdk.metrics.data.LongPointData; import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension; diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerMetricsCollectorTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerMetricsCollectorTest.java index f5d2d3793..7d5ad2dc4 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerMetricsCollectorTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerMetricsCollectorTest.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import static org.assertj.core.api.Assertions.assertThat; diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/TopicMetricsCollectorTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/TopicMetricsCollectorTest.java index 738e50300..841231242 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/TopicMetricsCollectorTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/TopicMetricsCollectorTest.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metricscollector; import static org.assertj.core.api.Assertions.assertThat; diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigTest.java index 9abc81dbf..53500907e 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigTest.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.opentelemetry; import static org.assertj.core.api.Assertions.assertThat; diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java index 973d3d7b9..dcd4aa490 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java @@ -1,18 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.opentelemetry; import static java.util.Collections.singletonList; diff --git a/ibm-mq-metrics/templates/registry/java/Metrics.java.j2 b/ibm-mq-metrics/templates/registry/java/Metrics.java.j2 new file mode 100644 index 000000000..22d935808 --- /dev/null +++ b/ibm-mq-metrics/templates/registry/java/Metrics.java.j2 @@ -0,0 +1,33 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.splunk.ibm.mq.metrics; + +import io.opentelemetry.api.metrics.LongCounter; +import io.opentelemetry.api.metrics.LongGauge; +import io.opentelemetry.api.metrics.Meter; + +// This file is generated using weaver. Do not edit manually. + +/** + * Metric definitions generated from a Weaver model. Do not edit manually. + */ +public class Metrics { +{% for metric in ctx %} + public static {% if metric.instrument == "gauge" %}LongGauge{% elif metric.instrument == "counter" %}LongCounter{% endif %} create{{ metric.metric_name.split('.')|map('capitalize')|join }}(Meter meter) { + return meter.{% if metric.instrument == "gauge" %}gauge{% elif metric.instrument == "counter" %}counter{% endif %}Builder("{{ metric.metric_name }}").{% if metric.instrument == "gauge" %}ofLongs().{% endif %}setUnit("{{ metric.unit }}").setDescription("{{ metric.brief }}").build(); + } +{% endfor %} +} \ No newline at end of file diff --git a/ibm-mq-metrics/templates/registry/java/MetricsConfig.java.j2 b/ibm-mq-metrics/templates/registry/java/MetricsConfig.java.j2 new file mode 100644 index 000000000..5ad5bd51c --- /dev/null +++ b/ibm-mq-metrics/templates/registry/java/MetricsConfig.java.j2 @@ -0,0 +1,48 @@ +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.splunk.ibm.mq.metrics; + +import com.splunk.ibm.mq.opentelemetry.ConfigWrapper; +import java.util.Map; + +// This file is generated using weaver. Do not edit manually. + +/** + * Configuration of metrics as defined in config.yml. + * + */ +public class MetricsConfig { + + private final Map config; + + public MetricsConfig(ConfigWrapper config) { + this.config = config.getMetrics(); + } + +{% for metric in ctx %} + public boolean is{{ metric.metric_name.split('.')|map('capitalize')|join }}Enabled() { + Object metricInfo = config.get("{{ metric.metric_name }}"); + if (!(metricInfo instanceof Map)) { + return false; + } + Object enabled = ((Map) metricInfo).get("enabled"); + if (enabled instanceof Boolean) { + return (Boolean) ((Map) metricInfo).get("enabled"); + } + return false; + } +{% endfor %} +} \ No newline at end of file diff --git a/ibm-mq-metrics/templates/registry/java/weaver.yaml b/ibm-mq-metrics/templates/registry/java/weaver.yaml new file mode 100644 index 000000000..8e4ea48e1 --- /dev/null +++ b/ibm-mq-metrics/templates/registry/java/weaver.yaml @@ -0,0 +1,7 @@ +templates: + - pattern: Metrics.java.j2 + filter: '.groups | map(select(.type == "metric"))' + application_mode: single + - pattern: MetricsConfig.java.j2 + filter: '.groups | map(select(.type == "metric"))' + application_mode: single \ No newline at end of file From 6fa008c7ff5baec7bbc020da3e0c4e8bba1489b5 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 13 Jun 2025 13:44:29 -0700 Subject: [PATCH 03/66] continue cleanup --- .../mq/{WMQContext.java => WmqContext.java} | 6 +- .../mq/{WMQMonitor.java => WmqMonitor.java} | 43 +++++----- .../ibm/mq/config/ExcludeFilters.java | 10 ++- .../ibm/mq/config/QueueManager.java | 79 +++++++++---------- .../MetricsCollectorContext.java | 8 +- .../ibm/mq/opentelemetry/Main.java | 4 +- .../ibm/mq/util/AuthorityEventCreator.java | 78 ------------------ .../mq/util/{WMQUtil.java => WmqUtil.java} | 10 +-- 8 files changed, 81 insertions(+), 157 deletions(-) rename ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/{WMQContext.java => WmqContext.java} (96%) rename ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/{WMQMonitor.java => WmqMonitor.java} (92%) delete mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/AuthorityEventCreator.java rename ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/{WMQUtil.java => WmqUtil.java} (94%) diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WMQContext.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqContext.java similarity index 96% rename from ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WMQContext.java rename to ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqContext.java index de8f8de8f..279cbd3a7 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WMQContext.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqContext.java @@ -16,14 +16,14 @@ * authorization.
* It also validates the arguments passed for various scenarios. */ -public class WMQContext { +public class WmqContext { private static final String TRANSPORT_TYPE_CLIENT = "Client"; private static final String TRANSPORT_TYPE_BINDINGS = "Bindings"; - public static final Logger logger = LoggerFactory.getLogger(WMQContext.class); + public static final Logger logger = LoggerFactory.getLogger(WmqContext.class); private final QueueManager queueManager; - public WMQContext(QueueManager queueManager) { + public WmqContext(QueueManager queueManager) { this.queueManager = queueManager; validateArgs(); } diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WMQMonitor.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqMonitor.java similarity index 92% rename from ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WMQMonitor.java rename to ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqMonitor.java index 3b913b49a..753839f91 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WMQMonitor.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqMonitor.java @@ -14,7 +14,6 @@ import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.ibm.mq.config.QueueManager; import io.opentelemetry.ibm.mq.metrics.MetricsConfig; -import io.opentelemetry.ibm.mq.metricscollector.*; import io.opentelemetry.ibm.mq.metricscollector.ChannelMetricsCollector; import io.opentelemetry.ibm.mq.metricscollector.InquireChannelCmdCollector; import io.opentelemetry.ibm.mq.metricscollector.InquireQueueManagerCmdCollector; @@ -27,7 +26,7 @@ import io.opentelemetry.ibm.mq.metricscollector.ReadConfigurationEventQueueCollector; import io.opentelemetry.ibm.mq.metricscollector.TopicMetricsCollector; import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; -import io.opentelemetry.ibm.mq.util.WMQUtil; +import io.opentelemetry.ibm.mq.util.WmqUtil; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -35,12 +34,13 @@ import java.util.concurrent.ExecutorService; import java.util.function.Consumer; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class WMQMonitor { +public class WmqMonitor { - private static final Logger logger = LoggerFactory.getLogger(WMQMonitor.class); + private static final Logger logger = LoggerFactory.getLogger(WmqMonitor.class); private final List queueManagers; private final List> jobs = new ArrayList<>(); @@ -48,7 +48,7 @@ public class WMQMonitor { private final ExecutorService threadPool; private final MetricsConfig metricsConfig; - public WMQMonitor(ConfigWrapper config, ExecutorService threadPool, Meter meter) { + public WmqMonitor(ConfigWrapper config, ExecutorService threadPool, Meter meter) { List> queueManagers = getQueueManagers(config); ObjectMapper mapper = new ObjectMapper(); @@ -86,16 +86,6 @@ public void run() { } } - @NotNull - private static List> getQueueManagers(ConfigWrapper config) { - List> queueManagers = config.getQueueManagers(); - if (queueManagers.isEmpty()) { - throw new IllegalStateException( - "The 'queueManagers' section in config.yml is empty or otherwise incorrect."); - } - return queueManagers; - } - public void run(QueueManager queueManager) { String queueManagerName = queueManager.getName(); logger.debug("WMQMonitor thread for queueManager {} started.", queueManagerName); @@ -104,11 +94,11 @@ public void run(QueueManager queueManager) { PCFMessageAgent agent = null; int heartBeatMetricValue = 0; try { - ibmQueueManager = WMQUtil.connectToQueueManager(queueManager); + ibmQueueManager = WmqUtil.connectToQueueManager(queueManager); heartBeatMetricValue = 1; - agent = WMQUtil.initPCFMessageAgent(queueManager, ibmQueueManager); + agent = WmqUtil.initPCFMessageAgent(queueManager, ibmQueueManager); extractAndReportMetrics(ibmQueueManager, queueManager, agent); - } catch (Exception e) { + } catch (RuntimeException e) { logger.error( "Error connecting to QueueManager {} by thread {}: {}", queueManagerName, @@ -130,6 +120,16 @@ public void run(QueueManager queueManager) { } } + @NotNull + private static List> getQueueManagers(ConfigWrapper config) { + List> queueManagers = config.getQueueManagers(); + if (queueManagers.isEmpty()) { + throw new IllegalStateException( + "The 'queueManagers' section in config.yml is empty or otherwise incorrect."); + } + return queueManagers; + } + private void extractAndReportMetrics( MQQueueManager mqQueueManager, QueueManager queueManager, PCFMessageAgent agent) { logger.debug("Queueing {} jobs", jobs.size()); @@ -154,9 +154,9 @@ private void extractAndReportMetrics( collector.getClass().getSimpleName(), diffTime); } - } catch (Exception e) { + } catch (RuntimeException e) { logger.error( - "Error while running task name = " + collector.getClass().getSimpleName(), e); + "Error while running task name = {}", collector.getClass().getSimpleName(), e); } return null; }); @@ -170,7 +170,8 @@ private void extractAndReportMetrics( } /** Destroy the agent and disconnect from queue manager */ - private static void cleanUp(MQQueueManager ibmQueueManager, PCFMessageAgent agent) { + private static void cleanUp( + @Nullable MQQueueManager ibmQueueManager, @Nullable PCFMessageAgent agent) { // Disconnect the agent. if (agent != null) { diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/ExcludeFilters.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/ExcludeFilters.java index 3f8ec8390..7d9d4950a 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/ExcludeFilters.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/ExcludeFilters.java @@ -7,12 +7,16 @@ import io.opentelemetry.ibm.mq.metricscollector.FilterType; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.Set; +/** + * A jackson databind class used for config. + */ public class ExcludeFilters { - private String type; + private String type = "UNKNOWN"; private Set values = new HashSet<>(); public String getType() { @@ -24,11 +28,11 @@ public void setType(String type) { } public Set getValues() { - return values; + return Collections.unmodifiableSet(values); } public void setValues(Set values) { - this.values = values; + this.values = new HashSet<>(values); } public static boolean isExcluded(String resourceName, Collection excludeFilters) { diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/QueueManager.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/QueueManager.java index 7e366cfb7..8ad0626ff 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/QueueManager.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/QueueManager.java @@ -6,25 +6,26 @@ package io.opentelemetry.ibm.mq.config; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import java.util.List; +import org.jetbrains.annotations.Nullable; +/** This is a jackson databind class used purely for config. */ @JsonIgnoreProperties(ignoreUnknown = true) public class QueueManager { - private String host; + @Nullable private String host; private int port = -1; - private String name; - private String channelName; - private String transportType; - private String username; - private String password; - private String sslKeyRepository; + private String name = "UNKNOWN"; + @Nullable private String channelName; + @Nullable private String transportType; + @Nullable private String username; + @Nullable private String password; + @Nullable private String sslKeyRepository; private int ccsid = Integer.MIN_VALUE; private int encoding = Integer.MIN_VALUE; - private String cipherSuite; - private String cipherSpec; - private String replyQueuePrefix; - private String modelQueueName; + @Nullable private String cipherSuite; + @Nullable private String cipherSpec; + @Nullable private String replyQueuePrefix; + @Nullable private String modelQueueName; private String configurationQueueName = "SYSTEM.ADMIN.CONFIG.EVENT"; private String performanceEventsQueueName = "SYSTEM.ADMIN.PERFM.EVENT"; private String queueManagerEventsQueueName = "SYSTEM.ADMIN.QMGR.EVENT"; @@ -34,14 +35,12 @@ public class QueueManager { // https://www.ibm.com/docs/en/ibm-mq/9.3.x?topic=qmini-channels-stanza-file private int maxActiveChannels = 100; - private ResourceFilters queueFilters; - private ResourceFilters channelFilters; - private ResourceFilters listenerFilters; - private ResourceFilters topicFilters; + @Nullable private ResourceFilters queueFilters; + @Nullable private ResourceFilters channelFilters; + @Nullable private ResourceFilters listenerFilters; + @Nullable private ResourceFilters topicFilters; - List writeStatsDirectory; - - public String getHost() { + public @Nullable String getHost() { return host; } @@ -65,35 +64,35 @@ public void setName(String name) { this.name = name; } - public String getChannelName() { + public @Nullable String getChannelName() { return channelName; } - public void setChannelName(String channelName) { + public void setChannelName(@Nullable String channelName) { this.channelName = channelName; } - public String getTransportType() { + public @Nullable String getTransportType() { return transportType; } - public void setTransportType(String transportType) { + public void setTransportType(@Nullable String transportType) { this.transportType = transportType; } - public String getUsername() { + public @Nullable String getUsername() { return username; } - public void setUsername(String username) { + public void setUsername(@Nullable String username) { this.username = username; } - public String getPassword() { + public @Nullable String getPassword() { return password; } - public void setPassword(String password) { + public void setPassword(@Nullable String password) { this.password = password; } @@ -104,19 +103,19 @@ public ResourceFilters getQueueFilters() { return queueFilters; } - public void setQueueFilters(ResourceFilters queueFilters) { + public void setQueueFilters(@Nullable ResourceFilters queueFilters) { this.queueFilters = queueFilters; } - public String getSslKeyRepository() { + public @Nullable String getSslKeyRepository() { return sslKeyRepository; } - public void setSslKeyRepository(String sslKeyRepository) { + public void setSslKeyRepository(@Nullable String sslKeyRepository) { this.sslKeyRepository = sslKeyRepository; } - public String getCipherSuite() { + public @Nullable String getCipherSuite() { return cipherSuite; } @@ -124,11 +123,11 @@ public void setCipherSuite(String cipherSuite) { this.cipherSuite = cipherSuite; } - public String getCipherSpec() { + public @Nullable String getCipherSpec() { return cipherSpec; } - public void setCipherSpec(String cipherSpec) { + public void setCipherSpec(@Nullable String cipherSpec) { this.cipherSpec = cipherSpec; } @@ -139,23 +138,23 @@ public ResourceFilters getChannelFilters() { return channelFilters; } - public void setChannelFilters(ResourceFilters channelFilters) { + public void setChannelFilters(@Nullable ResourceFilters channelFilters) { this.channelFilters = channelFilters; } - public String getReplyQueuePrefix() { + public @Nullable String getReplyQueuePrefix() { return replyQueuePrefix; } - public void setReplyQueuePrefix(String replyQueuePrefix) { + public void setReplyQueuePrefix(@Nullable String replyQueuePrefix) { this.replyQueuePrefix = replyQueuePrefix; } - public String getModelQueueName() { + public @Nullable String getModelQueueName() { return modelQueueName; } - public void setModelQueueName(String modelQueueName) { + public void setModelQueueName(@Nullable String modelQueueName) { this.modelQueueName = modelQueueName; } @@ -166,7 +165,7 @@ public ResourceFilters getListenerFilters() { return listenerFilters; } - public void setListenerFilters(ResourceFilters listenerFilters) { + public void setListenerFilters(@Nullable ResourceFilters listenerFilters) { this.listenerFilters = listenerFilters; } @@ -193,7 +192,7 @@ public ResourceFilters getTopicFilters() { return topicFilters; } - public void setTopicFilters(ResourceFilters topicFilters) { + public void setTopicFilters(@Nullable ResourceFilters topicFilters) { this.topicFilters = topicFilters; } diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MetricsCollectorContext.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MetricsCollectorContext.java index 774f39b10..dab85748e 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MetricsCollectorContext.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MetricsCollectorContext.java @@ -15,11 +15,11 @@ import io.opentelemetry.ibm.mq.config.QueueManager; import io.opentelemetry.ibm.mq.metrics.MetricsConfig; import java.io.IOException; -import java.util.*; +import java.util.Arrays; +import java.util.List; +import java.util.Set; import javax.annotation.concurrent.Immutable; import org.jetbrains.annotations.NotNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * A temporary bundle to contain the collaborators of the original MetricsCollector base class until @@ -29,8 +29,6 @@ @Immutable public final class MetricsCollectorContext { - private static final Logger logger = LoggerFactory.getLogger(MetricsCollectorContext.class); - private final QueueManager queueManager; private final PCFMessageAgent agent; private final MQQueueManager mqQueueManager; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java index d795f2faf..fe6f144d4 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java @@ -7,7 +7,7 @@ import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.metrics.MeterProvider; -import io.opentelemetry.ibm.mq.WMQMonitor; +import io.opentelemetry.ibm.mq.WmqMonitor; import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; import io.opentelemetry.sdk.resources.Resource; @@ -76,7 +76,7 @@ public static void run( MeterProvider meterProvider = otel.getMeterProvider(); Runtime.getRuntime().addShutdownHook(new Thread(service::shutdown)); - WMQMonitor monitor = new WMQMonitor(config, service, meterProvider.get("websphere/mq")); + WmqMonitor monitor = new WmqMonitor(config, service, meterProvider.get("websphere/mq")); service.scheduleAtFixedRate( monitor::run, config.getTaskInitialDelaySeconds(), diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/AuthorityEventCreator.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/AuthorityEventCreator.java deleted file mode 100644 index 3b3e71bd3..000000000 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/AuthorityEventCreator.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.ibm.mq.util; - -import com.ibm.mq.MQException; -import com.ibm.msg.client.jms.JmsConnectionFactory; -import com.ibm.msg.client.jms.JmsFactoryFactory; -import com.ibm.msg.client.wmq.WMQConstants; -import javax.jms.JMSContext; -import javax.jms.JMSException; -import javax.jms.JMSRuntimeException; - -/** - * Application that tries to log in to a queue manager to create authority events. - * - *

You can run it with - * - *

- * java -cp ibm-mq-monitoring--all.jar:com.ibm.mq.allclient.jar com.splunk.ibm.mq.util.AuthorityEventCreator       
- * 
- */ -public class AuthorityEventCreator { - - public static void main(String[] args) { - String host, port, queueManagerName, channelName, username, password; - if (args.length < 6) { - throw new IllegalArgumentException("Need 6 arguments"); - } - host = args[0]; - port = args[1]; - queueManagerName = args[2]; - channelName = args[3]; - username = args[4]; - password = args[5]; - - JMSContext context = null; - try { - // Create a connection factory - JmsFactoryFactory ff = JmsFactoryFactory.getInstance(WMQConstants.JAKARTA_WMQ_PROVIDER); - JmsConnectionFactory cf = ff.createConnectionFactory(); - - // Set the properties - cf.setStringProperty(WMQConstants.WMQ_HOST_NAME, host); - cf.setIntProperty(WMQConstants.WMQ_PORT, Integer.parseInt(port)); - cf.setStringProperty(WMQConstants.WMQ_CHANNEL, channelName); - cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT); - cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, queueManagerName); - cf.setStringProperty(WMQConstants.WMQ_APPLICATIONNAME, "Bad Password"); - cf.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP, true); - cf.setStringProperty(WMQConstants.USERID, username); - cf.setStringProperty(WMQConstants.PASSWORD, password); - // cf.setStringProperty(WMQConstants.WMQ_SSL_CIPHER_SUITE, "*TLS12ORHIGHER"); - // cf.setIntProperty(MQConstants.CERTIFICATE_VALIDATION_POLICY, - // MQConstants.MQ_CERT_VAL_POLICY_NONE); - - // Create Jakarta objects - context = cf.createContext(); - } catch (JMSException e) { - throw new RuntimeException(e); - } catch (JMSRuntimeException e) { - if (e.getCause() instanceof MQException) { - MQException mqe = (MQException) e.getCause(); - if (mqe.getReason() == 2035) { // bad password - System.out.println("Error 2035 returned"); - return; - } - } - throw new RuntimeException(e); - } finally { - if (context != null) { - context.close(); - } - } - } -} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/WMQUtil.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/WmqUtil.java similarity index 94% rename from ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/WMQUtil.java rename to ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/WmqUtil.java index 07f7da104..f042dfac1 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/WMQUtil.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/WmqUtil.java @@ -9,17 +9,17 @@ import com.ibm.mq.MQQueueManager; import com.ibm.mq.headers.MQDataException; import com.ibm.mq.headers.pcf.PCFMessageAgent; -import io.opentelemetry.ibm.mq.WMQContext; +import io.opentelemetry.ibm.mq.WmqContext; import io.opentelemetry.ibm.mq.config.QueueManager; import java.util.Hashtable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class WMQUtil { +public class WmqUtil { - private static final Logger logger = LoggerFactory.getLogger(WMQUtil.class); + private static final Logger logger = LoggerFactory.getLogger(WmqUtil.class); - private WMQUtil() {} + private WmqUtil() {} public static PCFMessageAgent initPCFMessageAgent( QueueManager queueManager, MQQueueManager ibmQueueManager) { @@ -56,7 +56,7 @@ && isNotNullOrEmpty(queueManager.getReplyQueuePrefix())) { @SuppressWarnings("rawtypes") public static MQQueueManager connectToQueueManager(QueueManager queueManager) { - WMQContext auth = new WMQContext(queueManager); + WmqContext auth = new WmqContext(queueManager); Hashtable env = auth.getMQEnvironment(); try { MQQueueManager ibmQueueManager = new MQQueueManager(queueManager.getName(), env); From 1bf19938f53d63f31c2b87cfa842ba33a650f8e2 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 13 Jun 2025 13:50:28 -0700 Subject: [PATCH 04/66] continue cleanups --- .../io/opentelemetry/ibm/mq/WmqMonitor.java | 2 +- .../metricscollector/InquireQCmdCollector.java | 2 +- .../InquireQStatusCmdCollector.java | 2 +- .../InquireQueueManagerCmdCollector.java | 2 +- .../metricscollector/QueueCollectionBuddy.java | 18 ++++++++---------- .../QueueManagerMetricsCollector.java | 2 +- .../ResetQStatsCmdCollector.java | 2 +- .../io/opentelemetry/ibm/mq/util/WmqUtil.java | 9 +++++---- .../QueueCollectionBuddyTest.java | 12 ++++++------ 9 files changed, 25 insertions(+), 26 deletions(-) diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqMonitor.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqMonitor.java index 753839f91..679295a94 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqMonitor.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqMonitor.java @@ -96,7 +96,7 @@ public void run(QueueManager queueManager) { try { ibmQueueManager = WmqUtil.connectToQueueManager(queueManager); heartBeatMetricValue = 1; - agent = WmqUtil.initPCFMessageAgent(queueManager, ibmQueueManager); + agent = WmqUtil.initPcfMessageAgent(queueManager, ibmQueueManager); extractAndReportMetrics(ibmQueueManager, queueManager, agent); } catch (RuntimeException e) { logger.error( diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQCmdCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQCmdCollector.java index 25a3e9354..16164b46d 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQCmdCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQCmdCollector.java @@ -57,7 +57,7 @@ public void accept(MetricsCollectorContext context) { request.addParameter(CMQC.MQIA_Q_TYPE, CMQC.MQQT_ALL); request.addParameter(CMQCFC.MQIACF_Q_ATTRS, ATTRIBUTES); - queueBuddy.processPCFRequestAndPublishQMetrics( + queueBuddy.processPcfRequestAndPublishQMetrics( context, request, queueGenericName, ATTRIBUTES); } long exitTime = System.currentTimeMillis() - entryTime; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQStatusCmdCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQStatusCmdCollector.java index f5b372feb..3580c02b1 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQStatusCmdCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQStatusCmdCollector.java @@ -63,7 +63,7 @@ public void accept(MetricsCollectorContext context) { PCFMessage request = new PCFMessage(CMQCFC.MQCMD_INQUIRE_Q_STATUS); request.addParameter(CMQC.MQCA_Q_NAME, queueGenericName); request.addParameter(CMQCFC.MQIACF_Q_STATUS_ATTRS, ATTRIBUTES); - queueBuddy.processPCFRequestAndPublishQMetrics( + queueBuddy.processPcfRequestAndPublishQMetrics( context, request, queueGenericName, ATTRIBUTES); } long exitTime = System.currentTimeMillis() - entryTime; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQueueManagerCmdCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQueueManagerCmdCollector.java index 15c803d8a..3a7604742 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQueueManagerCmdCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQueueManagerCmdCollector.java @@ -67,7 +67,7 @@ public void accept(MetricsCollectorContext context) { } } catch (Exception e) { logger.error("Error collecting QueueManagerCmd metrics", e); - throw new RuntimeException(e); + throw new IllegalStateException(e); } finally { long exitTime = System.currentTimeMillis() - entryTime; logger.debug("Time taken to publish metrics for queuemanager is {} milliseconds", exitTime); diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java index 9a3694961..510d17de9 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java @@ -5,7 +5,11 @@ package io.opentelemetry.ibm.mq.metricscollector; -import static com.ibm.mq.constants.CMQC.*; +import static com.ibm.mq.constants.CMQC.MQQT_ALIAS; +import static com.ibm.mq.constants.CMQC.MQQT_CLUSTER; +import static com.ibm.mq.constants.CMQC.MQQT_LOCAL; +import static com.ibm.mq.constants.CMQC.MQQT_MODEL; +import static com.ibm.mq.constants.CMQC.MQQT_REMOTE; import com.ibm.mq.constants.CMQC; import com.ibm.mq.constants.CMQCFC; @@ -35,7 +39,7 @@ */ final class QueueCollectionBuddy { private static final Logger logger = LoggerFactory.getLogger(QueueCollectionBuddy.class); - private Map gauges; + private final Map gauges = new HashMap<>(); private final QueueCollectorSharedState sharedState; private final LongGauge onqtimeShort; @@ -43,11 +47,10 @@ final class QueueCollectionBuddy { @FunctionalInterface private interface AllowedGauge { - void set(MetricsCollectorContext context, Integer value, Attributes attributes); } - private AllowedGauge createAllowedGauge( + private static AllowedGauge createAllowedGauge( LongGauge gauge, Function allowed) { return (context, val, attributes) -> { if (allowed.apply(context.getMetricsConfig())) { @@ -58,7 +61,6 @@ private AllowedGauge createAllowedGauge( QueueCollectionBuddy(Meter meter, QueueCollectorSharedState sharedState) { this.sharedState = sharedState; - this.gauges = new HashMap<>(); gauges.put( CMQC.MQIA_CURRENT_Q_DEPTH, createAllowedGauge( @@ -118,17 +120,13 @@ private AllowedGauge createAllowedGauge( this.onqtimeShort = Metrics.createMqOnqtime1(meter); this.onqtimeLong = Metrics.createMqOnqtime2(meter); - - initialize(meter); } - private void initialize(Meter meter) {} - /** * Sends a PCFMessage request, reads the response, and generates metrics from the response. It * handles all exceptions. */ - void processPCFRequestAndPublishQMetrics( + void processPcfRequestAndPublishQMetrics( MetricsCollectorContext context, PCFMessage request, String queueGenericName, int[] fields) { try { doProcessPCFRequestAndPublishQMetrics(context, request, queueGenericName, fields); 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 e04bb6f2d..ebb8f2095 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 @@ -102,7 +102,7 @@ public void accept(MetricsCollectorContext context) { } } catch (Exception e) { logger.error(e.getMessage()); - throw new RuntimeException(e); + throw new IllegalStateException(e); } finally { long exitTime = System.currentTimeMillis() - entryTime; logger.debug("Time taken to publish metrics for queuemanager is {} milliseconds", exitTime); diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ResetQStatsCmdCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ResetQStatsCmdCollector.java index 0c0c3595b..6f75acfe2 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ResetQStatsCmdCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ResetQStatsCmdCollector.java @@ -44,7 +44,7 @@ public void accept(MetricsCollectorContext context) { // https://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.ref.adm.doc/q088310_.htm PCFMessage request = new PCFMessage(CMQCFC.MQCMD_RESET_Q_STATS); request.addParameter(CMQC.MQCA_Q_NAME, queueGenericName); - queueBuddy.processPCFRequestAndPublishQMetrics( + queueBuddy.processPcfRequestAndPublishQMetrics( context, request, queueGenericName, ATTRIBUTES); } long exitTime = System.currentTimeMillis() - entryTime; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/WmqUtil.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/WmqUtil.java index f042dfac1..72c8c0278 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/WmqUtil.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/WmqUtil.java @@ -12,6 +12,7 @@ import io.opentelemetry.ibm.mq.WmqContext; import io.opentelemetry.ibm.mq.config.QueueManager; import java.util.Hashtable; +import javax.annotation.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,7 +22,7 @@ public class WmqUtil { private WmqUtil() {} - public static PCFMessageAgent initPCFMessageAgent( + public static PCFMessageAgent initPcfMessageAgent( QueueManager queueManager, MQQueueManager ibmQueueManager) { try { PCFMessageAgent agent; @@ -50,7 +51,7 @@ && isNotNullOrEmpty(queueManager.getReplyQueuePrefix())) { return agent; } catch (MQDataException mqe) { logger.error(mqe.getMessage(), mqe); - throw new RuntimeException(mqe); + throw new IllegalStateException(mqe); } } @@ -67,11 +68,11 @@ public static MQQueueManager connectToQueueManager(QueueManager queueManager) { return ibmQueueManager; } catch (MQException mqe) { logger.error(mqe.getMessage(), mqe); - throw new RuntimeException(mqe.getMessage()); + throw new IllegalStateException(mqe.getMessage()); } } - private static boolean isNotNullOrEmpty(String str) { + private static boolean isNotNullOrEmpty(@Nullable String str) { return str != null && !str.isEmpty(); } } diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java index a04728dcc..6fc5587e2 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java @@ -53,7 +53,7 @@ void setup() throws Exception { } @Test - void testProcessPCFRequestAndPublishQMetricsForInquireQStatusCmd() throws Exception { + void testProcessPcfRequestAndPublishQMetricsForInquireQStatusCmd() throws Exception { QueueCollectorSharedState sharedState = new QueueCollectorSharedState(); sharedState.putQueueType("AMQ.5AF1608820C7D76E", "local-transmission"); sharedState.putQueueType("DEV.DEAD.LETTER.QUEUE", "local-transmission"); @@ -62,7 +62,7 @@ void testProcessPCFRequestAndPublishQMetricsForInquireQStatusCmd() throws Except when(pcfMessageAgent.send(request)).thenReturn(createPCFResponseForInquireQStatusCmd()); classUnderTest = new QueueCollectionBuddy(meter, sharedState); - classUnderTest.processPCFRequestAndPublishQMetrics( + classUnderTest.processPcfRequestAndPublishQMetrics( collectorContext, request, "*", InquireQStatusCmdCollector.ATTRIBUTES); Map> expectedValues = @@ -107,11 +107,11 @@ void testProcessPCFRequestAndPublishQMetricsForInquireQStatusCmd() throws Except } @Test - void testProcessPCFRequestAndPublishQMetricsForInquireQCmd() throws Exception { + void testProcessPcfRequestAndPublishQMetricsForInquireQCmd() throws Exception { PCFMessage request = createPCFRequestForInquireQCmd(); when(pcfMessageAgent.send(request)).thenReturn(createPCFResponseForInquireQCmd()); classUnderTest = new QueueCollectionBuddy(meter, new QueueCollectorSharedState()); - classUnderTest.processPCFRequestAndPublishQMetrics( + classUnderTest.processPcfRequestAndPublishQMetrics( collectorContext, request, "*", InquireQCmdCollector.ATTRIBUTES); Map> expectedValues = @@ -154,7 +154,7 @@ void testProcessPCFRequestAndPublishQMetricsForInquireQCmd() throws Exception { } @Test - void testProcessPCFRequestAndPublishQMetricsForResetQStatsCmd() throws Exception { + void testProcessPcfRequestAndPublishQMetricsForResetQStatsCmd() throws Exception { QueueCollectorSharedState sharedState = new QueueCollectorSharedState(); sharedState.putQueueType("AMQ.5AF1608820C7D76E", "local-transmission"); sharedState.putQueueType("DEV.DEAD.LETTER.QUEUE", "local-transmission"); @@ -162,7 +162,7 @@ void testProcessPCFRequestAndPublishQMetricsForResetQStatsCmd() throws Exception PCFMessage request = createPCFRequestForResetQStatsCmd(); when(pcfMessageAgent.send(request)).thenReturn(createPCFResponseForResetQStatsCmd()); classUnderTest = new QueueCollectionBuddy(meter, sharedState); - classUnderTest.processPCFRequestAndPublishQMetrics( + classUnderTest.processPcfRequestAndPublishQMetrics( collectorContext, request, "*", ResetQStatsCmdCollector.ATTRIBUTES); for (MetricData metric : otelTesting.getMetrics()) { From a2b95a8a113c9cf44de3201ac9fac816a566e5a9 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 13 Jun 2025 13:59:05 -0700 Subject: [PATCH 05/66] more cleanups --- .../ibm/mq/config/ExcludeFilters.java | 4 +--- .../InquireTStatusCmdCollector.java | 4 ++-- .../ibm/mq/metricscollector/MessageFilter.java | 12 ++++++++---- .../mq/metricscollector/QueueCollectionBuddy.java | 14 +++++++++----- .../ReadConfigurationEventQueueCollector.java | 2 ++ .../opentelemetry/ibm/mq/opentelemetry/Config.java | 8 ++++++-- .../opentelemetry/ibm/mq/opentelemetry/Main.java | 12 ++++++++---- .../ibm/mq/opentelemetry/ConfigTest.java | 2 +- 8 files changed, 37 insertions(+), 21 deletions(-) diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/ExcludeFilters.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/ExcludeFilters.java index 7d9d4950a..f02f05cc0 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/ExcludeFilters.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/ExcludeFilters.java @@ -11,9 +11,7 @@ import java.util.HashSet; import java.util.Set; -/** - * A jackson databind class used for config. - */ +/** A jackson databind class used for config. */ public class ExcludeFilters { private String type = "UNKNOWN"; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireTStatusCmdCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireTStatusCmdCollector.java index 0a3ec157c..cc9eb9ad7 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireTStatusCmdCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireTStatusCmdCollector.java @@ -51,7 +51,7 @@ public void accept(MetricsCollectorContext context) { request.addParameter(CMQC.MQCA_TOPIC_STRING, topicGenericName); try { - processPCFRequestAndPublishQMetrics(context, topicGenericName, request); + processPcfRequestAndPublishQMetrics(context, topicGenericName, request); } catch (PCFException pcfe) { logger.error( "PCFException caught while collecting metric for Queue: {} for command MQCMD_INQUIRE_TOPIC_STATUS", @@ -73,7 +73,7 @@ public void accept(MetricsCollectorContext context) { exitTime); } - private void processPCFRequestAndPublishQMetrics( + private void processPcfRequestAndPublishQMetrics( MetricsCollectorContext context, String topicGenericName, PCFMessage request) throws IOException, MQDataException { logger.debug( diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MessageFilter.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MessageFilter.java index ffcc5ba3c..531c217b0 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MessageFilter.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/MessageFilter.java @@ -5,12 +5,15 @@ package io.opentelemetry.ibm.mq.metricscollector; +import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.ibm.mq.headers.pcf.PCFException; import com.ibm.mq.headers.pcf.PCFMessage; import io.opentelemetry.ibm.mq.config.ExcludeFilters; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,15 +52,16 @@ public List filter(List messages) throws PCFException { static class MessageFilterBuilder { - private Collection filters; - private String kind; + private final String kind; + private Set filters = new HashSet<>(); public MessageFilterBuilder(String kind) { this.kind = kind; } - public MessageFilterBuilder excluding(Collection filters) { - this.filters = filters; + @CanIgnoreReturnValue + public MessageFilterBuilder excluding(Set filters) { + this.filters = new HashSet<>(filters); return this; } diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java index 510d17de9..5cf5f9ee5 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java @@ -30,6 +30,7 @@ import java.util.List; import java.util.Map; import java.util.function.Function; +import javax.annotation.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -129,7 +130,7 @@ private static AllowedGauge createAllowedGauge( void processPcfRequestAndPublishQMetrics( MetricsCollectorContext context, PCFMessage request, String queueGenericName, int[] fields) { try { - doProcessPCFRequestAndPublishQMetrics(context, request, queueGenericName, fields); + doProcessPcfRequestAndPublishQMetrics(context, request, queueGenericName, fields); } catch (PCFException pcfe) { logger.error( "PCFException caught while collecting metric for Queue: {}", queueGenericName, pcfe); @@ -150,7 +151,7 @@ void processPcfRequestAndPublishQMetrics( } } - private void doProcessPCFRequestAndPublishQMetrics( + private void doProcessPcfRequestAndPublishQMetrics( MetricsCollectorContext context, PCFMessage request, String queueGenericName, int[] fields) throws IOException, MQDataException { logger.debug( @@ -191,6 +192,7 @@ private void handleMessage(MetricsCollectorContext context, PCFMessage message, getMetrics(context, message, queueName, queueType, fields); } + @Nullable private String getQueueTypeFromName(PCFMessage message, String queueName) throws PCFException { if (message.getParameterValue(CMQC.MQIA_Q_TYPE) == null) { return sharedState.getType(queueName); @@ -216,8 +218,9 @@ private static String maybeAppendUsage(PCFMessage message, String baseQueueType) return baseQueueType + "-normal"; case CMQC.MQUS_TRANSMISSION: return baseQueueType + "-transmission"; + default: + return baseQueueType; } - return baseQueueType; } private static String getBaseQueueType(PCFMessage message) throws PCFException { @@ -232,9 +235,10 @@ private static String getBaseQueueType(PCFMessage message) throws PCFException { return "cluster"; case MQQT_MODEL: return "model"; + default: + logger.warn("Unknown type of queue {}", message.getIntParameterValue(CMQC.MQIA_Q_TYPE)); + return "unknown"; } - logger.warn("Unknown type of queue {}", message.getIntParameterValue(CMQC.MQIA_Q_TYPE)); - return "unknown"; } private void getMetrics( diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ReadConfigurationEventQueueCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ReadConfigurationEventQueueCollector.java index f5ab9293c..734827c65 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ReadConfigurationEventQueueCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ReadConfigurationEventQueueCollector.java @@ -20,6 +20,7 @@ import io.opentelemetry.ibm.mq.metrics.Metrics; import java.io.IOException; import java.util.function.Consumer; +import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,6 +37,7 @@ public ReadConfigurationEventQueueCollector(Meter meter) { this.maxHandlesGauge = Metrics.createMqManagerMaxHandles(meter); } + @Nullable private PCFMessage findLastUpdate( MetricsCollectorContext context, long entryTime, String configurationQueueName) throws Exception { diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Config.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Config.java index ed27ad831..e3b32acea 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Config.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Config.java @@ -10,11 +10,15 @@ import org.slf4j.LoggerFactory; /** Utilities reading configuration and create domain objects */ -class Config { +final class Config { private static final Logger logger = LoggerFactory.getLogger(Config.class); - static void setUpSSLConnection(Map config) { + private Config(){ + + } + + static void setUpSslConnection(Map config) { getConfigValueAndSetSystemProperty(config, "keyStorePath", "javax.net.ssl.keyStore"); getConfigValueAndSetSystemProperty( config, "keyStorePassword", "javax.net.ssl.keyStorePassword"); diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java index fe6f144d4..80d350bf6 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java @@ -13,15 +13,19 @@ import io.opentelemetry.sdk.resources.Resource; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import org.jetbrains.annotations.VisibleForTesting; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class Main { +@SuppressWarnings("SystemOut") +public final class Main { private static final Logger logger = LoggerFactory.getLogger(Main.class); + private Main() {} + public static void main(String[] args) throws Exception { if (args.length == 0) { System.err.println("Usage: Main "); @@ -52,12 +56,12 @@ public static void main(String[] args) throws Exception { }); Config.configureSecurity(config); - Config.setUpSSLConnection(config.getSslConnection()); + Config.setUpSslConnection(config.getSslConnection()); run(config, service); } - public static void run(ConfigWrapper config, final ScheduledExecutorService service) { + public static void run(ConfigWrapper config, ScheduledExecutorService service) { AutoConfiguredOpenTelemetrySdk sdk = AutoConfiguredOpenTelemetrySdk.builder() @@ -77,7 +81,7 @@ public static void run( Runtime.getRuntime().addShutdownHook(new Thread(service::shutdown)); WmqMonitor monitor = new WmqMonitor(config, service, meterProvider.get("websphere/mq")); - service.scheduleAtFixedRate( + ScheduledFuture unused = service.scheduleAtFixedRate( monitor::run, config.getTaskInitialDelaySeconds(), config.getTaskDelaySeconds(), diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigTest.java index 53500907e..0607a308b 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigTest.java @@ -28,7 +28,7 @@ public void cacheSystemProperties() { @Test void testSSLConnection() { - Config.setUpSSLConnection( + Config.setUpSslConnection( new HashMap() { { put("keyStorePath", "foo"); From 91080d3ba852fbe31f2bc8de1408738145af3903 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 13 Jun 2025 14:03:27 -0700 Subject: [PATCH 06/66] more cleanups --- .../io/opentelemetry/ibm/mq/WmqContext.java | 5 +-- .../io/opentelemetry/ibm/mq/WmqMonitor.java | 2 +- .../ibm/mq/config/QueueManager.java | 32 ++++++++++++------- .../ReadConfigurationEventQueueCollector.java | 2 +- .../ibm/mq/opentelemetry/Config.java | 4 +-- .../ibm/mq/opentelemetry/Main.java | 11 ++++--- .../io/opentelemetry/ibm/mq/util/WmqUtil.java | 2 +- 7 files changed, 34 insertions(+), 24 deletions(-) diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqContext.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqContext.java index 279cbd3a7..6ded88547 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqContext.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqContext.java @@ -8,6 +8,7 @@ import com.ibm.mq.constants.CMQC; import io.opentelemetry.ibm.mq.config.QueueManager; import java.util.Hashtable; +import javax.annotation.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,7 +31,7 @@ public WmqContext(QueueManager queueManager) { /** Note: This Hashtable type is needed for IBM client classes. */ @SuppressWarnings("JdkObsolete") - public Hashtable getMQEnvironment() { + public Hashtable getMqEnvironment() { Hashtable env = new Hashtable<>(); addEnvProperty(env, CMQC.HOST_NAME_PROPERTY, queueManager.getHost()); addEnvProperty(env, CMQC.PORT_PROPERTY, queueManager.getPort()); @@ -56,7 +57,7 @@ public WmqContext(QueueManager queueManager) { } @SuppressWarnings({"unused", "unchecked", "rawtypes"}) - private void addEnvProperty(Hashtable env, String propName, Object propVal) { + private static void addEnvProperty(Hashtable env, String propName, @Nullable Object propVal) { if (null != propVal) { if (propVal instanceof String) { String propString = (String) propVal; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqMonitor.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqMonitor.java index 679295a94..496c7f95b 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqMonitor.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqMonitor.java @@ -33,8 +33,8 @@ import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.function.Consumer; +import javax.annotation.Nullable; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/QueueManager.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/QueueManager.java index 8ad0626ff..685840977 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/QueueManager.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/config/QueueManager.java @@ -6,7 +6,7 @@ package io.opentelemetry.ibm.mq.config; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import org.jetbrains.annotations.Nullable; +import javax.annotation.Nullable; /** This is a jackson databind class used purely for config. */ @JsonIgnoreProperties(ignoreUnknown = true) @@ -40,7 +40,8 @@ public class QueueManager { @Nullable private ResourceFilters listenerFilters; @Nullable private ResourceFilters topicFilters; - public @Nullable String getHost() { + @Nullable + public String getHost() { return host; } @@ -64,7 +65,8 @@ public void setName(String name) { this.name = name; } - public @Nullable String getChannelName() { + @Nullable + public String getChannelName() { return channelName; } @@ -72,7 +74,8 @@ public void setChannelName(@Nullable String channelName) { this.channelName = channelName; } - public @Nullable String getTransportType() { + @Nullable + public String getTransportType() { return transportType; } @@ -80,7 +83,8 @@ public void setTransportType(@Nullable String transportType) { this.transportType = transportType; } - public @Nullable String getUsername() { + @Nullable + public String getUsername() { return username; } @@ -88,7 +92,8 @@ public void setUsername(@Nullable String username) { this.username = username; } - public @Nullable String getPassword() { + @Nullable + public String getPassword() { return password; } @@ -107,7 +112,8 @@ public void setQueueFilters(@Nullable ResourceFilters queueFilters) { this.queueFilters = queueFilters; } - public @Nullable String getSslKeyRepository() { + @Nullable + public String getSslKeyRepository() { return sslKeyRepository; } @@ -115,7 +121,8 @@ public void setSslKeyRepository(@Nullable String sslKeyRepository) { this.sslKeyRepository = sslKeyRepository; } - public @Nullable String getCipherSuite() { + @Nullable + public String getCipherSuite() { return cipherSuite; } @@ -123,7 +130,8 @@ public void setCipherSuite(String cipherSuite) { this.cipherSuite = cipherSuite; } - public @Nullable String getCipherSpec() { + @Nullable + public String getCipherSpec() { return cipherSpec; } @@ -142,7 +150,8 @@ public void setChannelFilters(@Nullable ResourceFilters channelFilters) { this.channelFilters = channelFilters; } - public @Nullable String getReplyQueuePrefix() { + @Nullable + public String getReplyQueuePrefix() { return replyQueuePrefix; } @@ -150,7 +159,8 @@ public void setReplyQueuePrefix(@Nullable String replyQueuePrefix) { this.replyQueuePrefix = replyQueuePrefix; } - public @Nullable String getModelQueueName() { + @Nullable + public String getModelQueueName() { return modelQueueName; } diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ReadConfigurationEventQueueCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ReadConfigurationEventQueueCollector.java index 734827c65..6200cfd61 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ReadConfigurationEventQueueCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ReadConfigurationEventQueueCollector.java @@ -20,7 +20,7 @@ import io.opentelemetry.ibm.mq.metrics.Metrics; import java.io.IOException; import java.util.function.Consumer; -import org.jetbrains.annotations.Nullable; +import javax.annotation.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Config.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Config.java index e3b32acea..68ede61c7 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Config.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Config.java @@ -14,9 +14,7 @@ final class Config { private static final Logger logger = LoggerFactory.getLogger(Config.class); - private Config(){ - - } + private Config() {} static void setUpSslConnection(Map config) { getConfigValueAndSetSystemProperty(config, "keyStorePath", "javax.net.ssl.keyStore"); diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java index 80d350bf6..d0963b091 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java @@ -81,10 +81,11 @@ public static void run( Runtime.getRuntime().addShutdownHook(new Thread(service::shutdown)); WmqMonitor monitor = new WmqMonitor(config, service, meterProvider.get("websphere/mq")); - ScheduledFuture unused = service.scheduleAtFixedRate( - monitor::run, - config.getTaskInitialDelaySeconds(), - config.getTaskDelaySeconds(), - TimeUnit.SECONDS); + ScheduledFuture unused = + service.scheduleAtFixedRate( + monitor::run, + config.getTaskInitialDelaySeconds(), + config.getTaskDelaySeconds(), + TimeUnit.SECONDS); } } diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/WmqUtil.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/WmqUtil.java index 72c8c0278..cefa9e5d9 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/WmqUtil.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/util/WmqUtil.java @@ -58,7 +58,7 @@ && isNotNullOrEmpty(queueManager.getReplyQueuePrefix())) { @SuppressWarnings("rawtypes") public static MQQueueManager connectToQueueManager(QueueManager queueManager) { WmqContext auth = new WmqContext(queueManager); - Hashtable env = auth.getMQEnvironment(); + Hashtable env = auth.getMqEnvironment(); try { MQQueueManager ibmQueueManager = new MQQueueManager(queueManager.getName(), env); logger.debug( From cfd675c6a4bb18502e46677f519552fe4433bd04 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 13 Jun 2025 14:22:56 -0700 Subject: [PATCH 07/66] fixing tests erroreprone --- ibm-mq-metrics/build.gradle.kts | 3 +- .../ChannelMetricsCollectorTest.java | 7 +- .../InquireChannelCmdCollectorTest.java | 5 +- .../ListenerMetricsCollectorTest.java | 4 +- .../QueueCollectionBuddyTest.java | 89 ++++++++----------- .../QueueManagerMetricsCollectorTest.java | 7 +- .../TopicMetricsCollectorTest.java | 8 +- .../ibm/mq/opentelemetry/ConfigTest.java | 15 ++-- .../mq/opentelemetry/ConfigWrapperTest.java | 9 +- 9 files changed, 68 insertions(+), 79 deletions(-) diff --git a/ibm-mq-metrics/build.gradle.kts b/ibm-mq-metrics/build.gradle.kts index 9e0d06b37..a550c9397 100644 --- a/ibm-mq-metrics/build.gradle.kts +++ b/ibm-mq-metrics/build.gradle.kts @@ -48,7 +48,8 @@ dependencies { // testImplementation(libs.org.mockito.mockito.core) // testImplementation(libs.org.mockito.mockito.junit.jupiter) // testImplementation(libs.org.assertj.assertj.core) -// testImplementation(libs.io.opentelemetry.opentelemetry.sdk.testing) + testImplementation("com.google.guava:guava") + testImplementation("io.opentelemetry:opentelemetry-sdk-testing:1.50.0") // testImplementation(libs.com.ibm.mq.com.ibm.mq.jakarta.client) // testImplementation(libs.jakarta.jms.jakarta.jms.api) // testImplementation(libs.org.junit.jupiter.junit.jupiter.engine) diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollectorTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollectorTest.java index fd1d5e516..8bf675827 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollectorTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollectorTest.java @@ -10,7 +10,7 @@ import static io.opentelemetry.ibm.mq.metricscollector.MetricAssert.assertThatMetric; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.params.provider.Arguments.arguments; -import static org.mockito.Mockito.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import com.fasterxml.jackson.databind.ObjectMapper; @@ -25,6 +25,7 @@ import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.stream.Stream; import org.junit.jupiter.api.BeforeEach; @@ -69,7 +70,7 @@ void testPublishMetrics() throws Exception { List metricsList = new ArrayList<>( - List.of( + Arrays.asList( "mq.message.count", "mq.status", "mq.byte.sent", @@ -133,7 +134,7 @@ void testPublishMetrics() throws Exception { MQCFIN [type: 3, strucLength: 16, parameter: 1609 (MQIACH_CHANNEL_SUBSTATE), value: 300] */ - private PCFMessage[] createPCFResponseForInquireChannelStatusCmd() { + private static PCFMessage[] createPCFResponseForInquireChannelStatusCmd() { PCFMessage response1 = new PCFMessage(2, CMQCFC.MQCMD_INQUIRE_CHANNEL_STATUS, 1, true); response1.addParameter(CMQCFC.MQCACH_CHANNEL_NAME, "DEV.ADMIN.SVRCONN"); response1.addParameter(CMQCFC.MQIACH_CHANNEL_TYPE, 7); diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollectorTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollectorTest.java index 0c787ceb3..2dced05ea 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollectorTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollectorTest.java @@ -21,6 +21,7 @@ import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -60,7 +61,7 @@ public void testProcessPCFRequestAndPublishQMetricsForInquireQStatusCmd() throws classUnderTest.accept(context); List metricsList = new ArrayList<>( - List.of( + Arrays.asList( "mq.message.retry.count", "mq.message.received.count", "mq.message.sent.count")); for (MetricData metric : otelTesting.getMetrics()) { if (metricsList.remove(metric.getName())) { @@ -81,7 +82,7 @@ public void testProcessPCFRequestAndPublishQMetricsForInquireQStatusCmd() throws assertThat(metricsList).isEmpty(); } - private PCFMessage[] createPCFResponseForInquireChannelCmd() { + private static PCFMessage[] createPCFResponseForInquireChannelCmd() { PCFMessage response1 = new PCFMessage(2, CMQCFC.MQCMD_INQUIRE_CHANNEL, 1, true); response1.addParameter(CMQCFC.MQCACH_CHANNEL_NAME, "my.channel"); response1.addParameter(CMQCFC.MQIACH_CHANNEL_TYPE, CMQXC.MQCHT_SVRCONN); diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollectorTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollectorTest.java index b6cca0c09..8c8736ee7 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollectorTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollectorTest.java @@ -6,7 +6,7 @@ package io.opentelemetry.ibm.mq.metricscollector; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import com.fasterxml.jackson.databind.ObjectMapper; @@ -84,7 +84,7 @@ public void testPublishMetrics() throws Exception { MQCFIN [type: 3, strucLength: 16, parameter: 1599 (MQIACH_LISTENER_STATUS), value: 2] */ - private PCFMessage[] createPCFResponseForInquireListenerStatusCmd() { + private static PCFMessage[] createPCFResponseForInquireListenerStatusCmd() { PCFMessage response1 = new PCFMessage(2, CMQCFC.MQCMD_INQUIRE_LISTENER_STATUS, 1, true); response1.addParameter(CMQCFC.MQCACH_LISTENER_NAME, "DEV.DEFAULT.LISTENER.TCP"); response1.addParameter(CMQCFC.MQIACH_LISTENER_STATUS, 2); diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java index 6fc5587e2..8699534cb 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java @@ -9,6 +9,7 @@ import static org.mockito.Mockito.when; import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.ImmutableMap; import com.ibm.mq.constants.CMQC; import com.ibm.mq.constants.CMQCFC; import com.ibm.mq.headers.pcf.PCFMessage; @@ -66,32 +67,24 @@ void testProcessPcfRequestAndPublishQMetricsForInquireQStatusCmd() throws Except collectorContext, request, "*", InquireQStatusCmdCollector.ATTRIBUTES); Map> expectedValues = - new HashMap>() { - { - put( + new HashMap>( + ImmutableMap.of( "DEV.DEAD.LETTER.QUEUE", - new HashMap() { - { - put("mq.oldest.msg.age", -1L); - put("mq.uncommitted.messages", 0L); - put("mq.onqtime.1", -1L); - put("mq.onqtime.2", -1L); - put("mq.queue.depth", 0L); - } - }); - put( + new HashMap<>( + ImmutableMap.of( + "mq.oldest.msg.age", -1L, + "mq.uncommitted.messages", 0L, + "mq.onqtime.1", -1L, + "mq.onqtime.2", -1L, + "mq.queue.depth", 0L)), "DEV.QUEUE.1", - new HashMap() { - { - put("mq.oldest.msg.age", -1L); - put("mq.uncommitted.messages", 10L); - put("mq.onqtime.1", -1L); - put("mq.onqtime.2", -1L); - put("mq.queue.depth", 1L); - } - }); - } - }; + new HashMap( + ImmutableMap.of( + "mq.oldest.msg.age", -1L, + "mq.uncommitted.messages", 10L, + "mq.onqtime.1", -1L, + "mq.onqtime.2", -1L, + "mq.queue.depth", 1L)))); for (MetricData metric : otelTesting.getMetrics()) { for (LongPointData d : metric.getLongGaugeData().getPoints()) { @@ -115,30 +108,22 @@ void testProcessPcfRequestAndPublishQMetricsForInquireQCmd() throws Exception { collectorContext, request, "*", InquireQCmdCollector.ATTRIBUTES); Map> expectedValues = - new HashMap>() { - { - put( + new HashMap<>( + ImmutableMap.of( "DEV.DEAD.LETTER.QUEUE", - new HashMap() { - { - put("mq.queue.depth", 2L); - put("mq.max.queue.depth", 5000L); - put("mq.open.input.count", 2L); - put("mq.open.output.count", 2L); - } - }); - put( + new HashMap<>( + ImmutableMap.of( + "mq.queue.depth", 2L, + "mq.max.queue.depth", 5000L, + "mq.open.input.count", 2L, + "mq.open.output.count", 2L)), "DEV.QUEUE.1", - new HashMap() { - { - put("mq.queue.depth", 3L); - put("mq.max.queue.depth", 5000L); - put("mq.open.input.count", 3L); - put("mq.open.output.count", 3L); - } - }); - } - }; + new HashMap<>( + ImmutableMap.of( + "mq.queue.depth", 3L, + "mq.max.queue.depth", 5000L, + "mq.open.input.count", 3L, + "mq.open.output.count", 3L)))); for (MetricData metric : otelTesting.getMetrics()) { for (LongPointData d : metric.getLongGaugeData().getPoints()) { @@ -183,7 +168,7 @@ void testProcessPcfRequestAndPublishQMetricsForResetQStatsCmd() throws Exception MQCFST [type: 4, strucLength: 24, parameter: 2016 (MQCA_Q_NAME), codedCharSetId: 0, stringLength: 1, string: *] MQCFIL [type: 5, strucLength: 32, parameter: 1026 (MQIACF_Q_STATUS_ATTRS), count: 4, values: {2016, 1226, 1227, 1027}] */ - private PCFMessage createPCFRequestForInquireQStatusCmd() { + private static PCFMessage createPCFRequestForInquireQStatusCmd() { PCFMessage request = new PCFMessage(CMQCFC.MQCMD_INQUIRE_Q_STATUS); request.addParameter(CMQC.MQCA_Q_NAME, "*"); request.addParameter(CMQCFC.MQIACF_Q_STATUS_ATTRS, new int[] {2016, 1226, 1227, 1027}); @@ -218,7 +203,7 @@ private PCFMessage createPCFRequestForInquireQStatusCmd() { MQCFIL [type: 5, strucLength: 24, parameter: 1226 (MQIACF_Q_TIME_INDICATOR), count: 2, values: {-1, -1}] MQCFIN [type: 3, strucLength: 16, parameter: 1027 (MQIACF_UNCOMMITTED_MSGS), value: 0]" */ - private PCFMessage[] createPCFResponseForInquireQStatusCmd() { + private static PCFMessage[] createPCFResponseForInquireQStatusCmd() { PCFMessage response1 = new PCFMessage(2, CMQCFC.MQCMD_INQUIRE_Q_STATUS, 1, false); response1.addParameter(CMQC.MQCA_Q_NAME, "AMQ.5AF1608820C7D76E"); response1.addParameter(CMQCFC.MQIACF_Q_STATUS_TYPE, 1105); @@ -253,7 +238,7 @@ private PCFMessage[] createPCFResponseForInquireQStatusCmd() { MQCFIN [type: 3, strucLength: 16, parameter: 20 (MQIA_Q_TYPE), value: 1001] MQCFIL [type: 5, strucLength: 36, parameter: 1002 (MQIACF_Q_ATTRS), count: 5, values: {2016, 15, 3, 17, 18}] */ - private PCFMessage createPCFRequestForInquireQCmd() { + private static PCFMessage createPCFRequestForInquireQCmd() { PCFMessage request = new PCFMessage(CMQCFC.MQCMD_INQUIRE_Q); request.addParameter(CMQC.MQCA_Q_NAME, "*"); request.addParameter(CMQC.MQIA_Q_TYPE, CMQC.MQQT_ALL); @@ -290,7 +275,7 @@ private PCFMessage createPCFRequestForInquireQCmd() { MQCFIN [type: 3, strucLength: 16, parameter: 18 (MQIA_OPEN_OUTPUT_COUNT), value: 0]" */ - private PCFMessage[] createPCFResponseForInquireQCmd() { + private static PCFMessage[] createPCFResponseForInquireQCmd() { PCFMessage response1 = new PCFMessage(2, CMQCFC.MQCMD_INQUIRE_Q, 1, false); response1.addParameter(CMQC.MQCA_Q_NAME, "AMQ.5AF1608820C76D80"); response1.addParameter(CMQC.MQIA_Q_TYPE, 1); @@ -326,7 +311,7 @@ private PCFMessage[] createPCFResponseForInquireQCmd() { MQCFH [type: 1, strucLength: 36, version: 1, command: 17 (MQCMD_RESET_Q_STATS), msgSeqNumber: 1, control: 1, compCode: 0, reason: 0, parameterCount: 1] MQCFST [type: 4, strucLength: 24, parameter: 2016 (MQCA_Q_NAME), codedCharSetId: 0, stringLength: 1, string: *] */ - private PCFMessage createPCFRequestForResetQStatsCmd() { + private static PCFMessage createPCFRequestForResetQStatsCmd() { PCFMessage request = new PCFMessage(CMQCFC.MQCMD_RESET_Q_STATS); request.addParameter(CMQC.MQCA_Q_NAME, "*"); return request; @@ -341,7 +326,7 @@ private PCFMessage createPCFRequestForResetQStatsCmd() { MQCFIN [type: 3, strucLength: 16, parameter: 36 (MQIA_HIGH_Q_DEPTH), value: 0] MQCFIN [type: 3, strucLength: 16, parameter: 35 (MQIA_TIME_SINCE_RESET), value: 65]" */ - private PCFMessage[] createPCFResponseForResetQStatsCmd() { + private static PCFMessage[] createPCFResponseForResetQStatsCmd() { PCFMessage response1 = new PCFMessage(2, CMQCFC.MQCMD_RESET_Q_STATS, 1, false); response1.addParameter(CMQC.MQCA_Q_NAME, "DEV.DEAD.LETTER.QUEUE"); response1.addParameter(CMQC.MQIA_MSG_ENQ_COUNT, 3); diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerMetricsCollectorTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerMetricsCollectorTest.java index 7d5ad2dc4..52578e4e3 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerMetricsCollectorTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerMetricsCollectorTest.java @@ -5,8 +5,9 @@ package io.opentelemetry.ibm.mq.metricscollector; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import com.fasterxml.jackson.databind.ObjectMapper; @@ -57,7 +58,7 @@ public void testProcessPCFRequestAndPublishQMetricsForInquireQStatusCmd() throws new QueueManagerMetricsCollector( otelTesting.getOpenTelemetry().getMeter("opentelemetry.io/mq")); classUnderTest.accept(context); - List metricsList = new ArrayList<>(List.of("mq.manager.status")); + List metricsList = new ArrayList<>(singletonList("mq.manager.status")); for (MetricData metric : otelTesting.getMetrics()) { if (metricsList.remove(metric.getName())) { @@ -100,7 +101,7 @@ public void testProcessPCFRequestAndPublishQMetricsForInquireQStatusCmd() throws MQCFST [type: 4, strucLength: 28, parameter: 3176 (null), codedCharSetId: 819, stringLength: 8, string: 08.32.08] */ - private PCFMessage[] createPCFResponseForInquireQMgrStatusCmd() { + private static PCFMessage[] createPCFResponseForInquireQMgrStatusCmd() { PCFMessage response1 = new PCFMessage(2, CMQCFC.MQCMD_INQUIRE_Q_MGR_STATUS, 1, true); response1.addParameter(CMQC.MQCA_Q_MGR_NAME, "QM1"); response1.addParameter(CMQCFC.MQIACF_Q_MGR_STATUS, 2); diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/TopicMetricsCollectorTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/TopicMetricsCollectorTest.java index 841231242..562adcc74 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/TopicMetricsCollectorTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/TopicMetricsCollectorTest.java @@ -6,7 +6,8 @@ package io.opentelemetry.ibm.mq.metricscollector; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; import com.fasterxml.jackson.databind.ObjectMapper; import com.ibm.mq.constants.CMQC; @@ -20,6 +21,7 @@ import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -61,7 +63,7 @@ void testPublishMetrics() throws Exception { classUnderTest.accept(context); List metricsList = - new ArrayList<>(List.of("mq.publish.count", "mq.subscription.count")); + new ArrayList<>(Arrays.asList("mq.publish.count", "mq.subscription.count")); for (MetricData metric : otelTesting.getMetrics()) { if (metricsList.remove(metric.getName())) { @@ -90,7 +92,7 @@ void testPublishMetrics() throws Exception { assertThat(metricsList).isEmpty(); } - private PCFMessage[] createPCFResponseForInquireTopicStatusCmd() { + private static PCFMessage[] createPCFResponseForInquireTopicStatusCmd() { PCFMessage response1 = new PCFMessage(2, CMQCFC.MQCMD_INQUIRE_TOPIC_STATUS, 1, false); response1.addParameter(CMQC.MQCA_TOPIC_STRING, "test"); response1.addParameter(CMQC.MQIA_PUB_COUNT, 2); diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigTest.java index 0607a308b..73aadc6a1 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigTest.java @@ -7,6 +7,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import com.google.common.collect.ImmutableMap; import java.util.HashMap; import java.util.Map; import java.util.Properties; @@ -29,14 +30,12 @@ public void cacheSystemProperties() { @Test void testSSLConnection() { Config.setUpSslConnection( - new HashMap() { - { - put("keyStorePath", "foo"); - put("trustStorePath", "bar"); - put("keyStorePassword", "password"); - put("trustStorePassword", "password1"); - } - }); + new HashMap( + ImmutableMap.of( + "keyStorePath", "foo", + "trustStorePath", "bar", + "keyStorePassword", "password", + "trustStorePassword", "password1"))); assertThat(System.getProperties().get("javax.net.ssl.keyStore")).isEqualTo("foo"); assertThat(System.getProperties().get("javax.net.ssl.trustStorePath")).isEqualTo("bar"); diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java index dcd4aa490..835caed37 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java @@ -8,7 +8,6 @@ import static java.util.Collections.singletonList; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import java.io.FileNotFoundException; import java.time.Duration; import java.time.temporal.ChronoUnit; import org.junit.jupiter.api.BeforeEach; @@ -24,25 +23,25 @@ void setUp() { } @Test - void testQueueManagerNames() throws FileNotFoundException { + void testQueueManagerNames() throws Exception { ConfigWrapper config = ConfigWrapper.parse(file); assertThat(config.getQueueManagerNames()).isEqualTo(singletonList("QM1")); } @Test - void testNumberOfThreads() throws FileNotFoundException { + void testNumberOfThreads() throws Exception { ConfigWrapper config = ConfigWrapper.parse(file); assertThat(config.getNumberOfThreads()).isEqualTo(20); } @Test - void testTaskDelay() throws FileNotFoundException { + void testTaskDelay() throws Exception { ConfigWrapper config = ConfigWrapper.parse(file); assertThat(config.getTaskDelay()).isEqualTo(Duration.of(27, ChronoUnit.SECONDS)); } @Test - void testTaskInitialDelay() throws FileNotFoundException { + void testTaskInitialDelay() throws Exception { ConfigWrapper config = ConfigWrapper.parse(file); assertThat(config.getTaskInitialDelaySeconds()).isEqualTo(0); } From c0fde4446dbe07d05b1802d8821628a16e68a6f3 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 13 Jun 2025 14:35:02 -0700 Subject: [PATCH 08/66] start adding/fixing integrationtests --- ibm-mq-metrics/build.gradle.kts | 40 +-- .../mq/integration/tests/JakartaPutGet.java | 294 ++++++++++++++++++ .../mq/integration/tests/TestWMQMonitor.java | 58 ++++ .../tests/WMQMonitorIntegrationTest.java | 281 +++++++++++++++++ 4 files changed, 653 insertions(+), 20 deletions(-) create mode 100644 ibm-mq-metrics/src/integrationTest/java/io/opentelemetry/ibm/mq/integration/tests/JakartaPutGet.java create mode 100644 ibm-mq-metrics/src/integrationTest/java/io/opentelemetry/ibm/mq/integration/tests/TestWMQMonitor.java create mode 100644 ibm-mq-metrics/src/integrationTest/java/io/opentelemetry/ibm/mq/integration/tests/WMQMonitorIntegrationTest.java diff --git a/ibm-mq-metrics/build.gradle.kts b/ibm-mq-metrics/build.gradle.kts index a550c9397..8be9fed0e 100644 --- a/ibm-mq-metrics/build.gradle.kts +++ b/ibm-mq-metrics/build.gradle.kts @@ -39,28 +39,13 @@ dependencies { api("io.opentelemetry:opentelemetry-exporter-otlp") api("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") api("org.slf4j:slf4j-api:2.0.7") -// api(libs.org.apache.logging.log4j.log4j.api) -// api(libs.org.apache.logging.log4j.log4j.core) -// api(libs.org.apache.logging.log4j.log4j.slf4j2.impl) -// api(libs.org.json.json) -// testImplementation(libs.org.junit.jupiter.junit.jupiter.api) -// testImplementation(libs.org.junit.jupiter.junit.jupiter.params) -// testImplementation(libs.org.mockito.mockito.core) -// testImplementation(libs.org.mockito.mockito.junit.jupiter) -// testImplementation(libs.org.assertj.assertj.core) testImplementation("com.google.guava:guava") testImplementation("io.opentelemetry:opentelemetry-sdk-testing:1.50.0") -// testImplementation(libs.com.ibm.mq.com.ibm.mq.jakarta.client) -// testImplementation(libs.jakarta.jms.jakarta.jms.api) -// testImplementation(libs.org.junit.jupiter.junit.jupiter.engine) -// testRuntimeOnly(libs.org.junit.platform.junit.platform.launcher) -// integrationTestImplementation(libs.org.assertj.assertj.core) -// integrationTestImplementation(libs.org.junit.jupiter.junit.jupiter.api) -// integrationTestImplementation(libs.io.opentelemetry.opentelemetry.sdk.testing) -// integrationTestImplementation(libs.com.ibm.mq.com.ibm.mq.jakarta.client) -// integrationTestImplementation(libs.jakarta.jms.jakarta.jms.api) -// integrationTestImplementation(libs.org.junit.jupiter.junit.jupiter.engine) -// integrationTestRuntimeOnly(libs.org.junit.platform.junit.platform.launcher) + integrationTestImplementation("org.assertj:assertj-core:3.27.3") + integrationTestImplementation("org.junit.jupiter:junit-jupiter-api:5.12.2") + integrationTestImplementation("io.opentelemetry:opentelemetry-sdk-testing:1.50.0") + integrationTestImplementation("com.ibm.mq:com.ibm.mq.jakarta.client:9.4.2.0") + integrationTestImplementation("jakarta.jms:jakarta.jms-api:3.1.0") ibmClientJar("com.ibm.mq:com.ibm.mq.allclient:9.4.2.1") { artifact { name = "com.ibm.mq.allclient" @@ -75,3 +60,18 @@ tasks.shadowJar { exclude(dependency("com.ibm.mq:com.ibm.mq.allclient:9.4.2.1")) } } + +val integrationTest = tasks.register("integrationTest") { + description = "Runs integration tests." + group = "verification" + + testClassesDirs = sourceSets["integrationTest"].output.classesDirs + classpath = sourceSets["integrationTest"].runtimeClasspath + shouldRunAfter("test") + + useJUnitPlatform() + + testLogging { + events("passed") + } +} diff --git a/ibm-mq-metrics/src/integrationTest/java/io/opentelemetry/ibm/mq/integration/tests/JakartaPutGet.java b/ibm-mq-metrics/src/integrationTest/java/io/opentelemetry/ibm/mq/integration/tests/JakartaPutGet.java new file mode 100644 index 000000000..02f4ad441 --- /dev/null +++ b/ibm-mq-metrics/src/integrationTest/java/io/opentelemetry/ibm/mq/integration/tests/JakartaPutGet.java @@ -0,0 +1,294 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.ibm.mq.integration.tests; + +import com.ibm.mq.MQException; +import com.ibm.mq.MQQueueManager; +import com.ibm.mq.constants.CMQC; +import com.ibm.mq.constants.CMQCFC; +import com.ibm.mq.headers.pcf.PCFException; +import com.ibm.mq.headers.pcf.PCFMessage; +import com.ibm.mq.headers.pcf.PCFMessageAgent; +import com.ibm.msg.client.jakarta.jms.JmsConnectionFactory; +import com.ibm.msg.client.jakarta.jms.JmsFactoryFactory; +import com.ibm.msg.client.jakarta.wmq.WMQConstants; +import io.opentelemetry.ibm.mq.config.QueueManager; +import io.opentelemetry.ibm.mq.util.WmqUtil; +import jakarta.jms.Destination; +import jakarta.jms.JMSConsumer; +import jakarta.jms.JMSContext; +import jakarta.jms.JMSException; +import jakarta.jms.JMSProducer; +import jakarta.jms.JMSRuntimeException; +import jakarta.jms.TextMessage; + +/** + * This code was adapted from https://github.com/ibm-messaging/mq-dev-samples/. + * + *

A minimal and simple application for Point-to-point messaging. + * + *

Application makes use of fixed literals, any customisations will require re-compilation of + * this source file. Application assumes that the named queue is empty prior to a run. + * + *

Notes: + * + *

API type: Jakarta API (JMS v3.0, simplified domain) + * + *

Messaging domain: Point-to-point + * + *

Provider type: IBM MQ + * + *

Connection mode: Client connection + * + *

JNDI in use: No + */ +public final class JakartaPutGet { + + private JakartaPutGet(){ + } + + public static void createQueue(QueueManager manager, String name, int maxDepth) { + MQQueueManager ibmQueueManager = WmqUtil.connectToQueueManager(manager); + PCFMessageAgent agent = WmqUtil.initPcfMessageAgent(manager, ibmQueueManager); + PCFMessage request = new PCFMessage(CMQCFC.MQCMD_CREATE_Q); + request.addParameter(com.ibm.mq.constants.CMQC.MQCA_Q_NAME, name); + request.addParameter(CMQC.MQIA_Q_TYPE, CMQC.MQQT_LOCAL); + + request.addParameter(CMQC.MQIA_MAX_Q_DEPTH, maxDepth); + // these parameters are indicated in percentage of max depth. + request.addParameter(CMQC.MQIA_Q_DEPTH_HIGH_LIMIT, 75); + request.addParameter(CMQC.MQIA_Q_DEPTH_LOW_LIMIT, 20); + request.addParameter(CMQC.MQIA_Q_DEPTH_HIGH_EVENT, CMQCFC.MQEVR_ENABLED); + request.addParameter(CMQC.MQIA_Q_DEPTH_LOW_EVENT, CMQCFC.MQEVR_ENABLED); + request.addParameter(CMQC.MQIA_Q_DEPTH_MAX_EVENT, CMQCFC.MQEVR_ENABLED); + try { + agent.send(request); + } catch (PCFException e) { + if (e.reasonCode == CMQCFC.MQRCCF_OBJECT_ALREADY_EXISTS) { + return; + } + throw new RuntimeException(e); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * @param manager Queue manager configuration + * @param queueName Queue that the application uses to put and get messages to and from + * @param numberOfMessages Number of messages to send + * @param sleepIntervalMs Sleep interval in ms + */ + public static void runPutGet( + QueueManager manager, String queueName, int numberOfMessages, int sleepIntervalMs) { + + createQueue(manager, queueName, 100000); + JMSContext context = null; + JMSContext senderContext = null; + try { + // Create a connection factory + JmsFactoryFactory ff = JmsFactoryFactory.getInstance(WMQConstants.JAKARTA_WMQ_PROVIDER); + JmsConnectionFactory cf = ff.createConnectionFactory(); + + // Set the properties + cf.setStringProperty(WMQConstants.WMQ_HOST_NAME, manager.getHost()); + cf.setIntProperty(WMQConstants.WMQ_PORT, manager.getPort()); + cf.setStringProperty(WMQConstants.WMQ_CHANNEL, manager.getChannelName()); + cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT); + cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, manager.getName()); + cf.setStringProperty(WMQConstants.WMQ_APPLICATIONNAME, "JakartaPutGet (Jakarta)"); + cf.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP, true); + cf.setStringProperty(WMQConstants.USERID, manager.getUsername()); + cf.setStringProperty(WMQConstants.PASSWORD, manager.getPassword()); + // cf.setStringProperty(WMQConstants.WMQ_SSL_CIPHER_SUITE, "*TLS12ORHIGHER"); + // cf.setIntProperty(MQConstants.CERTIFICATE_VALIDATION_POLICY, + // MQConstants.MQ_CERT_VAL_POLICY_NONE); + + // Create Jakarta objects + context = cf.createContext(); + Destination destination = context.createQueue("queue:///" + queueName); + + JMSConsumer consumer = context.createConsumer(destination); + consumer.setMessageListener(message -> {}); + + senderContext = cf.createContext(); + Destination senderDestination = senderContext.createQueue("queue:///" + queueName); + + for (int i = 0; i < numberOfMessages; i++) { + long uniqueNumber = System.currentTimeMillis() % 1000; + TextMessage message = + senderContext.createTextMessage("Your lucky number today is " + uniqueNumber); + message.setIntProperty(WMQConstants.JMS_IBM_CHARACTER_SET, 37); + JMSProducer producer = senderContext.createProducer(); + producer.send(senderDestination, message); + + Thread.sleep(sleepIntervalMs); + } + + } catch (JMSException | InterruptedException jmsex) { + throw new RuntimeException(jmsex); + } finally { + if (context != null) { + context.close(); + } + if (senderContext != null) { + senderContext.close(); + } + } + } + + /** + * Send a number of messages to the queue. + * + * @param manager Queue manager configuration + * @param queueName Queue that the application uses to put and get messages to and from + * @param numberOfMessages Number of messages to send + */ + public static void sendMessages(QueueManager manager, String queueName, int numberOfMessages) { + + createQueue(manager, queueName, 1000); + JMSContext context = null; + try { + // Create a connection factory + JmsFactoryFactory ff = JmsFactoryFactory.getInstance(WMQConstants.JAKARTA_WMQ_PROVIDER); + JmsConnectionFactory cf = ff.createConnectionFactory(); + + // Set the properties + cf.setStringProperty(WMQConstants.WMQ_HOST_NAME, manager.getHost()); + cf.setIntProperty(WMQConstants.WMQ_PORT, manager.getPort()); + cf.setStringProperty(WMQConstants.WMQ_CHANNEL, manager.getChannelName()); + cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT); + cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, manager.getName()); + cf.setStringProperty(WMQConstants.WMQ_APPLICATIONNAME, "Message Sender"); + cf.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP, true); + cf.setStringProperty(WMQConstants.USERID, manager.getUsername()); + cf.setStringProperty(WMQConstants.PASSWORD, manager.getPassword()); + // cf.setStringProperty(WMQConstants.WMQ_SSL_CIPHER_SUITE, "*TLS12ORHIGHER"); + // cf.setIntProperty(MQConstants.CERTIFICATE_VALIDATION_POLICY, + // MQConstants.MQ_CERT_VAL_POLICY_NONE); + + // Create Jakarta objects + context = cf.createContext(); + Destination destination = context.createQueue("queue:///" + queueName); + + for (int i = 0; i < numberOfMessages; i++) { + long uniqueNumber = System.currentTimeMillis() % 1000; + TextMessage message = + context.createTextMessage("Your lucky number today is " + uniqueNumber); + message.setIntProperty(WMQConstants.JMS_IBM_CHARACTER_SET, 37); + JMSProducer producer = context.createProducer(); + producer.send(destination, message); + } + + } catch (JMSException e) { + throw new RuntimeException(e); + } catch (JMSRuntimeException e) { + if (e.getCause() instanceof MQException) { + MQException mqe = (MQException) e.getCause(); + if (mqe.getReason() == 2053) { // queue is full + return; + } + } + throw new RuntimeException(e); + } finally { + if (context != null) { + context.close(); + } + } + } + + /** + * Reads all the messages of the queue. + * + * @param manager Queue manager configuration + * @param queueName Queue that the application uses to put and get messages to and from + */ + public static void readMessages(QueueManager manager, String queueName) { + JMSContext context = null; + try { + // Create a connection factory + JmsFactoryFactory ff = JmsFactoryFactory.getInstance(WMQConstants.JAKARTA_WMQ_PROVIDER); + JmsConnectionFactory cf = ff.createConnectionFactory(); + + // Set the properties + cf.setStringProperty(WMQConstants.WMQ_HOST_NAME, manager.getHost()); + cf.setIntProperty(WMQConstants.WMQ_PORT, manager.getPort()); + cf.setStringProperty(WMQConstants.WMQ_CHANNEL, manager.getChannelName()); + cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT); + cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, manager.getName()); + cf.setStringProperty(WMQConstants.WMQ_APPLICATIONNAME, "Message Receiver"); + cf.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP, true); + cf.setStringProperty(WMQConstants.USERID, manager.getUsername()); + cf.setStringProperty(WMQConstants.PASSWORD, manager.getPassword()); + // cf.setStringProperty(WMQConstants.WMQ_SSL_CIPHER_SUITE, "*TLS12ORHIGHER"); + // cf.setIntProperty(MQConstants.CERTIFICATE_VALIDATION_POLICY, + // MQConstants.MQ_CERT_VAL_POLICY_NONE); + + // Create Jakarta objects + context = cf.createContext(); + Destination destination = context.createQueue("queue:///" + queueName); + + JMSConsumer consumer = context.createConsumer(destination); // autoclosable + while (consumer.receiveBody(String.class, 100) != null) {} + + } catch (JMSException e) { + throw new RuntimeException(e); + } catch (JMSRuntimeException e) { + if (e.getCause() instanceof MQException) { + MQException mqe = (MQException) e.getCause(); + if (mqe.getReason() == CMQC.MQRC_NO_MSG_AVAILABLE) { // out of messages, we read them all. + return; + } + } + throw new RuntimeException(e); + } finally { + if (context != null) { + context.close(); + } + } + } + + public static void tryLoginWithBadPassword(QueueManager manager) { + + JMSContext context = null; + try { + // Create a connection factory + JmsFactoryFactory ff = JmsFactoryFactory.getInstance(WMQConstants.JAKARTA_WMQ_PROVIDER); + JmsConnectionFactory cf = ff.createConnectionFactory(); + + // Set the properties + cf.setStringProperty(WMQConstants.WMQ_HOST_NAME, manager.getHost()); + cf.setIntProperty(WMQConstants.WMQ_PORT, manager.getPort()); + cf.setStringProperty(WMQConstants.WMQ_CHANNEL, manager.getChannelName()); + cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT); + cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, manager.getName()); + cf.setStringProperty(WMQConstants.WMQ_APPLICATIONNAME, "Bad Password"); + cf.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP, true); + cf.setStringProperty(WMQConstants.USERID, manager.getUsername()); + cf.setStringProperty(WMQConstants.PASSWORD, "badpassword"); + // cf.setStringProperty(WMQConstants.WMQ_SSL_CIPHER_SUITE, "*TLS12ORHIGHER"); + // cf.setIntProperty(MQConstants.CERTIFICATE_VALIDATION_POLICY, + // MQConstants.MQ_CERT_VAL_POLICY_NONE); + + // Create Jakarta objects + context = cf.createContext(); + } catch (JMSException e) { + throw new RuntimeException(e); + } catch (JMSRuntimeException e) { + if (e.getCause() instanceof MQException) { + MQException mqe = (MQException) e.getCause(); + if (mqe.getReason() == 2035) { // bad password + return; + } + } + throw new RuntimeException(e); + } finally { + if (context != null) { + context.close(); + } + } + } +} diff --git a/ibm-mq-metrics/src/integrationTest/java/io/opentelemetry/ibm/mq/integration/tests/TestWMQMonitor.java b/ibm-mq-metrics/src/integrationTest/java/io/opentelemetry/ibm/mq/integration/tests/TestWMQMonitor.java new file mode 100644 index 000000000..8221c9353 --- /dev/null +++ b/ibm-mq-metrics/src/integrationTest/java/io/opentelemetry/ibm/mq/integration/tests/TestWMQMonitor.java @@ -0,0 +1,58 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.ibm.mq.integration.tests; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.ibm.mq.WmqMonitor; +import io.opentelemetry.ibm.mq.config.QueueManager; +import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutorService; + +/** + * The TestWMQMonitor class extends the WMQMonitor class and provides a test implementation of the + * WebSphere MQ monitoring functionality. It is intended for internal integration test purposes and + * facilitates custom configuration through a test configuration file and a test metric write + * helper. + */ +class TestWMQMonitor { + + private final ConfigWrapper config; + private final ExecutorService threadPool; + private final Meter meter; + + TestWMQMonitor(ConfigWrapper config, Meter meter, ExecutorService service) { + this.config = config; + this.threadPool = service; + this.meter = meter; + } + + /** + * Executes a test run for monitoring WebSphere MQ queue managers based on the provided + * configuration "testConfigFile". + * + *

The method retrieves "queueManagers" from the yml configuration file and uses a custom + * MetricWriteHelper if provided, initializes a TasksExecutionServiceProvider, and executes the + * WMQMonitorTask + */ + void runTest() { + List> queueManagers = config.getQueueManagers(); + assertThat(queueManagers).isNotNull(); + ObjectMapper mapper = new ObjectMapper(); + + WmqMonitor wmqTask = new WmqMonitor(config, threadPool, meter); + + // we override this helper to pass in our opentelemetry helper instead. + for (Map queueManager : queueManagers) { + QueueManager qManager = mapper.convertValue(queueManager, QueueManager.class); + wmqTask.run(qManager); + } + } +} diff --git a/ibm-mq-metrics/src/integrationTest/java/io/opentelemetry/ibm/mq/integration/tests/WMQMonitorIntegrationTest.java b/ibm-mq-metrics/src/integrationTest/java/io/opentelemetry/ibm/mq/integration/tests/WMQMonitorIntegrationTest.java new file mode 100644 index 000000000..425889214 --- /dev/null +++ b/ibm-mq-metrics/src/integrationTest/java/io/opentelemetry/ibm/mq/integration/tests/WMQMonitorIntegrationTest.java @@ -0,0 +1,281 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.ibm.mq.integration.tests; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ibm.mq.MQQueueManager; +import com.ibm.mq.constants.CMQC; +import com.ibm.mq.constants.CMQCFC; +import com.ibm.mq.headers.pcf.PCFException; +import com.ibm.mq.headers.pcf.PCFMessage; +import com.ibm.mq.headers.pcf.PCFMessageAgent; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.ibm.mq.config.QueueManager; +import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; +import io.opentelemetry.ibm.mq.opentelemetry.Main; +import io.opentelemetry.ibm.mq.util.WmqUtil; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension; +import java.io.File; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** Integration Test for WMQMonitor */ +class WMQMonitorIntegrationTest { + + private static final Logger logger = LoggerFactory.getLogger(WMQMonitorIntegrationTest.class); + + @RegisterExtension + static final OpenTelemetryExtension otelTesting = OpenTelemetryExtension.create(); + + private static final ExecutorService service = + Executors.newFixedThreadPool( + 4, /* one gets burned with our @BeforeAll message uzi, 4 is faster than 2 */ + r -> { + Thread thread = new Thread(r); + thread.setUncaughtExceptionHandler( + (t, e) -> { + logger.error("Uncaught exception", e); + fail(e.getMessage()); + }); + thread.setDaemon(true); + thread.setName("WMQMonitorIntegrationTest"); + return thread; + }); + + private static QueueManager getQueueManagerConfig() throws Exception { + String configFile = getConfigFile("conf/test-config.yml"); + ConfigWrapper wrapper = ConfigWrapper.parse(configFile); + Map queueManagerConfig = wrapper.getQueueManagers().get(0); + ObjectMapper mapper = new ObjectMapper(); + return mapper.convertValue(queueManagerConfig, QueueManager.class); + } + + @NotNull + private static String getConfigFile(String resourcePath) throws URISyntaxException { + URL resource = WMQMonitorIntegrationTest.class.getClassLoader().getResource(resourcePath); + if (resource == null) { + throw new IllegalArgumentException("file not found!"); + } + + File file = Paths.get(resource.toURI()).toFile(); + logger.info("Config file: {}", file.getAbsolutePath()); + return file.getAbsolutePath(); + } + + private static void configureQueueManager(QueueManager manager) { + MQQueueManager ibmQueueManager = WmqUtil.connectToQueueManager(manager); + PCFMessageAgent agent = WmqUtil.initPcfMessageAgent(manager, ibmQueueManager); + PCFMessage request = new PCFMessage(CMQCFC.MQCMD_CHANGE_Q_MGR); + // turn on emitting authority events + request.addParameter(CMQC.MQIA_AUTHORITY_EVENT, CMQCFC.MQEVR_ENABLED); + // turn on emitting configuration events + request.addParameter(CMQC.MQIA_CONFIGURATION_EVENT, CMQCFC.MQEVR_ENABLED); + // turn on emitting channel auto-definition events + request.addParameter(CMQC.MQIA_CHANNEL_AUTO_DEF_EVENT, CMQCFC.MQEVR_ENABLED); + // turn on emitting channel events + request.addParameter(CMQC.MQIA_CHANNEL_EVENT, CMQCFC.MQEVR_ENABLED); + // turn on emitting command events + request.addParameter(CMQC.MQIA_COMMAND_EVENT, CMQCFC.MQEVR_ENABLED); + // turn on emitting inhibit events + request.addParameter(CMQC.MQIA_INHIBIT_EVENT, CMQCFC.MQEVR_ENABLED); + // turn on emitting local events + request.addParameter(CMQC.MQIA_LOCAL_EVENT, CMQCFC.MQEVR_ENABLED); + // turn on emitting performance events + request.addParameter(CMQC.MQIA_PERFORMANCE_EVENT, CMQCFC.MQEVR_ENABLED); + // turn on emitting remote events + request.addParameter(CMQC.MQIA_REMOTE_EVENT, CMQCFC.MQEVR_ENABLED); + // turn on emitting SSL events + request.addParameter(CMQC.MQIA_SSL_EVENT, CMQCFC.MQEVR_ENABLED); + // turn on emitting start/stop events + request.addParameter(CMQC.MQIA_START_STOP_EVENT, CMQCFC.MQEVR_ENABLED); + try { + agent.send(request); + } catch (Exception e) { + if (e instanceof PCFException) { + PCFMessage[] msgs = (PCFMessage[]) ((PCFException) e).exceptionSource; + for (PCFMessage msg : msgs) { + logger.error(msg.toString()); + } + } + throw new RuntimeException(e); + } + } + + @BeforeAll + public static void sendClientMessages() throws Exception { + QueueManager qManager = getQueueManagerConfig(); + configureQueueManager(qManager); + + // create a queue and fill it up past its capacity. + JakartaPutGet.createQueue(qManager, "smallqueue", 10); + + JakartaPutGet.runPutGet(qManager, "myqueue", 10, 1); + + Future ignored = + service.submit(() -> JakartaPutGet.runPutGet(qManager, "myqueue", 1000000, 100)); + } + + @AfterAll + public static void stopSendingClientMessages() throws Exception { + QueueManager qManager = getQueueManagerConfig(); + configureQueueManager(qManager); + + service.shutdown(); + } + + @BeforeEach + void setUpEvents() throws Exception { + QueueManager qManager = getQueueManagerConfig(); + // try to login with a bad password: + JakartaPutGet.tryLoginWithBadPassword(qManager); + + JakartaPutGet.sendMessages(qManager, "smallqueue", 1); + Thread.sleep(1000); + JakartaPutGet.sendMessages(qManager, "smallqueue", 8); + Thread.sleep(1000); + JakartaPutGet.sendMessages(qManager, "smallqueue", 5); + } + + @AfterEach + void clearQueue() throws Exception { + // clear the full queue. + JakartaPutGet.readMessages(getQueueManagerConfig(), "smallqueue"); + } + + @Test + void test_monitor_with_full_config() throws Exception { + String configFile = getConfigFile("conf/test-config.yml"); + + ConfigWrapper config = ConfigWrapper.parse(configFile); + Meter meter = otelTesting.getOpenTelemetry().getMeter("opentelemetry.io/mq"); + TestWMQMonitor monitor = new TestWMQMonitor(config, meter, service); + monitor.runTest(); + + List data = otelTesting.getMetrics(); + Map metrics = new HashMap<>(); + for (MetricData metricData : data) { + metrics.put(metricData.getName(), metricData); + } + Set metricNames = metrics.keySet(); + // this value is read from the active channels count: + assertThat(metricNames).contains("mq.manager.active.channels"); + // this value is read from the configuration queue. + assertThat(metricNames).contains("mq.manager.max.handles"); + // this value is read from the queue manager events, for unauthorized events. + assertThat(metricNames).contains("mq.unauthorized.event"); + // this value is read from the performance event queue. + assertThat(metricNames).contains("mq.queue.depth.full.event"); + // this value is read from the performance event queue. + assertThat(metricNames).contains("mq.queue.depth.high.event"); + assertThat(metricNames).contains("mq.queue.depth.low.event"); + // reads a value from the heartbeat gauge + assertThat(metricNames).contains("mq.heartbeat"); + assertThat(metricNames).contains("mq.oldest.msg.age"); + if (metrics.get("mq.oldest.msg.age") != null) { + Set queueNames = + metrics.get("mq.oldest.msg.age").getLongGaugeData().getPoints().stream() + .map(pt -> pt.getAttributes().get(AttributeKey.stringKey("queue.name"))) + .collect(Collectors.toSet()); + assertThat(queueNames).contains("smallqueue"); + } + // make sure we get MQ manager status + assertThat(metricNames).contains("mq.manager.status"); + if (metrics.get("mq.manager.status") != null) { + Set queueManagers = + metrics.get("mq.manager.status").getLongGaugeData().getPoints().stream() + .map(pt -> pt.getAttributes().get(AttributeKey.stringKey("queue.manager"))) + .collect(Collectors.toSet()); + assertThat(queueManagers).contains("QM1"); + } + + assertThat(metricNames).contains("mq.onqtime.2"); + if (metrics.get("mq.onqtime.2") != null) { + Set queueNames = + metrics.get("mq.onqtime.2").getLongGaugeData().getPoints().stream() + .map(pt -> pt.getAttributes().get(AttributeKey.stringKey("queue.name"))) + .collect(Collectors.toSet()); + assertThat(queueNames).contains("smallqueue"); + Set queueManagers = + metrics.get("mq.manager.status").getLongGaugeData().getPoints().stream() + .map(pt -> pt.getAttributes().get(AttributeKey.stringKey("queue.manager"))) + .collect(Collectors.toSet()); + assertThat(queueManagers).contains("QM1"); + // TODO: Add more asserts about data values, units, attributes, etc, not just names + } + } + + @Test + void test_wmqmonitor() throws Exception { + String configFile = getConfigFile("conf/test-queuemgr-config.yml"); + ConfigWrapper config = ConfigWrapper.parse(configFile); + Meter meter = otelTesting.getOpenTelemetry().getMeter("opentelemetry.io/mq"); + + TestWMQMonitor monitor = new TestWMQMonitor(config, meter, service); + monitor.runTest(); + // TODO: Wait why are there no asserts here? + } + + @Test + void test_otlphttp() throws Exception { + ConfigWrapper config = + ConfigWrapper.parse(WMQMonitorIntegrationTest.getConfigFile("conf/test-config.yml")); + ScheduledExecutorService service = + Executors.newScheduledThreadPool(config.getNumberOfThreads()); + Main.run(config, service, otelTesting.getOpenTelemetry()); + CountDownLatch latch = new CountDownLatch(1); + Future ignored = service.submit(latch::countDown); + Thread.sleep(5000); // TODO: This is fragile and time consuming and should be made better + service.shutdown(); + assertTrue(service.awaitTermination(30, TimeUnit.SECONDS)); + + List data = otelTesting.getMetrics(); + Set metricNames = new HashSet<>(); + for (MetricData metricData : data) { + metricNames.add(metricData.getName()); + } + // this value is read from the active channels count: + assertThat(metricNames).contains("mq.manager.active.channels"); + // this value is read from the configuration queue. + assertThat(metricNames).contains("mq.manager.max.handles"); + // this value is read from the queue manager events, for unauthorized events. + assertThat(metricNames).contains("mq.unauthorized.event"); + // this value is read from the performance event queue. + assertThat(metricNames).contains("mq.queue.depth.full.event"); + // this value is read from the performance event queue. + assertThat(metricNames).contains("mq.queue.depth.high.event"); + assertThat(metricNames).contains("mq.queue.depth.low.event"); + // reads a value from the heartbeat gauge + assertThat(metricNames).contains("mq.heartbeat"); + } +} From 0f99f3f6c20d1bd1a98ed988977bf11f344fb211 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 13 Jun 2025 14:41:05 -0700 Subject: [PATCH 09/66] fix integration test --- ibm-mq-metrics/build.gradle.kts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ibm-mq-metrics/build.gradle.kts b/ibm-mq-metrics/build.gradle.kts index 8be9fed0e..fcf53407e 100644 --- a/ibm-mq-metrics/build.gradle.kts +++ b/ibm-mq-metrics/build.gradle.kts @@ -46,6 +46,8 @@ dependencies { integrationTestImplementation("io.opentelemetry:opentelemetry-sdk-testing:1.50.0") integrationTestImplementation("com.ibm.mq:com.ibm.mq.jakarta.client:9.4.2.0") integrationTestImplementation("jakarta.jms:jakarta.jms-api:3.1.0") + integrationTestImplementation("org.junit.jupiter:junit-jupiter-engine:5.12.2") + integrationTestRuntimeOnly("org.junit.platform:junit-platform-launcher:1.13.0") ibmClientJar("com.ibm.mq:com.ibm.mq.allclient:9.4.2.1") { artifact { name = "com.ibm.mq.allclient" From 48a25aaa120a74f5678c5598845ce6b7989bb0c5 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 13 Jun 2025 14:45:02 -0700 Subject: [PATCH 10/66] add component owners --- .github/component_owners.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/component_owners.yml b/.github/component_owners.yml index 39388bf7f..841bb6381 100644 --- a/.github/component_owners.yml +++ b/.github/component_owners.yml @@ -90,3 +90,6 @@ components: opamp-client: - LikeTheSalad - jackshirazi + ibm-mq-metrics: + - breedx-splk + - atoulme From d631ee89d4bf2ed8bc0acac4aec00dcbad217c8d Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 13 Jun 2025 14:45:08 -0700 Subject: [PATCH 11/66] add makefile --- ibm-mq-metrics/Makefile | 84 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 ibm-mq-metrics/Makefile diff --git a/ibm-mq-metrics/Makefile b/ibm-mq-metrics/Makefile new file mode 100644 index 000000000..e55fb2e47 --- /dev/null +++ b/ibm-mq-metrics/Makefile @@ -0,0 +1,84 @@ +# From where to resolve the containers (e.g. "otel/weaver"). +WEAVER_CONTAINER_REPOSITORY=docker.io +# Versioned, non-qualified references to containers used in this Makefile. +# These are parsed from dependencies.Dockerfile so dependabot will autoupdate +# the versions of docker files we use. +VERSIONED_WEAVER_CONTAINER_NO_REPO=$(shell cat buildscripts/dependencies.Dockerfile | awk '$$4=="weaver" {print $$2}') +# Versioned, non-qualified references to containers used in this Makefile. +WEAVER_CONTAINER=$(WEAVER_CONTAINER_REPOSITORY)/$(VERSIONED_WEAVER_CONTAINER_NO_REPO) + +# Next - we want to run docker as our local file user, so generated code is not +# owned by root, and we don't give unnecessary access. +# +# Determine if "docker" is actually podman +DOCKER_VERSION_OUTPUT := $(shell docker --version 2>&1) +DOCKER_IS_PODMAN := $(shell echo $(DOCKER_VERSION_OUTPUT) | grep -c podman) +ifeq ($(DOCKER_IS_PODMAN),0) + DOCKER_COMMAND := docker +else + DOCKER_COMMAND := podman +endif +DOCKER_RUN=$(DOCKER_COMMAND) run +DOCKER_USER=$(shell id -u):$(shell id -g) +DOCKER_USER_IS_HOST_USER_ARG=-u $(DOCKER_USER) +ifeq ($(DOCKER_COMMAND),podman) + # On podman, additional arguments are needed to make "-u" work + # correctly with the host user ID and host group ID. + # + # Error: OCI runtime error: crun: setgroups: Invalid argument + DOCKER_USER_IS_HOST_USER_ARG=--userns=keep-id -u $(DOCKER_USER) +endif + +.PHONY: generate-docs +generate-docs: + mkdir -p docs + $(DOCKER_RUN) --rm \ + $(DOCKER_USER_IS_HOST_USER_ARG) \ + --mount 'type=bind,source=$(PWD)/model,target=/home/weaver/model,readonly' \ + --mount 'type=bind,source=$(PWD)/templates,target=/home/weaver/templates,readonly' \ + --mount 'type=bind,source=$(PWD)/docs,target=/home/weaver/target' \ + ${WEAVER_CONTAINER} registry generate \ + --registry=/home/weaver/model \ + markdown \ + --future \ + /home/weaver/target + +.PHONY: check +check: + $(DOCKER_RUN) --rm \ + $(DOCKER_USER_IS_HOST_USER_ARG) \ + --mount 'type=bind,source=$(PWD)/model,target=/home/weaver/model,readonly' \ + --mount 'type=bind,source=$(PWD)/templates,target=/home/weaver/templates,readonly' \ + --mount 'type=bind,source=$(PWD)/docs,target=/home/weaver/target' \ + ${WEAVER_CONTAINER} registry check \ + --registry=/home/weaver/model + +.PHONY: generate-java +generate-java: + mkdir -p src/main/java/com/splunk/ibm/mq/metrics + $(DOCKER_RUN) --rm \ + $(DOCKER_USER_IS_HOST_USER_ARG) \ + --mount 'type=bind,source=$(PWD)/model,target=/home/weaver/model,readonly' \ + --mount 'type=bind,source=$(PWD)/templates,target=/home/weaver/templates,readonly' \ + --mount 'type=bind,source=$(PWD)/src/main/java/com/splunk/ibm/mq/metrics,target=/home/weaver/target' \ + ${WEAVER_CONTAINER} registry generate \ + --registry=/home/weaver/model \ + java \ + --future \ + /home/weaver/target + +.PHONY: generate-yaml +generate-yaml: + $(DOCKER_RUN) --rm \ + $(DOCKER_USER_IS_HOST_USER_ARG) \ + --mount 'type=bind,source=$(PWD)/model,target=/home/weaver/model,readonly' \ + --mount 'type=bind,source=$(PWD)/templates,target=/home/weaver/templates,readonly' \ + --mount 'type=bind,source=$(PWD)/,target=/home/weaver/target' \ + ${WEAVER_CONTAINER} registry generate \ + --registry=/home/weaver/model \ + yaml \ + --future \ + /home/weaver/target + +.PHONY: generate +generate: generate-docs generate-yaml generate-java From 17d0bd30bc0694c69b9afb525ab8794941c4085c Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 13 Jun 2025 15:40:59 -0700 Subject: [PATCH 12/66] add weaver stuff --- ibm-mq-metrics/Makefile | 6 +- ibm-mq-metrics/README.md | 202 +++++ ibm-mq-metrics/docs/metrics.md | 757 ++++++++++++++++++ ibm-mq-metrics/model/attributes.yaml | 71 ++ ibm-mq-metrics/model/metrics.yaml | 611 ++++++++++++++ ibm-mq-metrics/model/registry_manifest.yaml | 3 + .../mq/integration/tests/JakartaPutGet.java | 3 +- .../opentelemetry/ibm/mq/metrics/Metrics.java | 322 ++------ .../ibm/mq/metrics/MetricsConfig.java | 11 +- ibm-mq-metrics/src/main/resources/log4j2.xml | 4 +- ibm-mq-metrics/src/test/resources/log4j.xml | 18 +- .../templates/registry/java/Metrics.java.j2 | 25 +- .../registry/java/MetricsConfig.java.j2 | 37 +- .../registry/markdown/attribute_macros.j2 | 36 + .../markdown/attribute_namespace.md.j2 | 51 ++ .../registry/markdown/attribute_table.j2 | 13 + .../registry/markdown/body_field_table.j2 | 18 + .../registry/markdown/enum_macros.j2 | 30 + .../registry/markdown/event_macros.j2 | 16 + .../registry/markdown/examples_macros.j2 | 17 + .../registry/markdown/metric_macros.j2 | 8 + .../registry/markdown/metric_table.j2 | 7 + .../templates/registry/markdown/metrics.md.j2 | 14 + .../templates/registry/markdown/notes.j2 | 9 + .../templates/registry/markdown/readme.md.j2 | 42 + .../registry/markdown/requirement.j2 | 9 + .../registry/markdown/resource_macros.j2 | 16 + .../registry/markdown/sampling_macros.j2 | 7 + .../templates/registry/markdown/snippet.md.j2 | 32 + .../templates/registry/markdown/stability.j2 | 11 + .../templates/registry/markdown/weaver.yaml | 4 + ibm-mq-metrics/weaver.Dockerfile | 6 + 32 files changed, 2069 insertions(+), 347 deletions(-) create mode 100644 ibm-mq-metrics/README.md create mode 100644 ibm-mq-metrics/docs/metrics.md create mode 100644 ibm-mq-metrics/model/attributes.yaml create mode 100644 ibm-mq-metrics/model/metrics.yaml create mode 100644 ibm-mq-metrics/model/registry_manifest.yaml create mode 100644 ibm-mq-metrics/templates/registry/markdown/attribute_macros.j2 create mode 100644 ibm-mq-metrics/templates/registry/markdown/attribute_namespace.md.j2 create mode 100644 ibm-mq-metrics/templates/registry/markdown/attribute_table.j2 create mode 100644 ibm-mq-metrics/templates/registry/markdown/body_field_table.j2 create mode 100644 ibm-mq-metrics/templates/registry/markdown/enum_macros.j2 create mode 100644 ibm-mq-metrics/templates/registry/markdown/event_macros.j2 create mode 100644 ibm-mq-metrics/templates/registry/markdown/examples_macros.j2 create mode 100644 ibm-mq-metrics/templates/registry/markdown/metric_macros.j2 create mode 100644 ibm-mq-metrics/templates/registry/markdown/metric_table.j2 create mode 100644 ibm-mq-metrics/templates/registry/markdown/metrics.md.j2 create mode 100644 ibm-mq-metrics/templates/registry/markdown/notes.j2 create mode 100644 ibm-mq-metrics/templates/registry/markdown/readme.md.j2 create mode 100644 ibm-mq-metrics/templates/registry/markdown/requirement.j2 create mode 100644 ibm-mq-metrics/templates/registry/markdown/resource_macros.j2 create mode 100644 ibm-mq-metrics/templates/registry/markdown/sampling_macros.j2 create mode 100644 ibm-mq-metrics/templates/registry/markdown/snippet.md.j2 create mode 100644 ibm-mq-metrics/templates/registry/markdown/stability.j2 create mode 100644 ibm-mq-metrics/templates/registry/markdown/weaver.yaml create mode 100644 ibm-mq-metrics/weaver.Dockerfile diff --git a/ibm-mq-metrics/Makefile b/ibm-mq-metrics/Makefile index e55fb2e47..d6ad8e42a 100644 --- a/ibm-mq-metrics/Makefile +++ b/ibm-mq-metrics/Makefile @@ -3,7 +3,7 @@ WEAVER_CONTAINER_REPOSITORY=docker.io # Versioned, non-qualified references to containers used in this Makefile. # These are parsed from dependencies.Dockerfile so dependabot will autoupdate # the versions of docker files we use. -VERSIONED_WEAVER_CONTAINER_NO_REPO=$(shell cat buildscripts/dependencies.Dockerfile | awk '$$4=="weaver" {print $$2}') +VERSIONED_WEAVER_CONTAINER_NO_REPO=$(shell cat weaver.Dockerfile | awk '$$4=="weaver" {print $$2}') # Versioned, non-qualified references to containers used in this Makefile. WEAVER_CONTAINER=$(WEAVER_CONTAINER_REPOSITORY)/$(VERSIONED_WEAVER_CONTAINER_NO_REPO) @@ -55,12 +55,12 @@ check: .PHONY: generate-java generate-java: - mkdir -p src/main/java/com/splunk/ibm/mq/metrics + mkdir -p src/main/java/io/opentelemetry/ibm/mq/metrics $(DOCKER_RUN) --rm \ $(DOCKER_USER_IS_HOST_USER_ARG) \ --mount 'type=bind,source=$(PWD)/model,target=/home/weaver/model,readonly' \ --mount 'type=bind,source=$(PWD)/templates,target=/home/weaver/templates,readonly' \ - --mount 'type=bind,source=$(PWD)/src/main/java/com/splunk/ibm/mq/metrics,target=/home/weaver/target' \ + --mount 'type=bind,source=$(PWD)/src/main/java/io/opentelemetry/ibm/mq/metrics,target=/home/weaver/target' \ ${WEAVER_CONTAINER} registry generate \ --registry=/home/weaver/model \ java \ diff --git a/ibm-mq-metrics/README.md b/ibm-mq-metrics/README.md new file mode 100644 index 000000000..8a3c121b3 --- /dev/null +++ b/ibm-mq-metrics/README.md @@ -0,0 +1,202 @@ +# IBM MQ Metrics + +:warning: This software is under development. + +## Use case + +IBM MQ, formerly known as WebSphere MQ (message queue) series, is an IBM software for +program-to-program messaging across multiple platforms. + +The IBM MQ metrics utility here can monitor multiple queues managers and their resources, +namely queues, topics, channels and listeners The metrics are extracted out using the +[PCF command messages](https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_8.0.0/com.ibm.mq.adm.doc/q020010_.htm). + +The metrics for queue manager, queue, topic, channel and listener can be configured. + +The MQ Monitor is compatible with IBM MQ version 7.x, 8.x and 9.x. + +## Prerequisites + +### Build + +This software requires compilation with Java 11. +It targets language level 8 and outputs java 8 class files. + +The extension has a dependency on the following jar's depending on IBM MQ version: + +* v8.0.0 and above +``` +com.ibm.mq.allclient.jar +``` +* For other versions +``` +com.ibm.mq.commonservices.jar +com.ibm.mq.jar +com.ibm.mq.jmqi.jar +com.ibm.mq.headers.jar +com.ibm.mq.pcf.jar +dhbcore.jar +connector.jar +``` + +These jar files are typically found in ```/opt/mqm/java/lib``` on a UNIX server but may be +found in an alternate location depending upon your environment. + +In case of **CLIENT** transport type, IBM MQ Client must be installed to get the MQ jars. +To download IBM MQ Client jars, see [here](https://developer.ibm.com/messaging/mq-downloads/) + +### MQ monitoring configuration + +This software reads events from event queues associated with the queue manager: +* `SYSTEM.ADMIN.PERFM.EVENT`: Performance events, such as low, high, and full queue depth events. +* `SYSTEM.ADMIN.QMGR.EVENT`: Authority events +* `SYSTEM.ADMIN.CONFIG.EVENT`: Configuration events + +Please turn on those events to take advantage of this monitoring. + +## Build + +Build the package with: +```shell +./gradlew shadowJar +``` + +Note: Due to restrictive licensing, this uber-jar (fat-jar) does not include the IBM client jar f + +## Run + +Run the standalone jar alongside the IBM jar: + +```shell +java \ + -Djavax.net.ssl.keyStore=key.jks \ + -Djavax.net.ssl.keyStorePassword= \ + -Djavax.net.ssl.trustStore=key.jks \ + -Djavax.net.ssl.trustStorePassword= \ + -cp target/ibm-mq-monitoring--all.jar:lib/com.ibm.mq.allclient.jar \ + io.opentelemetry.ibm.mq.opentelemetry.Main \ + ./my-config.yml +``` + +## Connection + +There are two transport modes in which this extension can be run: +* **Binding** : Requires WMQ Extension to be deployed in machine agent on the same machine where + WMQ server is installed. +* **Client** : In this mode, the WMQ extension is installed on a different host than the IBM MQ + server. Please install the [IBM MQ Client](https://developer.ibm.com/messaging/mq-downloads/) + for this mode to get the necessary jars as mentioned previously. + +If this extension is configured for **CLIENT** transport type +1. Please make sure the MQ's host and port is accessible. +2. Credentials of user with correct access rights would be needed in config.yml + [(Access Permissions section)](https://github.com/signalfx/opentelemetry-ibm-mq-monitoring-extension#access-permissions). +3. If the hosting OS for IBM MQ is Windows, Windows user credentials will be needed. + +If you are in **Bindings** mode, please make sure to start the MA process under a user which has +the following permissions on the broker. Similarly, for **Client** mode, please provide the user +credentials in config.yml which have permissions listed below. + +The user connecting to the queueManager should have the inquire, get, put (since PCF responses +cause dynamic queues to be created) permissions. For metrics that execute MQCMD_RESET_Q_STATS +command, chg permission is needed. + +### SSL Support + +1. Configure the IBM SSL Cipher Suite in the config.yml. + Note that, to use some CipherSuites the unrestricted policy needs to be configured in JRE. + Please visit [this link](http://www.ibm.com/support/knowledgecenter/SSYKE2_8.0.0/com.ibm.java.security.component.80.doc/security-component/sdkpolicyfiles.html) + for more details. For Oracle JRE, please update with [JCE Unlimited Strength Jurisdiction Policy](http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html). + The download includes a readme file with instructions on how to apply these files to JRE + +2. Please add the following JVM arguments to the MA start up command or script. + + ```-Dcom.ibm.mq.cfg.useIBMCipherMappings=false``` (If you are using IBM Cipher Suites, set the + flag to true. Please visit [this link](http://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.dev.doc/q113210_.htm) for more details. + ) +3. To configure SSL, the MA's trust store and keystore needs to be setup with the JKS filepath. + They can be passed either as Machine Agent JVM arguments or configured in config.yml (sslConnection)
+ + a. Machine Agent JVM arguments as follows: + + ```-Djavax.net.ssl.trustStore=```
+ ```-Djavax.net.ssl.trustStorePassword=```
+ ```-Djavax.net.ssl.keyStore=```
+ ```-Djavax.net.ssl.keyStorePassword=```
+ + b. sslConnection in config.yml, configure the trustStorePassword. Same holds for keyStore configuration as well. + + ``` + sslConnection: + trustStorePath: "" + trustStorePassword: "" + + keyStorePath: "" + keyStorePassword: "" + ``` + +## Configuration + +**Note** : Please make sure to not use tab (\t) while editing yaml files. You may want to validate +the yaml file using a [yaml validator](https://jsonformatter.org/yaml-validator). Configure the monitor by copying and editing the +config.yml file in src/main/resources/config.yml. + +1. Configure the queueManagers with appropriate fields and filters. You can configure multiple + queue managers in one configuration file. +2. To run the extension at a frequency > 1 minute, please configure the taskSchedule section. + Refer to the [Task Schedule](https://community.appdynamics.com/t5/Knowledge-Base/Task-Schedule-for-Extensions/ta-p/35414) doc for details. + +### Monitoring Workings - Internals + +This software extracts metrics through [PCF framework](https://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.adm.doc/q019990_.htm). A complete list of PCF commands are +listed [here](https://www.ibm.com/support/knowledgecenter/SSFKSJ_7.5.0/com.ibm.mq.ref.adm.doc/q086870_.htm). Each queue manager has an administration queue with a standard queue name and +the extension sends PCF command messages to that queue. On Windows and Unix platforms, the PCF +commands are sent is always sent to the SYSTEM.ADMIN.COMMAND.QUEUE queue. More details about that +is mentioned [here](https://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.adm.doc/q020010_.htm) + +By default, the PCF responses are sent to the SYSTEM.DEFAULT.MODEL.QUEUE. Using this queue causes +a temporary dynamic queue to be created. You can override the default here by using the +`modelQueueName` and `replyQueuePrefix` fields in the config.yml. +More details mentioned [here](https://www.ibm.com/support/knowledgecenter/SSFKSJ_7.5.0/com.ibm.mq.ref.adm.doc/q083240_.htm) + +## Metrics + +See [docs/metrics.md](docs/metrics.md). + +## Troubleshooting +1. Please follow the steps listed in this [troubleshooting-document](https://community.appdynamics.com/t5/Knowledge-Base/How-to-troubleshoot-missing-custom-metrics-or-extensions-metrics/ta-p/28695) in order to troubleshoot your issue. These are a set of common issues that customers might have faced during the installation of the extension. +2. Error `Completion Code '2', Reason '2495'` + Normally this error occurs if the environment variables are not set up correctly for this extension to work MQ in Bindings Mode. + + If you are seeing `Failed to load the WebSphere MQ native JNI library: 'mqjbnd'`, please add the following jvm argument when starting the MA. + + -Djava.library.path=\ For eg. on Unix it could -Djava.library.path=/opt/mqm/java/lib64 for 64-bit or -Djava.library.path=/opt/mqm/java/lib for 32-bit OS + + Sometimes you also have run the setmqenv script before using the above jvm argument to start the machine agent. + + . /opt/mqm/bin/setmqenv -s + + For more details, please check this [doc](https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.1.0/com.ibm.mq.doc/zr00610_.htm) + + This might occour due to various reasons ranging from incorrect installation to applying [ibm fix packs](http://www-01.ibm.com/support/docview.wss?uid=swg21410038) but most of the time it happens when you are trying to connect in `Bindings` mode and machine agent is not on the same machine on which WMQ server is running. If you want to connect to WMQ server from a remote machine then connect using `Client` mode. + + Another way to get around this issue is to avoid using the Bindings mode. Connect using CLIENT transport type from a remote box. + +3. Error `Completion Code '2', Reason '2035'` + This could happen for various reasons but for most of the cases, for **Client** mode the user specified in config.yml is not authorized to access the queue manager. Also sometimes even if userid and password are correct, channel auth (CHLAUTH) for that queue manager blocks traffics from other ips, you need to contact admin to provide you access to the queue manager. + For Bindings mode, please make sure that the MA is owned by a mqm user. Please check [this doc](https://www-01.ibm.com/support/docview.wss?uid=swg21636093) + +4. `MQJE001: Completion Code '2', Reason '2195'` + This could happen in **Client** mode. Please make sure that the IBM MQ dependency jars are correctly referenced in classpath of monitor.xml + +5. `MQJE001: Completion Code '2', Reason '2400'` + This could happen if unsupported cipherSuite is provided or JRE not having/enabled unlimited jurisdiction policy files. Please check SSL Support section. + +6. If you are seeing "NoClassDefFoundError" or "ClassNotFound" error for any of the MQ dependency even after providing correct path in monitor.xml, then you can also try copying all the required jars in WMQMonitor (MAHome/monitors/WMQMonitor) folder and provide classpath in monitor.xml like below + ``` + ibm-mq-monitoring--all.jar;com.ibm.mq.allclient.jar + ``` + OR + ``` + ibm-mq-monitoring--all.jar;com.ibm.mq.jar;com.ibm.mq.jmqi.jar;com.ibm.mq.commonservices.jar;com.ibm.mq.headers.jar;com.ibm.mq.pcf.jar;connector.jar;dhbcore.jar + ``` diff --git a/ibm-mq-metrics/docs/metrics.md b/ibm-mq-metrics/docs/metrics.md new file mode 100644 index 000000000..47189da11 --- /dev/null +++ b/ibm-mq-metrics/docs/metrics.md @@ -0,0 +1,757 @@ +# Produced Metrics + + +## Metric `mq.message.retry.count` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.message.retry.count` | Gauge | `{messages}` | Number of message retries | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.message.retry.count` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.status` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.status` | Gauge | `1` | Channel status | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.status` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `channel.start.time` | int | The start time of the channel as seconds since Epoch. | `1748462702` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `job.name` | string | The job name | `0000074900000003` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.max.sharing.conversations` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.max.sharing.conversations` | Gauge | `{conversations}` | Maximum number of conversations permitted on this channel instance. | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.max.sharing.conversations` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `channel.start.time` | int | The start time of the channel as seconds since Epoch. | `1748462702` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `job.name` | string | The job name | `0000074900000003` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.current.sharing.conversations` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.current.sharing.conversations` | Gauge | `{conversations}` | Current number of conversations permitted on this channel instance. | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.current.sharing.conversations` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `channel.start.time` | int | The start time of the channel as seconds since Epoch. | `1748462702` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `job.name` | string | The job name | `0000074900000003` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.byte.received` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.byte.received` | Gauge | `{bytes}` | Number of bytes received | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.byte.received` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `channel.start.time` | int | The start time of the channel as seconds since Epoch. | `1748462702` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `job.name` | string | The job name | `0000074900000003` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.byte.sent` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.byte.sent` | Gauge | `{bytes}` | Number of bytes sent | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.byte.sent` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `channel.start.time` | int | The start time of the channel as seconds since Epoch. | `1748462702` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `job.name` | string | The job name | `0000074900000003` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.buffers.received` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.buffers.received` | Gauge | `{buffers}` | Buffers received | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.buffers.received` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `channel.start.time` | int | The start time of the channel as seconds since Epoch. | `1748462702` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `job.name` | string | The job name | `0000074900000003` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.buffers.sent` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.buffers.sent` | Gauge | `{buffers}` | Buffers sent | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.buffers.sent` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `channel.start.time` | int | The start time of the channel as seconds since Epoch. | `1748462702` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `job.name` | string | The job name | `0000074900000003` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.message.count` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.message.count` | Gauge | `{messages}` | Message count | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.message.count` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `channel.start.time` | int | The start time of the channel as seconds since Epoch. | `1748462702` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `job.name` | string | The job name | `0000074900000003` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.open.input.count` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.open.input.count` | Gauge | `{applications}` | Count of applications sending messages to the queue | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.open.input.count` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.open.output.count` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.open.output.count` | Gauge | `{applications}` | Count of applications consuming messages from the queue | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.open.output.count` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.high.queue.depth` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.high.queue.depth` | Gauge | `{percent}` | The current high queue depth | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.high.queue.depth` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.service.interval` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.service.interval` | Gauge | `{percent}` | The queue service interval | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.service.interval` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.queue.depth.full.event` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.queue.depth.full.event` | Counter | `{events}` | The number of full queue events | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.queue.depth.full.event` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.queue.depth.high.event` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.queue.depth.high.event` | Counter | `{events}` | The number of high queue events | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.queue.depth.high.event` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.queue.depth.low.event` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.queue.depth.low.event` | Counter | `{events}` | The number of low queue events | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.queue.depth.low.event` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.uncommitted.messages` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.uncommitted.messages` | Gauge | `{messages}` | Number of uncommitted messages | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.uncommitted.messages` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.oldest.msg.age` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.oldest.msg.age` | Gauge | `microseconds` | Queue message oldest age | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.oldest.msg.age` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.current.max.queue.filesize` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.current.max.queue.filesize` | Gauge | `mib` | Current maximum queue file size | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.current.max.queue.filesize` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.current.queue.filesize` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.current.queue.filesize` | Gauge | `mib` | Current queue file size | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.current.queue.filesize` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.instances.per.client` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.instances.per.client` | Gauge | `{instances}` | Instances per client | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.instances.per.client` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.message.deq.count` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.message.deq.count` | Gauge | `{messages}` | Message dequeue count | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.message.deq.count` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.message.enq.count` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.message.enq.count` | Gauge | `{messages}` | Message enqueue count | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.message.enq.count` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.queue.depth` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.queue.depth` | Gauge | `{messages}` | Current queue depth | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.queue.depth` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.service.interval.event` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.service.interval.event` | Gauge | `1` | Queue service interval event | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.service.interval.event` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.reusable.log.size` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.reusable.log.size` | Gauge | `mib` | The amount of space occupied, in megabytes, by log extents available to be reused. | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.reusable.log.size` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.manager.active.channels` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.manager.active.channels` | Gauge | `{channels}` | The queue manager active maximum channels limit | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.manager.active.channels` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.restart.log.size` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.restart.log.size` | Gauge | `mib` | Size of the log data required for restart recovery in megabytes. | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.restart.log.size` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.max.queue.depth` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.max.queue.depth` | Gauge | `{messages}` | Maximum queue depth | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.max.queue.depth` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.onqtime.1` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.onqtime.1` | Gauge | `microseconds` | Amount of time, in microseconds, that a message spent on the queue, over a short period | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.onqtime.1` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.onqtime.2` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.onqtime.2` | Gauge | `microseconds` | Amount of time, in microseconds, that a message spent on the queue, over a longer period | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.onqtime.2` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.message.received.count` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.message.received.count` | Gauge | `{messages}` | Number of messages received | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.message.received.count` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.message.sent.count` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.message.sent.count` | Gauge | `{messages}` | Number of messages sent | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.message.sent.count` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.max.instances` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.max.instances` | Gauge | `{instances}` | Max channel instances | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.max.instances` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.connection.count` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.connection.count` | Gauge | `{connections}` | Active connections count | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.connection.count` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.manager.status` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.manager.status` | Gauge | `1` | Queue manager status | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.manager.status` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.heartbeat` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.heartbeat` | Gauge | `1` | Queue manager heartbeat | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.heartbeat` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.archive.log.size` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.archive.log.size` | Gauge | `mib` | Queue manager archive log size | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.archive.log.size` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.manager.max.active.channels` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.manager.max.active.channels` | Gauge | `{channels}` | Queue manager max active channels | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.manager.max.active.channels` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.manager.statistics.interval` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.manager.statistics.interval` | Gauge | `1` | Queue manager statistics interval | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.manager.statistics.interval` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.publish.count` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.publish.count` | Gauge | `{publications}` | Topic publication count | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.publish.count` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `topic.name` | string | The name of the topic | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.subscription.count` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.subscription.count` | Gauge | `{subscriptions}` | Topic subscription count | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.subscription.count` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `topic.name` | string | The name of the topic | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.listener.status` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.listener.status` | Gauge | `1` | Listener status | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.listener.status` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `listener.name` | string | The listener name | `listener` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.unauthorized.event` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.unauthorized.event` | Counter | `{events}` | Number of authentication error events | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.unauthorized.event` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `application.name` | string | The application name | `Wordle`; `JMSService` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `user.name` | string | The user name | `foo`; `root` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `mq.manager.max.handles` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `mq.manager.max.handles` | Gauge | `{events}` | Max open handles | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `mq.manager.max.handles` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + diff --git a/ibm-mq-metrics/model/attributes.yaml b/ibm-mq-metrics/model/attributes.yaml new file mode 100644 index 000000000..5d337099a --- /dev/null +++ b/ibm-mq-metrics/model/attributes.yaml @@ -0,0 +1,71 @@ +groups: + - id: shared.attributes + type: attribute_group + brief: Attributes of metrics. + attributes: + - id: queue.manager + type: string + brief: > + The name of the queue manager + stability: development + examples: ["MQ1"] + - id: topic.name + type: string + brief: > + The name of the topic + stability: development + examples: [ "dev/" ] + - id: channel.name + type: string + brief: > + The name of the channel + stability: development + examples: [ "DEV.ADMIN.SVRCONN" ] + - id: channel.type + type: string + brief: > + The type of the channel + stability: development + examples: [ "server-connection", "cluster-receiver", "amqp" ] + - id: job.name + type: string + brief: > + The job name + stability: development + examples: [ "0000074900000003" ] + - id: channel.start.time + type: int + brief: > + The start time of the channel as seconds since Epoch. + stability: development + examples: [ 1748462702 ] + - id: queue.name + type: string + brief: > + The queue name + stability: development + examples: [ "DEV.DEAD.LETTER.QUEUE" ] + - id: queue.type + type: string + brief: > + The queue type + stability: development + examples: [ "local-normal" ] + - id: listener.name + type: string + brief: > + The listener name + stability: development + examples: [ "listener" ] + - id: user.name + type: string + brief: > + The user name + stability: development + examples: [ "foo", "root" ] + - id: application.name + type: string + brief: > + The application name + stability: development + examples: [ "Wordle", "JMSService" ] \ No newline at end of file diff --git a/ibm-mq-metrics/model/metrics.yaml b/ibm-mq-metrics/model/metrics.yaml new file mode 100644 index 000000000..2cf42d3e3 --- /dev/null +++ b/ibm-mq-metrics/model/metrics.yaml @@ -0,0 +1,611 @@ +groups: + - id: mq.message.retry.count + type: metric + metric_name: mq.message.retry.count + stability: development + brief: "Number of message retries" + instrument: gauge + unit: "{messages}" + attributes: + - ref: channel.name + requirement_level: required + - ref: channel.type + requirement_level: required + - ref: queue.manager + requirement_level: required + - id: mq.status + type: metric + metric_name: mq.status + stability: development + brief: "Channel status" + instrument: gauge + unit: "1" + attributes: + - ref: channel.name + requirement_level: required + - ref: channel.type + requirement_level: required + - ref: queue.manager + requirement_level: required + - ref: job.name + requirement_level: required + - ref: channel.start.time + requirement_level: required + - id: mq.max.sharing.conversations + type: metric + metric_name: mq.max.sharing.conversations + stability: development + brief: "Maximum number of conversations permitted on this channel instance." + instrument: gauge + unit: "{conversations}" + attributes: + - ref: channel.name + requirement_level: required + - ref: channel.type + requirement_level: required + - ref: queue.manager + requirement_level: required + - ref: job.name + requirement_level: required + - ref: channel.start.time + requirement_level: required + - id: mq.current.sharing.conversations + type: metric + metric_name: mq.current.sharing.conversations + stability: development + unit: "{conversations}" + brief: "Current number of conversations permitted on this channel instance." + instrument: gauge + attributes: + - ref: channel.name + requirement_level: required + - ref: channel.type + requirement_level: required + - ref: queue.manager + requirement_level: required + - ref: job.name + requirement_level: required + - ref: channel.start.time + requirement_level: required + - id: mq.byte.received + type: metric + metric_name: mq.byte.received + stability: development + brief: "Number of bytes received" + instrument: gauge + unit: "{bytes}" + attributes: + - ref: channel.name + requirement_level: required + - ref: channel.type + requirement_level: required + - ref: queue.manager + requirement_level: required + - ref: job.name + requirement_level: required + - ref: channel.start.time + requirement_level: required + - id: mq.byte.sent + type: metric + metric_name: mq.byte.sent + stability: development + brief: "Number of bytes sent" + instrument: gauge + unit: "{bytes}" + attributes: + - ref: channel.name + requirement_level: required + - ref: channel.type + requirement_level: required + - ref: queue.manager + requirement_level: required + - ref: job.name + requirement_level: required + - ref: channel.start.time + requirement_level: required + - id: mq.buffers.received + type: metric + metric_name: mq.buffers.received + stability: development + brief: "Buffers received" + instrument: gauge + unit: "{buffers}" + attributes: + - ref: channel.name + requirement_level: required + - ref: channel.type + requirement_level: required + - ref: queue.manager + requirement_level: required + - ref: job.name + requirement_level: required + - ref: channel.start.time + requirement_level: required + - id: mq.buffers.sent + type: metric + metric_name: mq.buffers.sent + stability: development + brief: "Buffers sent" + unit: "{buffers}" + instrument: gauge + attributes: + - ref: channel.name + requirement_level: required + - ref: channel.type + requirement_level: required + - ref: queue.manager + requirement_level: required + - ref: job.name + requirement_level: required + - ref: channel.start.time + requirement_level: required + - id: mq.message.count + type: metric + metric_name: mq.message.count + stability: development + brief: "Message count" + unit: "{messages}" + instrument: gauge + attributes: + - ref: channel.name + requirement_level: required + - ref: channel.type + requirement_level: required + - ref: queue.manager + requirement_level: required + - ref: job.name + requirement_level: required + - ref: channel.start.time + requirement_level: required + - id: mq.open.input.count + type: metric + metric_name: mq.open.input.count + stability: development + brief: "Count of applications sending messages to the queue" + instrument: gauge + unit: "{applications}" + attributes: + - ref: queue.manager + requirement_level: required + - ref: queue.name + requirement_level: required + - ref: queue.type + requirement_level: required + - id: mq.open.output.count + type: metric + metric_name: mq.open.output.count + stability: development + brief: "Count of applications consuming messages from the queue" + instrument: gauge + unit: "{applications}" + attributes: + - ref: queue.manager + requirement_level: required + - ref: queue.name + requirement_level: required + - ref: queue.type + requirement_level: required + - id: mq.high.queue.depth + type: metric + metric_name: mq.high.queue.depth + stability: development + brief: "The current high queue depth" + instrument: gauge + unit: "{percent}" + attributes: + - ref: queue.manager + requirement_level: required + - ref: queue.name + requirement_level: required + - ref: queue.type + requirement_level: required + - id: mq.service.interval + type: metric + metric_name: mq.service.interval + stability: development + brief: "The queue service interval" + instrument: gauge + unit: "{percent}" + attributes: + - ref: queue.manager + requirement_level: required + - ref: queue.name + requirement_level: required + - ref: queue.type + requirement_level: required + - id: "mq.queue.depth.full.event" + type: metric + metric_name: "mq.queue.depth.full.event" + stability: development + brief: "The number of full queue events" + instrument: counter + unit: "{events}" + attributes: + - ref: queue.manager + requirement_level: required + - ref: queue.name + requirement_level: required + - id: "mq.queue.depth.high.event" + type: metric + metric_name: "mq.queue.depth.high.event" + stability: development + brief: "The number of high queue events" + instrument: counter + unit: "{events}" + attributes: + - ref: queue.manager + requirement_level: required + - ref: queue.name + requirement_level: required + - id: "mq.queue.depth.low.event" + type: metric + metric_name: "mq.queue.depth.low.event" + stability: development + brief: "The number of low queue events" + instrument: counter + unit: "{events}" + attributes: + - ref: queue.manager + requirement_level: required + - ref: queue.name + requirement_level: required + - id: mq.uncommitted.messages + type: metric + metric_name: mq.uncommitted.messages + stability: development + brief: "Number of uncommitted messages" + instrument: gauge + unit: "{messages}" + attributes: + - ref: queue.manager + requirement_level: required + - ref: queue.name + requirement_level: required + - ref: queue.type + requirement_level: required + - id: mq.oldest.msg.age + type: metric + metric_name: mq.oldest.msg.age + stability: development + brief: "Queue message oldest age" + instrument: gauge + unit: "microseconds" + attributes: + - ref: queue.manager + requirement_level: required + - ref: queue.name + requirement_level: required + - ref: queue.type + requirement_level: required + - id: mq.current.max.queue.filesize + type: metric + metric_name: mq.current.max.queue.filesize + stability: development + brief: "Current maximum queue file size" + instrument: gauge + unit: "mib" + attributes: + - ref: queue.manager + requirement_level: required + - ref: queue.name + requirement_level: required + - ref: queue.type + requirement_level: required + - id: mq.current.queue.filesize + type: metric + metric_name: mq.current.queue.filesize + stability: development + brief: "Current queue file size" + instrument: gauge + unit: "mib" + attributes: + - ref: queue.manager + requirement_level: required + - ref: queue.name + requirement_level: required + - ref: queue.type + requirement_level: required + - id: mq.instances.per.client + type: metric + metric_name: mq.instances.per.client + stability: development + brief: "Instances per client" + instrument: gauge + unit: "{instances}" + attributes: + - ref: queue.manager + requirement_level: required + - ref: queue.name + requirement_level: required + - ref: queue.type + requirement_level: required + - id: mq.message.deq.count + type: metric + metric_name: mq.message.deq.count + stability: development + brief: "Message dequeue count" + instrument: gauge + unit: "{messages}" + attributes: + - ref: queue.manager + requirement_level: required + - ref: queue.name + requirement_level: required + - ref: queue.type + requirement_level: required + - id: mq.message.enq.count + type: metric + metric_name: mq.message.enq.count + stability: development + brief: "Message enqueue count" + instrument: gauge + unit: "{messages}" + attributes: + - ref: queue.manager + requirement_level: required + - ref: queue.name + requirement_level: required + - ref: queue.type + requirement_level: required + - id: mq.queue.depth + type: metric + metric_name: mq.queue.depth + stability: development + brief: "Current queue depth" + instrument: gauge + unit: "{messages}" + attributes: + - ref: queue.manager + requirement_level: required + - ref: queue.name + requirement_level: required + - ref: queue.type + requirement_level: required + - id: mq.service.interval.event + type: metric + metric_name: mq.service.interval.event + stability: development + brief: "Queue service interval event" + instrument: gauge + unit: "1" + attributes: + - ref: queue.manager + requirement_level: required + - ref: queue.name + requirement_level: required + - ref: queue.type + requirement_level: required + - id: mq.reusable.log.size + type: metric + metric_name: mq.reusable.log.size + stability: development + brief: "The amount of space occupied, in megabytes, by log extents available to be reused." + instrument: gauge + unit: "mib" + attributes: + - ref: queue.manager + requirement_level: required + - id: mq.manager.active.channels + type: metric + metric_name: mq.manager.active.channels + stability: development + brief: "The queue manager active maximum channels limit" + instrument: gauge + unit: "{channels}" + attributes: + - ref: queue.manager + requirement_level: required + - id: mq.restart.log.size + type: metric + metric_name: mq.restart.log.size + stability: development + brief: "Size of the log data required for restart recovery in megabytes." + instrument: gauge + unit: "mib" + attributes: + - ref: queue.manager + requirement_level: required + - id: mq.max.queue.depth + type: metric + metric_name: mq.max.queue.depth + stability: development + brief: "Maximum queue depth" + instrument: gauge + unit: "{messages}" + attributes: + - ref: queue.manager + requirement_level: required + - ref: queue.name + requirement_level: required + - ref: queue.type + requirement_level: required + - id: mq.onqtime.1 + type: metric + metric_name: mq.onqtime.1 + stability: development + brief: "Amount of time, in microseconds, that a message spent on the queue, over a short period" + instrument: gauge + unit: "microseconds" + attributes: + - ref: queue.manager + requirement_level: required + - ref: queue.name + requirement_level: required + - ref: queue.type + requirement_level: required + - id: mq.onqtime.2 + type: metric + metric_name: mq.onqtime.2 + stability: development + brief: "Amount of time, in microseconds, that a message spent on the queue, over a longer period" + instrument: gauge + unit: "microseconds" + attributes: + - ref: queue.manager + requirement_level: required + - ref: queue.name + requirement_level: required + - ref: queue.type + requirement_level: required + - id: mq.message.received.count + type: metric + metric_name: mq.message.received.count + stability: development + brief: "Number of messages received" + instrument: gauge + unit: "{messages}" + attributes: + - ref: channel.name + requirement_level: required + - ref: channel.type + requirement_level: required + - ref: queue.manager + requirement_level: required + - id: mq.message.sent.count + type: metric + metric_name: mq.message.sent.count + stability: development + brief: "Number of messages sent" + instrument: gauge + unit: "{messages}" + attributes: + - ref: channel.name + requirement_level: required + - ref: channel.type + requirement_level: required + - ref: queue.manager + requirement_level: required + - id: mq.max.instances + type: metric + metric_name: mq.max.instances + stability: development + brief: "Max channel instances" + instrument: gauge + unit: "{instances}" + attributes: + - ref: channel.name + requirement_level: required + - ref: channel.type + requirement_level: required + - ref: queue.manager + requirement_level: required + - id: mq.connection.count + type: metric + metric_name: mq.connection.count + stability: development + brief: "Active connections count" + instrument: gauge + unit: "{connections}" + attributes: + - ref: queue.manager + requirement_level: required + - id: mq.manager.status + type: metric + metric_name: mq.manager.status + stability: development + brief: "Queue manager status" + instrument: gauge + unit: "1" + attributes: + - ref: queue.manager + requirement_level: required + - id: mq.heartbeat + type: metric + metric_name: mq.heartbeat + stability: development + brief: "Queue manager heartbeat" + instrument: gauge + unit: "1" + attributes: + - ref: queue.manager + requirement_level: required + - id: mq.archive.log.size + type: metric + metric_name: mq.archive.log.size + stability: development + brief: "Queue manager archive log size" + instrument: gauge + unit: "mib" + attributes: + - ref: queue.manager + requirement_level: required + - id: mq.manager.max.active.channels + type: metric + metric_name: mq.manager.max.active.channels + stability: development + brief: "Queue manager max active channels" + instrument: gauge + unit: "{channels}" + attributes: + - ref: queue.manager + requirement_level: required + - id: mq.manager.statistics.interval + type: metric + metric_name: mq.manager.statistics.interval + stability: development + brief: "Queue manager statistics interval" + instrument: gauge + unit: "1" + attributes: + - ref: queue.manager + requirement_level: required + - id: mq.publish.count + type: metric + metric_name: mq.publish.count + stability: development + brief: "Topic publication count" + instrument: gauge + unit: "{publications}" + attributes: + - ref: queue.manager + requirement_level: required + - ref: topic.name + requirement_level: required + - id: mq.subscription.count + type: metric + metric_name: mq.subscription.count + stability: development + brief: "Topic subscription count" + instrument: gauge + unit: "{subscriptions}" + attributes: + - ref: queue.manager + requirement_level: required + - ref: topic.name + requirement_level: required + - id: mq.listener.status + type: metric + metric_name: mq.listener.status + stability: development + brief: "Listener status" + instrument: gauge + unit: "1" + attributes: + - ref: queue.manager + requirement_level: required + - ref: listener.name + requirement_level: required + - id: mq.unauthorized.event + type: metric + metric_name: mq.unauthorized.event + stability: development + brief: "Number of authentication error events" + instrument: counter + unit: "{events}" + attributes: + - ref: queue.manager + requirement_level: required + - ref: user.name + requirement_level: required + - ref: application.name + requirement_level: required + - id: mq.manager.max.handles + type: metric + metric_name: mq.manager.max.handles + stability: development + brief: "Max open handles" + instrument: gauge + unit: "{events}" + attributes: + - ref: queue.manager + requirement_level: required \ No newline at end of file diff --git a/ibm-mq-metrics/model/registry_manifest.yaml b/ibm-mq-metrics/model/registry_manifest.yaml new file mode 100644 index 000000000..1fb92e0cb --- /dev/null +++ b/ibm-mq-metrics/model/registry_manifest.yaml @@ -0,0 +1,3 @@ +name: IBM MQ Monitoring +semconv_version: v1.34.0 +schema_base_url: https://www.github.com/open-telemetry/opentelemetry-java-contrib/ibm-mq-metrics diff --git a/ibm-mq-metrics/src/integrationTest/java/io/opentelemetry/ibm/mq/integration/tests/JakartaPutGet.java b/ibm-mq-metrics/src/integrationTest/java/io/opentelemetry/ibm/mq/integration/tests/JakartaPutGet.java index 02f4ad441..ef40efa44 100644 --- a/ibm-mq-metrics/src/integrationTest/java/io/opentelemetry/ibm/mq/integration/tests/JakartaPutGet.java +++ b/ibm-mq-metrics/src/integrationTest/java/io/opentelemetry/ibm/mq/integration/tests/JakartaPutGet.java @@ -47,8 +47,7 @@ */ public final class JakartaPutGet { - private JakartaPutGet(){ - } + private JakartaPutGet() {} public static void createQueue(QueueManager manager, String name, int maxDepth) { MQQueueManager ibmQueueManager = WmqUtil.connectToQueueManager(manager); 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 e512881e1..f77df6816 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 @@ -2,7 +2,6 @@ * Copyright The OpenTelemetry Authors * SPDX-License-Identifier: Apache-2.0 */ - package io.opentelemetry.ibm.mq.metrics; import io.opentelemetry.api.metrics.LongCounter; @@ -14,409 +13,184 @@ /** Metric definitions generated from a Weaver model. Do not edit manually. */ public final class Metrics { - private Metrics() {} - public static LongGauge createMqMessageRetryCount(Meter meter) { - return meter - .gaugeBuilder("mq.message.retry.count") - .ofLongs() - .setUnit("{messages}") - .setDescription("Number of message retries") - .build(); + return meter.gaugeBuilder("mq.message.retry.count").ofLongs().setUnit("{messages}").setDescription("Number of message retries").build(); } public static LongGauge createMqStatus(Meter meter) { - return meter - .gaugeBuilder("mq.status") - .ofLongs() - .setUnit("1") - .setDescription("Channel status") - .build(); + return meter.gaugeBuilder("mq.status").ofLongs().setUnit("1").setDescription("Channel status").build(); } public static LongGauge createMqMaxSharingConversations(Meter meter) { - return meter - .gaugeBuilder("mq.max.sharing.conversations") - .ofLongs() - .setUnit("{conversations}") - .setDescription("Maximum number of conversations permitted on this channel instance.") - .build(); + return meter.gaugeBuilder("mq.max.sharing.conversations").ofLongs().setUnit("{conversations}").setDescription("Maximum number of conversations permitted on this channel instance.").build(); } public static LongGauge createMqCurrentSharingConversations(Meter meter) { - return meter - .gaugeBuilder("mq.current.sharing.conversations") - .ofLongs() - .setUnit("{conversations}") - .setDescription("Current number of conversations permitted on this channel instance.") - .build(); + return meter.gaugeBuilder("mq.current.sharing.conversations").ofLongs().setUnit("{conversations}").setDescription("Current number of conversations permitted on this channel instance.").build(); } public static LongGauge createMqByteReceived(Meter meter) { - return meter - .gaugeBuilder("mq.byte.received") - .ofLongs() - .setUnit("{bytes}") - .setDescription("Number of bytes received") - .build(); + return meter.gaugeBuilder("mq.byte.received").ofLongs().setUnit("{bytes}").setDescription("Number of bytes received").build(); } public static LongGauge createMqByteSent(Meter meter) { - return meter - .gaugeBuilder("mq.byte.sent") - .ofLongs() - .setUnit("{bytes}") - .setDescription("Number of bytes sent") - .build(); + return meter.gaugeBuilder("mq.byte.sent").ofLongs().setUnit("{bytes}").setDescription("Number of bytes sent").build(); } public static LongGauge createMqBuffersReceived(Meter meter) { - return meter - .gaugeBuilder("mq.buffers.received") - .ofLongs() - .setUnit("{buffers}") - .setDescription("Buffers received") - .build(); + return meter.gaugeBuilder("mq.buffers.received").ofLongs().setUnit("{buffers}").setDescription("Buffers received").build(); } public static LongGauge createMqBuffersSent(Meter meter) { - return meter - .gaugeBuilder("mq.buffers.sent") - .ofLongs() - .setUnit("{buffers}") - .setDescription("Buffers sent") - .build(); + return meter.gaugeBuilder("mq.buffers.sent").ofLongs().setUnit("{buffers}").setDescription("Buffers sent").build(); } public static LongGauge createMqMessageCount(Meter meter) { - return meter - .gaugeBuilder("mq.message.count") - .ofLongs() - .setUnit("{messages}") - .setDescription("Message count") - .build(); + return meter.gaugeBuilder("mq.message.count").ofLongs().setUnit("{messages}").setDescription("Message count").build(); } public static LongGauge createMqOpenInputCount(Meter meter) { - return meter - .gaugeBuilder("mq.open.input.count") - .ofLongs() - .setUnit("{applications}") - .setDescription("Count of applications sending messages to the queue") - .build(); + return meter.gaugeBuilder("mq.open.input.count").ofLongs().setUnit("{applications}").setDescription("Count of applications sending messages to the queue").build(); } public static LongGauge createMqOpenOutputCount(Meter meter) { - return meter - .gaugeBuilder("mq.open.output.count") - .ofLongs() - .setUnit("{applications}") - .setDescription("Count of applications consuming messages from the queue") - .build(); + return meter.gaugeBuilder("mq.open.output.count").ofLongs().setUnit("{applications}").setDescription("Count of applications consuming messages from the queue").build(); } public static LongGauge createMqHighQueueDepth(Meter meter) { - return meter - .gaugeBuilder("mq.high.queue.depth") - .ofLongs() - .setUnit("{percent}") - .setDescription("The current high queue depth") - .build(); + return meter.gaugeBuilder("mq.high.queue.depth").ofLongs().setUnit("{percent}").setDescription("The current high queue depth").build(); } public static LongGauge createMqServiceInterval(Meter meter) { - return meter - .gaugeBuilder("mq.service.interval") - .ofLongs() - .setUnit("{percent}") - .setDescription("The queue service interval") - .build(); + return meter.gaugeBuilder("mq.service.interval").ofLongs().setUnit("{percent}").setDescription("The queue service interval").build(); } public static LongCounter createMqQueueDepthFullEvent(Meter meter) { - return meter - .counterBuilder("mq.queue.depth.full.event") - .setUnit("{events}") - .setDescription("The number of full queue events") - .build(); + return meter.counterBuilder("mq.queue.depth.full.event").setUnit("{events}").setDescription("The number of full queue events").build(); } public static LongCounter createMqQueueDepthHighEvent(Meter meter) { - return meter - .counterBuilder("mq.queue.depth.high.event") - .setUnit("{events}") - .setDescription("The number of high queue events") - .build(); + return meter.counterBuilder("mq.queue.depth.high.event").setUnit("{events}").setDescription("The number of high queue events").build(); } public static LongCounter createMqQueueDepthLowEvent(Meter meter) { - return meter - .counterBuilder("mq.queue.depth.low.event") - .setUnit("{events}") - .setDescription("The number of low queue events") - .build(); + return meter.counterBuilder("mq.queue.depth.low.event").setUnit("{events}").setDescription("The number of low queue events").build(); } public static LongGauge createMqUncommittedMessages(Meter meter) { - return meter - .gaugeBuilder("mq.uncommitted.messages") - .ofLongs() - .setUnit("{messages}") - .setDescription("Number of uncommitted messages") - .build(); + return meter.gaugeBuilder("mq.uncommitted.messages").ofLongs().setUnit("{messages}").setDescription("Number of uncommitted messages").build(); } public static LongGauge createMqOldestMsgAge(Meter meter) { - return meter - .gaugeBuilder("mq.oldest.msg.age") - .ofLongs() - .setUnit("microseconds") - .setDescription("Queue message oldest age") - .build(); + return meter.gaugeBuilder("mq.oldest.msg.age").ofLongs().setUnit("microseconds").setDescription("Queue message oldest age").build(); } public static LongGauge createMqCurrentMaxQueueFilesize(Meter meter) { - return meter - .gaugeBuilder("mq.current.max.queue.filesize") - .ofLongs() - .setUnit("mib") - .setDescription("Current maximum queue file size") - .build(); + return meter.gaugeBuilder("mq.current.max.queue.filesize").ofLongs().setUnit("mib").setDescription("Current maximum queue file size").build(); } public static LongGauge createMqCurrentQueueFilesize(Meter meter) { - return meter - .gaugeBuilder("mq.current.queue.filesize") - .ofLongs() - .setUnit("mib") - .setDescription("Current queue file size") - .build(); + return meter.gaugeBuilder("mq.current.queue.filesize").ofLongs().setUnit("mib").setDescription("Current queue file size").build(); } public static LongGauge createMqInstancesPerClient(Meter meter) { - return meter - .gaugeBuilder("mq.instances.per.client") - .ofLongs() - .setUnit("{instances}") - .setDescription("Instances per client") - .build(); + return meter.gaugeBuilder("mq.instances.per.client").ofLongs().setUnit("{instances}").setDescription("Instances per client").build(); } public static LongGauge createMqMessageDeqCount(Meter meter) { - return meter - .gaugeBuilder("mq.message.deq.count") - .ofLongs() - .setUnit("{messages}") - .setDescription("Message dequeue count") - .build(); + return meter.gaugeBuilder("mq.message.deq.count").ofLongs().setUnit("{messages}").setDescription("Message dequeue count").build(); } public static LongGauge createMqMessageEnqCount(Meter meter) { - return meter - .gaugeBuilder("mq.message.enq.count") - .ofLongs() - .setUnit("{messages}") - .setDescription("Message enqueue count") - .build(); + return meter.gaugeBuilder("mq.message.enq.count").ofLongs().setUnit("{messages}").setDescription("Message enqueue count").build(); } public static LongGauge createMqQueueDepth(Meter meter) { - return meter - .gaugeBuilder("mq.queue.depth") - .ofLongs() - .setUnit("{messages}") - .setDescription("Current queue depth") - .build(); + return meter.gaugeBuilder("mq.queue.depth").ofLongs().setUnit("{messages}").setDescription("Current queue depth").build(); } public static LongGauge createMqServiceIntervalEvent(Meter meter) { - return meter - .gaugeBuilder("mq.service.interval.event") - .ofLongs() - .setUnit("1") - .setDescription("Queue service interval event") - .build(); + return meter.gaugeBuilder("mq.service.interval.event").ofLongs().setUnit("1").setDescription("Queue service interval event").build(); } public static LongGauge createMqReusableLogSize(Meter meter) { - return meter - .gaugeBuilder("mq.reusable.log.size") - .ofLongs() - .setUnit("mib") - .setDescription( - "The amount of space occupied, in megabytes, by log extents available to be reused.") - .build(); + return meter.gaugeBuilder("mq.reusable.log.size").ofLongs().setUnit("mib").setDescription("The amount of space occupied, in megabytes, by log extents available to be reused.").build(); } public static LongGauge createMqManagerActiveChannels(Meter meter) { - return meter - .gaugeBuilder("mq.manager.active.channels") - .ofLongs() - .setUnit("{channels}") - .setDescription("The queue manager active maximum channels limit") - .build(); + return meter.gaugeBuilder("mq.manager.active.channels").ofLongs().setUnit("{channels}").setDescription("The queue manager active maximum channels limit").build(); } public static LongGauge createMqRestartLogSize(Meter meter) { - return meter - .gaugeBuilder("mq.restart.log.size") - .ofLongs() - .setUnit("mib") - .setDescription("Size of the log data required for restart recovery in megabytes.") - .build(); + return meter.gaugeBuilder("mq.restart.log.size").ofLongs().setUnit("mib").setDescription("Size of the log data required for restart recovery in megabytes.").build(); } public static LongGauge createMqMaxQueueDepth(Meter meter) { - return meter - .gaugeBuilder("mq.max.queue.depth") - .ofLongs() - .setUnit("{messages}") - .setDescription("Maximum queue depth") - .build(); + return meter.gaugeBuilder("mq.max.queue.depth").ofLongs().setUnit("{messages}").setDescription("Maximum queue depth").build(); } public static LongGauge createMqOnqtime1(Meter meter) { - return meter - .gaugeBuilder("mq.onqtime.1") - .ofLongs() - .setUnit("microseconds") - .setDescription( - "Amount of time, in microseconds, that a message spent on the queue, over a short period") - .build(); + return meter.gaugeBuilder("mq.onqtime.1").ofLongs().setUnit("microseconds").setDescription("Amount of time, in microseconds, that a message spent on the queue, over a short period").build(); } public static LongGauge createMqOnqtime2(Meter meter) { - return meter - .gaugeBuilder("mq.onqtime.2") - .ofLongs() - .setUnit("microseconds") - .setDescription( - "Amount of time, in microseconds, that a message spent on the queue, over a longer period") - .build(); + return meter.gaugeBuilder("mq.onqtime.2").ofLongs().setUnit("microseconds").setDescription("Amount of time, in microseconds, that a message spent on the queue, over a longer period").build(); } public static LongGauge createMqMessageReceivedCount(Meter meter) { - return meter - .gaugeBuilder("mq.message.received.count") - .ofLongs() - .setUnit("{messages}") - .setDescription("Number of messages received") - .build(); + return meter.gaugeBuilder("mq.message.received.count").ofLongs().setUnit("{messages}").setDescription("Number of messages received").build(); } public static LongGauge createMqMessageSentCount(Meter meter) { - return meter - .gaugeBuilder("mq.message.sent.count") - .ofLongs() - .setUnit("{messages}") - .setDescription("Number of messages sent") - .build(); + return meter.gaugeBuilder("mq.message.sent.count").ofLongs().setUnit("{messages}").setDescription("Number of messages sent").build(); } public static LongGauge createMqMaxInstances(Meter meter) { - return meter - .gaugeBuilder("mq.max.instances") - .ofLongs() - .setUnit("{instances}") - .setDescription("Max channel instances") - .build(); + return meter.gaugeBuilder("mq.max.instances").ofLongs().setUnit("{instances}").setDescription("Max channel instances").build(); } public static LongGauge createMqConnectionCount(Meter meter) { - return meter - .gaugeBuilder("mq.connection.count") - .ofLongs() - .setUnit("{connections}") - .setDescription("Active connections count") - .build(); + return meter.gaugeBuilder("mq.connection.count").ofLongs().setUnit("{connections}").setDescription("Active connections count").build(); } public static LongGauge createMqManagerStatus(Meter meter) { - return meter - .gaugeBuilder("mq.manager.status") - .ofLongs() - .setUnit("1") - .setDescription("Queue manager status") - .build(); + return meter.gaugeBuilder("mq.manager.status").ofLongs().setUnit("1").setDescription("Queue manager status").build(); } public static LongGauge createMqHeartbeat(Meter meter) { - return meter - .gaugeBuilder("mq.heartbeat") - .ofLongs() - .setUnit("1") - .setDescription("Queue manager heartbeat") - .build(); + return meter.gaugeBuilder("mq.heartbeat").ofLongs().setUnit("1").setDescription("Queue manager heartbeat").build(); } public static LongGauge createMqArchiveLogSize(Meter meter) { - return meter - .gaugeBuilder("mq.archive.log.size") - .ofLongs() - .setUnit("mib") - .setDescription("Queue manager archive log size") - .build(); + return meter.gaugeBuilder("mq.archive.log.size").ofLongs().setUnit("mib").setDescription("Queue manager archive log size").build(); } public static LongGauge createMqManagerMaxActiveChannels(Meter meter) { - return meter - .gaugeBuilder("mq.manager.max.active.channels") - .ofLongs() - .setUnit("{channels}") - .setDescription("Queue manager max active channels") - .build(); + return meter.gaugeBuilder("mq.manager.max.active.channels").ofLongs().setUnit("{channels}").setDescription("Queue manager max active channels").build(); } public static LongGauge createMqManagerStatisticsInterval(Meter meter) { - return meter - .gaugeBuilder("mq.manager.statistics.interval") - .ofLongs() - .setUnit("1") - .setDescription("Queue manager statistics interval") - .build(); + return meter.gaugeBuilder("mq.manager.statistics.interval").ofLongs().setUnit("1").setDescription("Queue manager statistics interval").build(); } public static LongGauge createMqPublishCount(Meter meter) { - return meter - .gaugeBuilder("mq.publish.count") - .ofLongs() - .setUnit("{publications}") - .setDescription("Topic publication count") - .build(); + return meter.gaugeBuilder("mq.publish.count").ofLongs().setUnit("{publications}").setDescription("Topic publication count").build(); } public static LongGauge createMqSubscriptionCount(Meter meter) { - return meter - .gaugeBuilder("mq.subscription.count") - .ofLongs() - .setUnit("{subscriptions}") - .setDescription("Topic subscription count") - .build(); + return meter.gaugeBuilder("mq.subscription.count").ofLongs().setUnit("{subscriptions}").setDescription("Topic subscription count").build(); } public static LongGauge createMqListenerStatus(Meter meter) { - return meter - .gaugeBuilder("mq.listener.status") - .ofLongs() - .setUnit("1") - .setDescription("Listener status") - .build(); + return meter.gaugeBuilder("mq.listener.status").ofLongs().setUnit("1").setDescription("Listener status").build(); } public static LongCounter createMqUnauthorizedEvent(Meter meter) { - return meter - .counterBuilder("mq.unauthorized.event") - .setUnit("{events}") - .setDescription("Number of authentication error events") - .build(); + return meter.counterBuilder("mq.unauthorized.event").setUnit("{events}").setDescription("Number of authentication error events").build(); } public static LongGauge createMqManagerMaxHandles(Meter meter) { - return meter - .gaugeBuilder("mq.manager.max.handles") - .ofLongs() - .setUnit("{events}") - .setDescription("Max open handles") - .build(); - } -} + return meter.gaugeBuilder("mq.manager.max.handles").ofLongs().setUnit("{events}").setDescription("Max open handles").build(); + } + +} \ No newline at end of file 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 72305ef90..cac79ca47 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 @@ -2,7 +2,6 @@ * Copyright The OpenTelemetry Authors * SPDX-License-Identifier: Apache-2.0 */ - package io.opentelemetry.ibm.mq.metrics; import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; @@ -11,17 +10,17 @@ // This file is generated using weaver. Do not edit manually. /** Configuration of metrics as defined in config.yml. */ -public class MetricsConfig { +public final class MetricsConfig { private final Map config; public MetricsConfig(ConfigWrapper config) { - this.config = config.getMetrics(); + this.config = config.getMetrics(); } + public boolean isMqMessageRetryCountEnabled() { - String key = "mq.message.retry.count"; - return isEnabled(key); + return isEnabled("mq.message.retry.count"); } public boolean isMqStatusEnabled() { @@ -211,4 +210,4 @@ private boolean isEnabled(String key) { } return false; } -} +} \ No newline at end of file diff --git a/ibm-mq-metrics/src/main/resources/log4j2.xml b/ibm-mq-metrics/src/main/resources/log4j2.xml index 98ee41146..049d2af6b 100644 --- a/ibm-mq-metrics/src/main/resources/log4j2.xml +++ b/ibm-mq-metrics/src/main/resources/log4j2.xml @@ -51,9 +51,9 @@ - + - \ No newline at end of file + diff --git a/ibm-mq-metrics/src/test/resources/log4j.xml b/ibm-mq-metrics/src/test/resources/log4j.xml index 1fe17d69c..233ddcbe9 100644 --- a/ibm-mq-metrics/src/test/resources/log4j.xml +++ b/ibm-mq-metrics/src/test/resources/log4j.xml @@ -1,20 +1,4 @@ - - @@ -24,7 +8,7 @@ - + diff --git a/ibm-mq-metrics/templates/registry/java/Metrics.java.j2 b/ibm-mq-metrics/templates/registry/java/Metrics.java.j2 index 22d935808..834343df7 100644 --- a/ibm-mq-metrics/templates/registry/java/Metrics.java.j2 +++ b/ibm-mq-metrics/templates/registry/java/Metrics.java.j2 @@ -1,19 +1,8 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ -package com.splunk.ibm.mq.metrics; +package io.opentelemetry.ibm.mq.metrics; import io.opentelemetry.api.metrics.LongCounter; import io.opentelemetry.api.metrics.LongGauge; @@ -21,13 +10,11 @@ import io.opentelemetry.api.metrics.Meter; // This file is generated using weaver. Do not edit manually. -/** - * Metric definitions generated from a Weaver model. Do not edit manually. - */ -public class Metrics { +/** Metric definitions generated from a Weaver model. Do not edit manually. */ +public final class Metrics { {% for metric in ctx %} public static {% if metric.instrument == "gauge" %}LongGauge{% elif metric.instrument == "counter" %}LongCounter{% endif %} create{{ metric.metric_name.split('.')|map('capitalize')|join }}(Meter meter) { return meter.{% if metric.instrument == "gauge" %}gauge{% elif metric.instrument == "counter" %}counter{% endif %}Builder("{{ metric.metric_name }}").{% if metric.instrument == "gauge" %}ofLongs().{% endif %}setUnit("{{ metric.unit }}").setDescription("{{ metric.brief }}").build(); } {% endfor %} -} \ No newline at end of file +} diff --git a/ibm-mq-metrics/templates/registry/java/MetricsConfig.java.j2 b/ibm-mq-metrics/templates/registry/java/MetricsConfig.java.j2 index 5ad5bd51c..2a5992308 100644 --- a/ibm-mq-metrics/templates/registry/java/MetricsConfig.java.j2 +++ b/ibm-mq-metrics/templates/registry/java/MetricsConfig.java.j2 @@ -1,30 +1,16 @@ /* - * Copyright Splunk Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ -package com.splunk.ibm.mq.metrics; +package io.opentelemetry.ibm.mq.metrics; -import com.splunk.ibm.mq.opentelemetry.ConfigWrapper; +import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; import java.util.Map; // This file is generated using weaver. Do not edit manually. -/** - * Configuration of metrics as defined in config.yml. - * - */ -public class MetricsConfig { +/** Configuration of metrics as defined in config.yml. */ +public final class MetricsConfig { private final Map config; @@ -34,15 +20,18 @@ public class MetricsConfig { {% for metric in ctx %} public boolean is{{ metric.metric_name.split('.')|map('capitalize')|join }}Enabled() { - Object metricInfo = config.get("{{ metric.metric_name }}"); + return isEnabled("{{ metric.metric_name }}"); + } +{% endfor %} + private boolean isEnabled(String key) { + Object metricInfo = config.get(key); if (!(metricInfo instanceof Map)) { return false; } Object enabled = ((Map) metricInfo).get("enabled"); if (enabled instanceof Boolean) { - return (Boolean) ((Map) metricInfo).get("enabled"); + return (Boolean) enabled; } return false; } -{% endfor %} -} \ No newline at end of file +} diff --git a/ibm-mq-metrics/templates/registry/markdown/attribute_macros.j2 b/ibm-mq-metrics/templates/registry/markdown/attribute_macros.j2 new file mode 100644 index 000000000..9c0fea34e --- /dev/null +++ b/ibm-mq-metrics/templates/registry/markdown/attribute_macros.j2 @@ -0,0 +1,36 @@ +{% import 'examples_macros.j2' as examples %} +{% macro type(attribute) %}{%- if attribute.type is mapping %} +{%- if attribute.type.members[0].value is string %}string{%- endif %} +{%- if attribute.type.members[0].value is int %}int{%- endif %} +{%- if attribute.type.members[0].value is float %}double{%- endif %} +{%- elif attribute.type == "template[boolean]" %}boolean +{%- elif attribute.type == "template[int]" %}int +{%- elif attribute.type == "template[double]" %}double +{%- elif attribute.type == "template[string]" %}string +{%- elif attribute.type == "template[boolean[]]" %}boolean[] +{%- elif attribute.type == "template[int[]]" %}int[] +{%- elif attribute.type == "template[double[]]" %}double[] +{%- elif attribute.type == "template[string[]]" %}string[] +{%- else %}{{ attribute.type | trim }}{%- endif %}{% endmacro %} + +{% macro name(attribute) %}{%- if attribute.type is startingwith("template[") %}`{{ attribute.name }}.` +{%- else %}`{{ attribute.name }}`{%- endif %}{% endmacro %} + +{% macro find_lineage(attr_id, lineage) %}{% if attr_id in lineage %}{{lineage[attr_id].source_group}}{% endif %}{% endmacro %} + +{% macro name_with_link(attribute, attribute_registry_base_url, lineage_attributes) %}[{{name(attribute)}}]({{attribute_registry_base_url}}/{{ find_lineage(attribute.name, lineage_attributes) | split_id | list | reject("eq", "registry")| first | kebab_case }}.md){% endmacro %} + +{% macro display_name(group) %} +{%- if 'display_name' in group %}{{ group.display_name }} +{%- else %}{{ group.id | split_id | list | reject("eq", "registry") | join(" ") | title_case | acronym }} Attributes +{%- endif %}{% endmacro %} + +{% macro heading_link_fragments(title) %}{{ title | trim | lower | replace(" ", "-") | replace("(", "") | replace(")", "") | replace("/", "") | replace("\\", "") | replace(".", "") | replace("!", "") | replace("?", "") | replace("~", "") | replace("#", "")}}{% endmacro %} + +{% macro humanize(text) %} + {{- text.replace('_', ' ') -}} +{% endmacro %} + +{% macro sentence_case(text) %} + {{- text[:1].upper() + text[1:].lower() -}} +{% endmacro %} diff --git a/ibm-mq-metrics/templates/registry/markdown/attribute_namespace.md.j2 b/ibm-mq-metrics/templates/registry/markdown/attribute_namespace.md.j2 new file mode 100644 index 000000000..e55c288b3 --- /dev/null +++ b/ibm-mq-metrics/templates/registry/markdown/attribute_namespace.md.j2 @@ -0,0 +1,51 @@ +{#- This template is rendered per top-level registry namespace. -#} +{#- It consists of two variables: -#} +{#- - id: The top-level namespace id. -#} +{#- - groups: A sequence of all attribute groups under this namespace. -#} +{#- This includes deprecated groups. -#} +{%- import 'stability.j2' as stability -%} +{%- import 'notes.j2' as notes -%} +{%- import 'enum_macros.j2' as enums -%} +{%- import 'attribute_macros.j2' as attrs -%} +{%- import 'examples_macros.j2' as examples -%} +{%- set my_file_name = ctx.id | lower | kebab_case ~ ".md" -%} +{{- template.set_file_name(my_file_name) -}} +{%- set groups = namespace(deprecated=[], non_deprecated=[]) -%} +{%- for group in ctx.groups | sort(attribute="id") -%} +{%- if group.id[-10:] == "deprecated" -%} +{%- set groups.deprecated = groups.deprecated + [group] -%} +{%- else -%} +{%- set groups.non_deprecated = groups.non_deprecated + [group] -%} +{%- endif -%} +{%- endfor -%} +{%- set attr_groups = groups.non_deprecated + groups.deprecated -%} + + + + +# {{ attrs.humanize(attrs.sentence_case(ctx.id)) | acronym }} + +{%- if attr_groups | length > 1 %} +{% for group in attr_groups %} +- [{{ attrs.display_name(group) }}](#{{ attrs.heading_link_fragments(attrs.display_name(group)) }}) +{%- endfor -%} +{%- endif %} +{% for group in attr_groups %} +## {{ attrs.display_name(group) }} + +{% if group.brief.endswith("\n") -%} +{{ group.brief }} +{% else -%} +{{ group.brief }} +{{"\n"}} +{%- endif -%} +| Attribute | Type | Description | Examples | Stability | +|---|---|---|---|---| +{%- for attribute in group.attributes | sort(attribute="name") %}{% set attr_anchor = attribute.name | kebab_case %} +| {{ attrs.name(attribute) }} | {{ attrs.type(attribute) }} | {{ attribute.brief | trim }}{{ notes.add({"note": attribute.note, "name": attribute.name}) }} | {{ examples.format(attribute) | trim }} | {{ stability.badge(attribute.stability, attribute.deprecated) | trim }} | +{%- endfor %} +{{ notes.render() }} +{%- for enum in group.attributes | sort(attribute="name") %} +{%- if enum.type is mapping -%}{{ enums.table(enum, notes) }}{% endif %} +{%- endfor -%} +{%- endfor -%} diff --git a/ibm-mq-metrics/templates/registry/markdown/attribute_table.j2 b/ibm-mq-metrics/templates/registry/markdown/attribute_table.j2 new file mode 100644 index 000000000..b40c54788 --- /dev/null +++ b/ibm-mq-metrics/templates/registry/markdown/attribute_table.j2 @@ -0,0 +1,13 @@ +{% import 'requirement.j2' as requirement %} +{% import 'stability.j2' as stability %} +{% import 'notes.j2' as notes %} +{% import 'attribute_macros.j2' as attrs %} +{% import 'enum_macros.j2' as enums %} +{% import 'sampling_macros.j2' as sampling %} +{% import 'examples_macros.j2' as examples %} +{#- Macro for creating attribute table -#} +{% macro generate(attributes, tag_filter, attribute_registry_base_url, lineage_attributes) %}{% if (tag_filter | length == 0) %}{% set filtered_attributes = attributes %}{% else %}{% set filtered_attributes = attributes | selectattr("tag", "in", tag_filter) %}{% endif %}{% if filtered_attributes | length > 0 %}| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +{% for attribute in filtered_attributes | attribute_sort %}| {{ attrs.name(attribute) }} | {{ attrs.type(attribute) }} | {{ attribute.brief | trim }}{{ notes.add({"note": attribute.note, "name": attribute.name}) }} | {{ examples.format(attribute) | trim }} | {{ requirement.render({"level": attribute.requirement_level, "name": attribute.name}, notes) | trim }} | {{ stability.badge(attribute.stability, attribute.deprecated) | trim }} | +{% endfor %}{{ notes.render() }}{{ sampling.snippet(filtered_attributes, attribute_registry_base_url, lineage_attributes) }}{{ enums.tables(filtered_attributes | selectattr("type", "mapping"), notes) }} +{% endif %}{% endmacro %} diff --git a/ibm-mq-metrics/templates/registry/markdown/body_field_table.j2 b/ibm-mq-metrics/templates/registry/markdown/body_field_table.j2 new file mode 100644 index 000000000..b600f6dd7 --- /dev/null +++ b/ibm-mq-metrics/templates/registry/markdown/body_field_table.j2 @@ -0,0 +1,18 @@ +{% import 'requirement.j2' as requirement %} +{% import 'stability.j2' as stability %} +{% import 'notes.j2' as notes %} +{% import 'enum_macros.j2' as enums %} +{% import 'examples_macros.j2' as examples %} +{% macro flatten(fields, ns, depth) %}{% if fields %}{% for f in fields | sort(attribute="id") %} +{% set ns.flat = [ns.flat, [{'field':f,'depth':depth}]] | flatten %}{% if f.fields %}{% set _= flatten(f.fields, ns, depth + 1) %}{% endif %} +{% endfor %}{% endif %}{% endmacro %} +{% macro field_name(field, depth) -%} +{%- set name= " " * 2 * depth ~ '`' ~ field.id ~ '`' -%} +{%- if (field.type == "map") or (field.type == "map[]") %}{{ name ~ ":"}}{% else -%} +{{ name }}{% endif %}{% endmacro %} +{#- Macro for creating body table -#} +{% macro generate(fields) %}{% if (fields | length > 0) %}{% set ns = namespace(flat=[])%}{% set _ = flatten(fields, ns, 0) %}| Body Field | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +{% for f in ns.flat %}| {{ field_name(f.field, f.depth) }} | {{ f.field.type }} | {{ f.field.brief | trim }}{{ notes.add({"note": f.field.note}) }} | {{ examples.format(f.field) | trim }} | {{ requirement.render({"level": f.field.requirement_level, "name": f.field.id}, notes) | trim }} | {{ stability.badge(f.field.stability, f.field.deprecated) | trim }} | +{% endfor %}{{ notes.render() }}{{ enums.field_tables(ns.flat | map(attribute="field") | selectattr("type", "eq", "enum"), notes) -}} +{%- endif %}{% endmacro %} diff --git a/ibm-mq-metrics/templates/registry/markdown/enum_macros.j2 b/ibm-mq-metrics/templates/registry/markdown/enum_macros.j2 new file mode 100644 index 000000000..d20327e14 --- /dev/null +++ b/ibm-mq-metrics/templates/registry/markdown/enum_macros.j2 @@ -0,0 +1,30 @@ +{% import 'stability.j2' as stability %} +{% macro filter(member) %}{% if (member.deprecated is none or member.deprecated == "") %}{{ "True" }}{% else %}{{ "False" }}{% endif %}{% endmacro %} +{% macro table(enum, notes) %} +--- + +`{{enum.name}}` has the following list of well-known values. If one of them applies, then the respective value MUST be used; otherwise, a custom value MAY be used. + +| Value | Description | Stability | +|---|---|---| +{% for espec in enum.type.members | sort(attribute='value') %} +{%- if filter(espec) == "True" -%} +| `{{ espec.value }}` | {{ (espec.brief or espec.id) | trim }}{{ notes.add({"note": espec.note}) }} | {{ stability.badge(espec.stability, espec.deprecated) }} | +{% endif %}{% endfor %}{{ notes.render() }}{% endmacro %} +{% macro tables(enums, notes) -%} +{% for enum in enums | sort(attribute="name") -%} +{{ table(enum, notes) -}} +{% endfor %}{% endmacro %} +{% macro field_table(enum, notes) %} +`{{enum.id}}` has the following list of well-known values. If one of them applies, then the respective value MUST be used; otherwise, a custom value MAY be used. + +| Value | Description | Stability | +|---|---|---| +{% for espec in enum.members | sort(attribute='value') %} +{%- if filter(espec) == "True" -%} +| `{{ espec.value }}` | {{ (espec.brief or espec.id) | trim }}{{ notes.add({"note": espec.note}) }} | {{ stability.badge(espec.stability, espec.deprecated) }} | +{% endif %}{% endfor %}{{ notes.render() }}{% endmacro %} +{% macro field_tables(enums, notes) -%} +{% for enum in enums | sort(attribute="id") -%} +{{ field_table(enum, notes) -}} +{% endfor %}{% endmacro %} \ No newline at end of file diff --git a/ibm-mq-metrics/templates/registry/markdown/event_macros.j2 b/ibm-mq-metrics/templates/registry/markdown/event_macros.j2 new file mode 100644 index 000000000..c6ef8ef6f --- /dev/null +++ b/ibm-mq-metrics/templates/registry/markdown/event_macros.j2 @@ -0,0 +1,16 @@ +{#- Macros for simplifying creating "Event" documentation. -#} +{% import 'stability.j2' as stability %} +{% import 'body_field_table.j2' as body_table %} +{% macro header(event) %}**Status:** {{ stability.badge(event.stability, event.deprecated) }} + +The event name MUST be `{{ event.name }}`. + +{{ event.brief | trim }} +{%if event.note %} +{{ event.note | trim }} +{% endif %} +{% endmacro %} +{% macro body(body) %}{% if body %}**Body fields:** + +{{ body_table.generate(body.fields) }} +{% endif %}{% endmacro %} diff --git a/ibm-mq-metrics/templates/registry/markdown/examples_macros.j2 b/ibm-mq-metrics/templates/registry/markdown/examples_macros.j2 new file mode 100644 index 000000000..bbd840d67 --- /dev/null +++ b/ibm-mq-metrics/templates/registry/markdown/examples_macros.j2 @@ -0,0 +1,17 @@ +{% macro print_examples(examples) %}{%- for e in examples %}{%if loop.first == false %}; {% endif %}`{{ e | trim }}`{%- endfor %}{% endmacro %} + +{% macro format(item) %}{%- if item.examples %} +{%- if "[]" in item.type and "template" not in item.type %} +{%- if item.examples is sequence %} +{%- if item.examples | select("sequence") | length == 0 %}`{{ item.examples | trim }}` +{%- else %}{{ print_examples(item.examples) }} +{%- endif %} +{%- else %}`[{{ item.examples | trim }}]` +{%- endif %} +{%- elif item.examples is sequence %}{{ print_examples(item.examples) }} +{%- else %}`{{ item.examples | trim }}` +{%- endif %}{%- elif item.type is mapping %} +{%- for e in item.type.members %}{% if loop.index0 < 3 %}{% if loop.first == false %}; {% endif %}`{{ e.value | trim }}`{% endif %}{%- endfor %} +{%- elif item.type == "enum" -%} +{%- for e in item.members %}{% if loop.index0 < 3 %}{% if loop.first == false %}; {% endif %}`{{ e.value | trim }}`{% endif %}{%- endfor %} +{%- endif %}{% endmacro %} diff --git a/ibm-mq-metrics/templates/registry/markdown/metric_macros.j2 b/ibm-mq-metrics/templates/registry/markdown/metric_macros.j2 new file mode 100644 index 000000000..deae008dd --- /dev/null +++ b/ibm-mq-metrics/templates/registry/markdown/metric_macros.j2 @@ -0,0 +1,8 @@ +{% macro instrument(type) -%} +{%- if type == "gauge" %}Gauge +{% elif type == "counter" %}Counter +{% elif type == "updowncounter" %}UpDownCounter +{% elif type == "histogram" %}Histogram +{% else %}{{ type }} +{%- endif %} +{% endmacro %} diff --git a/ibm-mq-metrics/templates/registry/markdown/metric_table.j2 b/ibm-mq-metrics/templates/registry/markdown/metric_table.j2 new file mode 100644 index 000000000..ddbd191c6 --- /dev/null +++ b/ibm-mq-metrics/templates/registry/markdown/metric_table.j2 @@ -0,0 +1,7 @@ +{% import 'stability.j2' as stability %} +{% import 'notes.j2' as notes %} +{% import 'metric_macros.j2' as metrics %} +{% macro generate(group) %}| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `{{ group.metric_name }}` | {{ metrics.instrument(group.instrument) | trim }} | `{{ group.unit }}` | {{ group.brief | trim }}{{ notes.add({"note": group.note}) }} | {{ stability.badge(group.stability, group.deprecated) | trim }} | +{{ notes.render() }}{% endmacro %} diff --git a/ibm-mq-metrics/templates/registry/markdown/metrics.md.j2 b/ibm-mq-metrics/templates/registry/markdown/metrics.md.j2 new file mode 100644 index 000000000..0ff8153bc --- /dev/null +++ b/ibm-mq-metrics/templates/registry/markdown/metrics.md.j2 @@ -0,0 +1,14 @@ +{%- import 'attribute_table.j2' as at -%} +{%- import 'metric_table.j2' as mt -%} + +# Produced Metrics + +{% for metric in ctx %} +## Metric `{{metric.metric_name}}` + +{{ mt.generate(metric) }} + +### `{{metric.metric_name}}` Attributes + +{{ at.generate(metric.attributes, "", "", metric.lineage.attributes) }} +{% endfor %} \ No newline at end of file diff --git a/ibm-mq-metrics/templates/registry/markdown/notes.j2 b/ibm-mq-metrics/templates/registry/markdown/notes.j2 new file mode 100644 index 000000000..a96b4270e --- /dev/null +++ b/ibm-mq-metrics/templates/registry/markdown/notes.j2 @@ -0,0 +1,9 @@ +{%- set ns = namespace(notes=[],index=0) -%} +{%- macro add(note) %}{% if note.note %}{% set ns.notes = [ns.notes, [note]] | flatten %} [{{ ns.notes | length + ns.index }}]{% endif %}{% endmacro %} +{%- macro add_with_limit(note) %}{% if note.note | length > 50 %}{% set ns.notes = [ns.notes, [note]] | flatten %} [{{ ns.notes | length + ns.index }}]{% elif note.note %} {{ note.note | trim }}{% endif %}{% endmacro %} +{% macro render() %}{% if ns.notes | length > 0 %} +{%- for note in ns.notes %} +{% if note.name %}**[{{ns.index+loop.index}}] `{{note.name}}`:** {{ note.note | trim }}{% else -%}**[{{ns.index+loop.index}}]:** {{ note.note | trim }} {%- endif -%} +{%- if not loop.last -%}{{"\n"}}{%- endif -%} +{% endfor %}{% set ns.index = ns.notes | length + ns.index %}{% set ns.notes = [] %} +{% endif %}{% endmacro %} diff --git a/ibm-mq-metrics/templates/registry/markdown/readme.md.j2 b/ibm-mq-metrics/templates/registry/markdown/readme.md.j2 new file mode 100644 index 000000000..8aea78a9f --- /dev/null +++ b/ibm-mq-metrics/templates/registry/markdown/readme.md.j2 @@ -0,0 +1,42 @@ +{{- template.set_file_name("README.md") -}} + + + + + +# Attribute registry + +The attributes registry is the place where attributes are defined. An attribute definition covers the following properties of an attribute: + +- the `id` (the fully qualified name) of the attribute +- the `type` of the attribute +- the `stability` of the attribute +- a `brief` description of the attribute and optionally a longer `note` +- example values + +Attributes defined in the registry can be used in different semantic conventions. Attributes should be included in this registry before they are used in semantic conventions. Semantic conventions may override all the properties of an attribute except for the `id`, `type` and `stability` in case it's required for a particular context. In addition, semantic conventions specify the requirement level of an attribute in the corresponding context. + +A definition of an attribute in the registry doesn't necessarily imply that the attribute is used in any of the semantic conventions. + +If applicable, application developers are encouraged to use existing attributes from this registry. See also [these recommendations][developers recommendations] regarding attribute selection and attribute naming for custom use cases. + +All registered attributes are listed by namespace in this registry. + +> [!WARNING] +> +> The following registry overview is a work in progress. +> +> Further attribute namespaces are currently being migrated and will appear in this registry soon. + +Currently, the following namespaces exist: + +{% for bundle in ctx %} +{%- set my_file_name = bundle.id | kebab_case ~ ".md" -%} +- [{{ bundle.id | title_case | acronym }}]({{ my_file_name }}) +{% endfor %} +[developers recommendations]: ../general/naming.md#recommendations-for-application-developers + diff --git a/ibm-mq-metrics/templates/registry/markdown/requirement.j2 b/ibm-mq-metrics/templates/registry/markdown/requirement.j2 new file mode 100644 index 000000000..1f5714de3 --- /dev/null +++ b/ibm-mq-metrics/templates/registry/markdown/requirement.j2 @@ -0,0 +1,9 @@ +{% macro render(attr, notes) -%} +{%- if attr.level == "recommended" %}`Recommended` +{% elif attr.level == "required" %}`Required` +{% elif attr.level == "opt_in" %}`Opt-In` +{% elif attr.level.conditionally_required %}`Conditionally Required`{{ notes.add_with_limit({"note": attr.level.conditionally_required, "name": attr.name}) }} +{% elif attr.level.recommended %}`Recommended`{{ notes.add_with_limit({"note": attr.level.recommended, "name": attr.name}) }} +{% else %}{{ level }} +{%- endif %} +{% endmacro %} diff --git a/ibm-mq-metrics/templates/registry/markdown/resource_macros.j2 b/ibm-mq-metrics/templates/registry/markdown/resource_macros.j2 new file mode 100644 index 000000000..f19680cbd --- /dev/null +++ b/ibm-mq-metrics/templates/registry/markdown/resource_macros.j2 @@ -0,0 +1,16 @@ +{#- Macros for simplifying creating "Resource" documentation. -#} +{% import 'stability.j2' as stability %} +{% macro real_stability(resource) %} +{% if resource.attributes | map(attribute='stability') | unique | length > 1 -%} +{{ stability.badge("mixed", "") }} +{%- else -%} +{{ stability.badge(resource.stability, resource.deprecated) }} +{%- endif %} +{% endmacro %} +{% macro header(resource) %} +**Status:** {{ real_stability(resource) | trim }} + +**type:** `{{ resource.name }}` + +**Description:** {{ resource.brief }} +{% endmacro %} \ No newline at end of file diff --git a/ibm-mq-metrics/templates/registry/markdown/sampling_macros.j2 b/ibm-mq-metrics/templates/registry/markdown/sampling_macros.j2 new file mode 100644 index 000000000..07929e7d4 --- /dev/null +++ b/ibm-mq-metrics/templates/registry/markdown/sampling_macros.j2 @@ -0,0 +1,7 @@ +{% import 'attribute_macros.j2' as attrs %} +{% macro snippet(attributes, attribute_registry_base_url, lineage_attributes) %}{% set sampling_attributes = attributes | selectattr("sampling_relevant", "true") %}{% if sampling_attributes | length > 0 %} +The following attributes can be important for making sampling decisions +and SHOULD be provided **at span creation time** (if provided at all): + +{% for attribute in sampling_attributes | sort(attribute="name") %}* {{ attrs.name_with_link(attribute, attribute_registry_base_url, lineage_attributes) }} +{% endfor %}{% endif %}{% endmacro %} diff --git a/ibm-mq-metrics/templates/registry/markdown/snippet.md.j2 b/ibm-mq-metrics/templates/registry/markdown/snippet.md.j2 new file mode 100644 index 000000000..6b225c811 --- /dev/null +++ b/ibm-mq-metrics/templates/registry/markdown/snippet.md.j2 @@ -0,0 +1,32 @@ + + + + + +{%- import 'attribute_table.j2' as at -%} +{%- import 'metric_table.j2' as mt -%} +{%- import 'event_macros.j2' as event -%} +{%- import 'resource_macros.j2' as resource %} + +{% macro generate_event(group) -%} +{{ event.header(group) }}{{ generate_attributes(group) }}{{ event.body(group.body) }}{% endmacro -%} +{%- macro generate_resource(group) -%} +{{ resource.header(group) }}{{ generate_attributes(group) }}{% endmacro -%} +{%- macro generate_metric(group) -%} +{{ mt.generate(group) }} +{{ generate_attributes(group) }}{% endmacro -%} +{%- macro generate_attributes(group) -%} +{{ at.generate(group.attributes, tag_filter, attribute_registry_base_url, group.lineage.attributes) }}{% endmacro -%} + +{% if group.type == "event" -%} +{{ generate_event(group) -}} +{%- elif group.type == "resource" -%} +{{ generate_resource(group) }} +{%- elif group.type == "metric" -%} +{{ generate_metric(group) }} +{%- else -%} +{{ generate_attributes(group) -}} +{% endif -%} + + + diff --git a/ibm-mq-metrics/templates/registry/markdown/stability.j2 b/ibm-mq-metrics/templates/registry/markdown/stability.j2 new file mode 100644 index 000000000..cc9ed7bde --- /dev/null +++ b/ibm-mq-metrics/templates/registry/markdown/stability.j2 @@ -0,0 +1,11 @@ +{% macro badge(stability, deprecated) -%} +{%- if deprecated %}![Deprecated](https://img.shields.io/badge/-deprecated-red)
{{ deprecated.note | trim }} +{%- elif stability == "mixed" %}![Mixed](https://img.shields.io/badge/-mixed-yellow) +{%- elif stability == "stable" %}![Stable](https://img.shields.io/badge/-stable-lightgreen) +{%- elif stability == "release_candidate" %}![Release Candidate](https://img.shields.io/badge/-rc-mediumorchid) +{%- elif stability == "deprecated" %}![Deprecated](https://img.shields.io/badge/-deprecated-red) +{%- elif stability == "experimental" %}![Development](https://img.shields.io/badge/-development-blue) +{%- elif stability == "development" %}![Development](https://img.shields.io/badge/-development-blue) +{%- else %}{{ "Unknown stability." }} +{%- endif %} +{%- endmacro %} diff --git a/ibm-mq-metrics/templates/registry/markdown/weaver.yaml b/ibm-mq-metrics/templates/registry/markdown/weaver.yaml new file mode 100644 index 000000000..6a1dd65ad --- /dev/null +++ b/ibm-mq-metrics/templates/registry/markdown/weaver.yaml @@ -0,0 +1,4 @@ +templates: + - pattern: metrics.md.j2 + filter: '.groups | map(select(.type == "metric"))' + application_mode: single \ No newline at end of file diff --git a/ibm-mq-metrics/weaver.Dockerfile b/ibm-mq-metrics/weaver.Dockerfile new file mode 100644 index 000000000..b1698505d --- /dev/null +++ b/ibm-mq-metrics/weaver.Dockerfile @@ -0,0 +1,6 @@ +# DO NOT BUILD +# This file is just for tracking dependencies of the semantic convention build. +# Dependabot can keep this file up to date with latest containers. + +# Weaver is used to generate markdown docs, and enforce policies on the model and run integration tests. +FROM otel/weaver:v0.15.1 AS weaver \ No newline at end of file From ffe34a1fa15807cb69769b8e6a662d6edfca91d2 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 13 Jun 2025 15:42:44 -0700 Subject: [PATCH 13/66] add component --- ibm-mq-metrics/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ibm-mq-metrics/README.md b/ibm-mq-metrics/README.md index 8a3c121b3..2379b7502 100644 --- a/ibm-mq-metrics/README.md +++ b/ibm-mq-metrics/README.md @@ -200,3 +200,9 @@ See [docs/metrics.md](docs/metrics.md). ``` ibm-mq-monitoring--all.jar;com.ibm.mq.jar;com.ibm.mq.jmqi.jar;com.ibm.mq.commonservices.jar;com.ibm.mq.headers.jar;com.ibm.mq.pcf.jar;connector.jar;dhbcore.jar ``` +## Component Owners + +- [Antoine Toulme Sharma](https://github.com/atoulme), Splunk +- [Jason Plumb](https://github.com/breedx-splk), Splunk + +Learn more about component owners in [component_owners.yml](../.github/component_owners.yml). From 8e0ae17ffbbf0591d1d3d8b758b3be66820dfaf4 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 13 Jun 2025 15:43:37 -0700 Subject: [PATCH 14/66] add to main readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 29bc8d222..8b8b041dc 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ feature or via instrumentation, this project is hopefully for you. | alpha | [GCP Authentication Extension](./gcp-auth-extension/README.md) | | beta | [GCP Resources](./gcp-resources/README.md) | | beta | [Inferred Spans](./inferred-spans/README.md) | +| alpha | [IBM MQ Metrics](./ibm-mq-metrics/README.md) | | alpha | [JFR Connection](./jfr-connection/README.md) | | alpha | [JFR Events](./jfr-events/README.md) | | alpha | [JMX Metric Gatherer](./jmx-metrics/README.md) | From 4d99fdec6ffde4574649a53433f53630122e44a5 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 13 Jun 2025 15:48:48 -0700 Subject: [PATCH 15/66] spotless --- ibm-mq-metrics/README.md | 6 +- ibm-mq-metrics/docs/metrics.md | 2 - .../opentelemetry/ibm/mq/metrics/Metrics.java | 320 +++++++++++++++--- .../ibm/mq/metrics/MetricsConfig.java | 6 +- 4 files changed, 278 insertions(+), 56 deletions(-) diff --git a/ibm-mq-metrics/README.md b/ibm-mq-metrics/README.md index 2379b7502..634edc4c7 100644 --- a/ibm-mq-metrics/README.md +++ b/ibm-mq-metrics/README.md @@ -4,11 +4,11 @@ ## Use case -IBM MQ, formerly known as WebSphere MQ (message queue) series, is an IBM software for +IBM MQ, formerly known as WebSphere MQ (message queue) series, is an IBM software for program-to-program messaging across multiple platforms. -The IBM MQ metrics utility here can monitor multiple queues managers and their resources, -namely queues, topics, channels and listeners The metrics are extracted out using the +The IBM MQ metrics utility here can monitor multiple queues managers and their resources, +namely queues, topics, channels and listeners The metrics are extracted out using the [PCF command messages](https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_8.0.0/com.ibm.mq.adm.doc/q020010_.htm). The metrics for queue manager, queue, topic, channel and listener can be configured. diff --git a/ibm-mq-metrics/docs/metrics.md b/ibm-mq-metrics/docs/metrics.md index 47189da11..fafe725ae 100644 --- a/ibm-mq-metrics/docs/metrics.md +++ b/ibm-mq-metrics/docs/metrics.md @@ -753,5 +753,3 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| | `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | - - 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 f77df6816..4d64f27b9 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 @@ -2,6 +2,7 @@ * Copyright The OpenTelemetry Authors * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metrics; import io.opentelemetry.api.metrics.LongCounter; @@ -14,183 +15,406 @@ public final class Metrics { public static LongGauge createMqMessageRetryCount(Meter meter) { - return meter.gaugeBuilder("mq.message.retry.count").ofLongs().setUnit("{messages}").setDescription("Number of message retries").build(); + return meter + .gaugeBuilder("mq.message.retry.count") + .ofLongs() + .setUnit("{messages}") + .setDescription("Number of message retries") + .build(); } public static LongGauge createMqStatus(Meter meter) { - return meter.gaugeBuilder("mq.status").ofLongs().setUnit("1").setDescription("Channel status").build(); + return meter + .gaugeBuilder("mq.status") + .ofLongs() + .setUnit("1") + .setDescription("Channel status") + .build(); } public static LongGauge createMqMaxSharingConversations(Meter meter) { - return meter.gaugeBuilder("mq.max.sharing.conversations").ofLongs().setUnit("{conversations}").setDescription("Maximum number of conversations permitted on this channel instance.").build(); + return meter + .gaugeBuilder("mq.max.sharing.conversations") + .ofLongs() + .setUnit("{conversations}") + .setDescription("Maximum number of conversations permitted on this channel instance.") + .build(); } public static LongGauge createMqCurrentSharingConversations(Meter meter) { - return meter.gaugeBuilder("mq.current.sharing.conversations").ofLongs().setUnit("{conversations}").setDescription("Current number of conversations permitted on this channel instance.").build(); + return meter + .gaugeBuilder("mq.current.sharing.conversations") + .ofLongs() + .setUnit("{conversations}") + .setDescription("Current number of conversations permitted on this channel instance.") + .build(); } public static LongGauge createMqByteReceived(Meter meter) { - return meter.gaugeBuilder("mq.byte.received").ofLongs().setUnit("{bytes}").setDescription("Number of bytes received").build(); + return meter + .gaugeBuilder("mq.byte.received") + .ofLongs() + .setUnit("{bytes}") + .setDescription("Number of bytes received") + .build(); } public static LongGauge createMqByteSent(Meter meter) { - return meter.gaugeBuilder("mq.byte.sent").ofLongs().setUnit("{bytes}").setDescription("Number of bytes sent").build(); + return meter + .gaugeBuilder("mq.byte.sent") + .ofLongs() + .setUnit("{bytes}") + .setDescription("Number of bytes sent") + .build(); } public static LongGauge createMqBuffersReceived(Meter meter) { - return meter.gaugeBuilder("mq.buffers.received").ofLongs().setUnit("{buffers}").setDescription("Buffers received").build(); + return meter + .gaugeBuilder("mq.buffers.received") + .ofLongs() + .setUnit("{buffers}") + .setDescription("Buffers received") + .build(); } public static LongGauge createMqBuffersSent(Meter meter) { - return meter.gaugeBuilder("mq.buffers.sent").ofLongs().setUnit("{buffers}").setDescription("Buffers sent").build(); + return meter + .gaugeBuilder("mq.buffers.sent") + .ofLongs() + .setUnit("{buffers}") + .setDescription("Buffers sent") + .build(); } public static LongGauge createMqMessageCount(Meter meter) { - return meter.gaugeBuilder("mq.message.count").ofLongs().setUnit("{messages}").setDescription("Message count").build(); + return meter + .gaugeBuilder("mq.message.count") + .ofLongs() + .setUnit("{messages}") + .setDescription("Message count") + .build(); } public static LongGauge createMqOpenInputCount(Meter meter) { - return meter.gaugeBuilder("mq.open.input.count").ofLongs().setUnit("{applications}").setDescription("Count of applications sending messages to the queue").build(); + return meter + .gaugeBuilder("mq.open.input.count") + .ofLongs() + .setUnit("{applications}") + .setDescription("Count of applications sending messages to the queue") + .build(); } public static LongGauge createMqOpenOutputCount(Meter meter) { - return meter.gaugeBuilder("mq.open.output.count").ofLongs().setUnit("{applications}").setDescription("Count of applications consuming messages from the queue").build(); + return meter + .gaugeBuilder("mq.open.output.count") + .ofLongs() + .setUnit("{applications}") + .setDescription("Count of applications consuming messages from the queue") + .build(); } public static LongGauge createMqHighQueueDepth(Meter meter) { - return meter.gaugeBuilder("mq.high.queue.depth").ofLongs().setUnit("{percent}").setDescription("The current high queue depth").build(); + return meter + .gaugeBuilder("mq.high.queue.depth") + .ofLongs() + .setUnit("{percent}") + .setDescription("The current high queue depth") + .build(); } public static LongGauge createMqServiceInterval(Meter meter) { - return meter.gaugeBuilder("mq.service.interval").ofLongs().setUnit("{percent}").setDescription("The queue service interval").build(); + return meter + .gaugeBuilder("mq.service.interval") + .ofLongs() + .setUnit("{percent}") + .setDescription("The queue service interval") + .build(); } public static LongCounter createMqQueueDepthFullEvent(Meter meter) { - return meter.counterBuilder("mq.queue.depth.full.event").setUnit("{events}").setDescription("The number of full queue events").build(); + return meter + .counterBuilder("mq.queue.depth.full.event") + .setUnit("{events}") + .setDescription("The number of full queue events") + .build(); } public static LongCounter createMqQueueDepthHighEvent(Meter meter) { - return meter.counterBuilder("mq.queue.depth.high.event").setUnit("{events}").setDescription("The number of high queue events").build(); + return meter + .counterBuilder("mq.queue.depth.high.event") + .setUnit("{events}") + .setDescription("The number of high queue events") + .build(); } public static LongCounter createMqQueueDepthLowEvent(Meter meter) { - return meter.counterBuilder("mq.queue.depth.low.event").setUnit("{events}").setDescription("The number of low queue events").build(); + return meter + .counterBuilder("mq.queue.depth.low.event") + .setUnit("{events}") + .setDescription("The number of low queue events") + .build(); } public static LongGauge createMqUncommittedMessages(Meter meter) { - return meter.gaugeBuilder("mq.uncommitted.messages").ofLongs().setUnit("{messages}").setDescription("Number of uncommitted messages").build(); + return meter + .gaugeBuilder("mq.uncommitted.messages") + .ofLongs() + .setUnit("{messages}") + .setDescription("Number of uncommitted messages") + .build(); } public static LongGauge createMqOldestMsgAge(Meter meter) { - return meter.gaugeBuilder("mq.oldest.msg.age").ofLongs().setUnit("microseconds").setDescription("Queue message oldest age").build(); + return meter + .gaugeBuilder("mq.oldest.msg.age") + .ofLongs() + .setUnit("microseconds") + .setDescription("Queue message oldest age") + .build(); } public static LongGauge createMqCurrentMaxQueueFilesize(Meter meter) { - return meter.gaugeBuilder("mq.current.max.queue.filesize").ofLongs().setUnit("mib").setDescription("Current maximum queue file size").build(); + return meter + .gaugeBuilder("mq.current.max.queue.filesize") + .ofLongs() + .setUnit("mib") + .setDescription("Current maximum queue file size") + .build(); } public static LongGauge createMqCurrentQueueFilesize(Meter meter) { - return meter.gaugeBuilder("mq.current.queue.filesize").ofLongs().setUnit("mib").setDescription("Current queue file size").build(); + return meter + .gaugeBuilder("mq.current.queue.filesize") + .ofLongs() + .setUnit("mib") + .setDescription("Current queue file size") + .build(); } public static LongGauge createMqInstancesPerClient(Meter meter) { - return meter.gaugeBuilder("mq.instances.per.client").ofLongs().setUnit("{instances}").setDescription("Instances per client").build(); + return meter + .gaugeBuilder("mq.instances.per.client") + .ofLongs() + .setUnit("{instances}") + .setDescription("Instances per client") + .build(); } public static LongGauge createMqMessageDeqCount(Meter meter) { - return meter.gaugeBuilder("mq.message.deq.count").ofLongs().setUnit("{messages}").setDescription("Message dequeue count").build(); + return meter + .gaugeBuilder("mq.message.deq.count") + .ofLongs() + .setUnit("{messages}") + .setDescription("Message dequeue count") + .build(); } public static LongGauge createMqMessageEnqCount(Meter meter) { - return meter.gaugeBuilder("mq.message.enq.count").ofLongs().setUnit("{messages}").setDescription("Message enqueue count").build(); + return meter + .gaugeBuilder("mq.message.enq.count") + .ofLongs() + .setUnit("{messages}") + .setDescription("Message enqueue count") + .build(); } public static LongGauge createMqQueueDepth(Meter meter) { - return meter.gaugeBuilder("mq.queue.depth").ofLongs().setUnit("{messages}").setDescription("Current queue depth").build(); + return meter + .gaugeBuilder("mq.queue.depth") + .ofLongs() + .setUnit("{messages}") + .setDescription("Current queue depth") + .build(); } public static LongGauge createMqServiceIntervalEvent(Meter meter) { - return meter.gaugeBuilder("mq.service.interval.event").ofLongs().setUnit("1").setDescription("Queue service interval event").build(); + return meter + .gaugeBuilder("mq.service.interval.event") + .ofLongs() + .setUnit("1") + .setDescription("Queue service interval event") + .build(); } public static LongGauge createMqReusableLogSize(Meter meter) { - return meter.gaugeBuilder("mq.reusable.log.size").ofLongs().setUnit("mib").setDescription("The amount of space occupied, in megabytes, by log extents available to be reused.").build(); + return meter + .gaugeBuilder("mq.reusable.log.size") + .ofLongs() + .setUnit("mib") + .setDescription( + "The amount of space occupied, in megabytes, by log extents available to be reused.") + .build(); } public static LongGauge createMqManagerActiveChannels(Meter meter) { - return meter.gaugeBuilder("mq.manager.active.channels").ofLongs().setUnit("{channels}").setDescription("The queue manager active maximum channels limit").build(); + return meter + .gaugeBuilder("mq.manager.active.channels") + .ofLongs() + .setUnit("{channels}") + .setDescription("The queue manager active maximum channels limit") + .build(); } public static LongGauge createMqRestartLogSize(Meter meter) { - return meter.gaugeBuilder("mq.restart.log.size").ofLongs().setUnit("mib").setDescription("Size of the log data required for restart recovery in megabytes.").build(); + return meter + .gaugeBuilder("mq.restart.log.size") + .ofLongs() + .setUnit("mib") + .setDescription("Size of the log data required for restart recovery in megabytes.") + .build(); } public static LongGauge createMqMaxQueueDepth(Meter meter) { - return meter.gaugeBuilder("mq.max.queue.depth").ofLongs().setUnit("{messages}").setDescription("Maximum queue depth").build(); + return meter + .gaugeBuilder("mq.max.queue.depth") + .ofLongs() + .setUnit("{messages}") + .setDescription("Maximum queue depth") + .build(); } public static LongGauge createMqOnqtime1(Meter meter) { - return meter.gaugeBuilder("mq.onqtime.1").ofLongs().setUnit("microseconds").setDescription("Amount of time, in microseconds, that a message spent on the queue, over a short period").build(); + return meter + .gaugeBuilder("mq.onqtime.1") + .ofLongs() + .setUnit("microseconds") + .setDescription( + "Amount of time, in microseconds, that a message spent on the queue, over a short period") + .build(); } public static LongGauge createMqOnqtime2(Meter meter) { - return meter.gaugeBuilder("mq.onqtime.2").ofLongs().setUnit("microseconds").setDescription("Amount of time, in microseconds, that a message spent on the queue, over a longer period").build(); + return meter + .gaugeBuilder("mq.onqtime.2") + .ofLongs() + .setUnit("microseconds") + .setDescription( + "Amount of time, in microseconds, that a message spent on the queue, over a longer period") + .build(); } public static LongGauge createMqMessageReceivedCount(Meter meter) { - return meter.gaugeBuilder("mq.message.received.count").ofLongs().setUnit("{messages}").setDescription("Number of messages received").build(); + return meter + .gaugeBuilder("mq.message.received.count") + .ofLongs() + .setUnit("{messages}") + .setDescription("Number of messages received") + .build(); } public static LongGauge createMqMessageSentCount(Meter meter) { - return meter.gaugeBuilder("mq.message.sent.count").ofLongs().setUnit("{messages}").setDescription("Number of messages sent").build(); + return meter + .gaugeBuilder("mq.message.sent.count") + .ofLongs() + .setUnit("{messages}") + .setDescription("Number of messages sent") + .build(); } public static LongGauge createMqMaxInstances(Meter meter) { - return meter.gaugeBuilder("mq.max.instances").ofLongs().setUnit("{instances}").setDescription("Max channel instances").build(); + return meter + .gaugeBuilder("mq.max.instances") + .ofLongs() + .setUnit("{instances}") + .setDescription("Max channel instances") + .build(); } public static LongGauge createMqConnectionCount(Meter meter) { - return meter.gaugeBuilder("mq.connection.count").ofLongs().setUnit("{connections}").setDescription("Active connections count").build(); + return meter + .gaugeBuilder("mq.connection.count") + .ofLongs() + .setUnit("{connections}") + .setDescription("Active connections count") + .build(); } public static LongGauge createMqManagerStatus(Meter meter) { - return meter.gaugeBuilder("mq.manager.status").ofLongs().setUnit("1").setDescription("Queue manager status").build(); + return meter + .gaugeBuilder("mq.manager.status") + .ofLongs() + .setUnit("1") + .setDescription("Queue manager status") + .build(); } public static LongGauge createMqHeartbeat(Meter meter) { - return meter.gaugeBuilder("mq.heartbeat").ofLongs().setUnit("1").setDescription("Queue manager heartbeat").build(); + return meter + .gaugeBuilder("mq.heartbeat") + .ofLongs() + .setUnit("1") + .setDescription("Queue manager heartbeat") + .build(); } public static LongGauge createMqArchiveLogSize(Meter meter) { - return meter.gaugeBuilder("mq.archive.log.size").ofLongs().setUnit("mib").setDescription("Queue manager archive log size").build(); + return meter + .gaugeBuilder("mq.archive.log.size") + .ofLongs() + .setUnit("mib") + .setDescription("Queue manager archive log size") + .build(); } public static LongGauge createMqManagerMaxActiveChannels(Meter meter) { - return meter.gaugeBuilder("mq.manager.max.active.channels").ofLongs().setUnit("{channels}").setDescription("Queue manager max active channels").build(); + return meter + .gaugeBuilder("mq.manager.max.active.channels") + .ofLongs() + .setUnit("{channels}") + .setDescription("Queue manager max active channels") + .build(); } public static LongGauge createMqManagerStatisticsInterval(Meter meter) { - return meter.gaugeBuilder("mq.manager.statistics.interval").ofLongs().setUnit("1").setDescription("Queue manager statistics interval").build(); + return meter + .gaugeBuilder("mq.manager.statistics.interval") + .ofLongs() + .setUnit("1") + .setDescription("Queue manager statistics interval") + .build(); } public static LongGauge createMqPublishCount(Meter meter) { - return meter.gaugeBuilder("mq.publish.count").ofLongs().setUnit("{publications}").setDescription("Topic publication count").build(); + return meter + .gaugeBuilder("mq.publish.count") + .ofLongs() + .setUnit("{publications}") + .setDescription("Topic publication count") + .build(); } public static LongGauge createMqSubscriptionCount(Meter meter) { - return meter.gaugeBuilder("mq.subscription.count").ofLongs().setUnit("{subscriptions}").setDescription("Topic subscription count").build(); + return meter + .gaugeBuilder("mq.subscription.count") + .ofLongs() + .setUnit("{subscriptions}") + .setDescription("Topic subscription count") + .build(); } public static LongGauge createMqListenerStatus(Meter meter) { - return meter.gaugeBuilder("mq.listener.status").ofLongs().setUnit("1").setDescription("Listener status").build(); + return meter + .gaugeBuilder("mq.listener.status") + .ofLongs() + .setUnit("1") + .setDescription("Listener status") + .build(); } public static LongCounter createMqUnauthorizedEvent(Meter meter) { - return meter.counterBuilder("mq.unauthorized.event").setUnit("{events}").setDescription("Number of authentication error events").build(); + return meter + .counterBuilder("mq.unauthorized.event") + .setUnit("{events}") + .setDescription("Number of authentication error events") + .build(); } public static LongGauge createMqManagerMaxHandles(Meter meter) { - return meter.gaugeBuilder("mq.manager.max.handles").ofLongs().setUnit("{events}").setDescription("Max open handles").build(); - } - -} \ No newline at end of file + return meter + .gaugeBuilder("mq.manager.max.handles") + .ofLongs() + .setUnit("{events}") + .setDescription("Max open handles") + .build(); + } +} 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 cac79ca47..1fe9fb337 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 @@ -2,6 +2,7 @@ * Copyright The OpenTelemetry Authors * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metrics; import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; @@ -15,10 +16,9 @@ public final class MetricsConfig { private final Map config; public MetricsConfig(ConfigWrapper config) { - this.config = config.getMetrics(); + this.config = config.getMetrics(); } - public boolean isMqMessageRetryCountEnabled() { return isEnabled("mq.message.retry.count"); } @@ -210,4 +210,4 @@ private boolean isEnabled(String key) { } return false; } -} \ No newline at end of file +} From 38a46f7b8c968bba796fb47e4198672acd89000e Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 13 Jun 2025 15:51:31 -0700 Subject: [PATCH 16/66] markdown fixes --- ibm-mq-metrics/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ibm-mq-metrics/README.md b/ibm-mq-metrics/README.md index 634edc4c7..7d4e61f74 100644 --- a/ibm-mq-metrics/README.md +++ b/ibm-mq-metrics/README.md @@ -17,18 +17,19 @@ The MQ Monitor is compatible with IBM MQ version 7.x, 8.x and 9.x. ## Prerequisites -### Build - This software requires compilation with Java 11. It targets language level 8 and outputs java 8 class files. The extension has a dependency on the following jar's depending on IBM MQ version: * v8.0.0 and above + ``` com.ibm.mq.allclient.jar ``` + * For other versions + ``` com.ibm.mq.commonservices.jar com.ibm.mq.jar From c8edae678785a970eec1b2bda526092880c82006 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 13 Jun 2025 15:52:10 -0700 Subject: [PATCH 17/66] markdown fixes --- ibm-mq-metrics/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ibm-mq-metrics/README.md b/ibm-mq-metrics/README.md index 7d4e61f74..cecdab8b4 100644 --- a/ibm-mq-metrics/README.md +++ b/ibm-mq-metrics/README.md @@ -149,8 +149,9 @@ config.yml file in src/main/resources/config.yml. ### Monitoring Workings - Internals -This software extracts metrics through [PCF framework](https://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.adm.doc/q019990_.htm). A complete list of PCF commands are -listed [here](https://www.ibm.com/support/knowledgecenter/SSFKSJ_7.5.0/com.ibm.mq.ref.adm.doc/q086870_.htm). Each queue manager has an administration queue with a standard queue name and +This software extracts metrics through [PCF framework](https://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.adm.doc/q019990_.htm). +[A complete list of PCF commands are listed here](https://www.ibm.com/support/knowledgecenter/SSFKSJ_7.5.0/com.ibm.mq.ref.adm.doc/q086870_.htm). +Each queue manager has an administration queue with a standard queue name and the extension sends PCF command messages to that queue. On Windows and Unix platforms, the PCF commands are sent is always sent to the SYSTEM.ADMIN.COMMAND.QUEUE queue. More details about that is mentioned [here](https://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.adm.doc/q020010_.htm) From 16227e8a65e05dd6c51e4afebb170d5128f19070 Mon Sep 17 00:00:00 2001 From: otelbot <197425009+otelbot@users.noreply.github.com> Date: Fri, 13 Jun 2025 22:53:22 +0000 Subject: [PATCH 18/66] ./gradlew spotlessApply --- ibm-mq-metrics/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ibm-mq-metrics/README.md b/ibm-mq-metrics/README.md index cecdab8b4..6dbfa3a3b 100644 --- a/ibm-mq-metrics/README.md +++ b/ibm-mq-metrics/README.md @@ -149,7 +149,7 @@ config.yml file in src/main/resources/config.yml. ### Monitoring Workings - Internals -This software extracts metrics through [PCF framework](https://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.adm.doc/q019990_.htm). +This software extracts metrics through [PCF framework](https://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.adm.doc/q019990_.htm). [A complete list of PCF commands are listed here](https://www.ibm.com/support/knowledgecenter/SSFKSJ_7.5.0/com.ibm.mq.ref.adm.doc/q086870_.htm). Each queue manager has an administration queue with a standard queue name and the extension sends PCF command messages to that queue. On Windows and Unix platforms, the PCF From 33d8c3a7458e61d3ade8b015397fc28e04a1e820 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 13 Jun 2025 15:54:13 -0700 Subject: [PATCH 19/66] markdown fixes --- ibm-mq-metrics/README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/ibm-mq-metrics/README.md b/ibm-mq-metrics/README.md index 6dbfa3a3b..da1ebad43 100644 --- a/ibm-mq-metrics/README.md +++ b/ibm-mq-metrics/README.md @@ -153,13 +153,13 @@ This software extracts metrics through [PCF framework](https://www.ibm.com/suppo [A complete list of PCF commands are listed here](https://www.ibm.com/support/knowledgecenter/SSFKSJ_7.5.0/com.ibm.mq.ref.adm.doc/q086870_.htm). Each queue manager has an administration queue with a standard queue name and the extension sends PCF command messages to that queue. On Windows and Unix platforms, the PCF -commands are sent is always sent to the SYSTEM.ADMIN.COMMAND.QUEUE queue. More details about that -is mentioned [here](https://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.adm.doc/q020010_.htm) +commands are sent is always sent to the SYSTEM.ADMIN.COMMAND.QUEUE queue. +[More details mentioned here](https://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.adm.doc/q020010_.htm) By default, the PCF responses are sent to the SYSTEM.DEFAULT.MODEL.QUEUE. Using this queue causes a temporary dynamic queue to be created. You can override the default here by using the `modelQueueName` and `replyQueuePrefix` fields in the config.yml. -More details mentioned [here](https://www.ibm.com/support/knowledgecenter/SSFKSJ_7.5.0/com.ibm.mq.ref.adm.doc/q083240_.htm) +[More details mentioned here](https://www.ibm.com/support/knowledgecenter/SSFKSJ_7.5.0/com.ibm.mq.ref.adm.doc/q083240_.htm) ## Metrics @@ -180,7 +180,7 @@ See [docs/metrics.md](docs/metrics.md). For more details, please check this [doc](https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.1.0/com.ibm.mq.doc/zr00610_.htm) - This might occour due to various reasons ranging from incorrect installation to applying [ibm fix packs](http://www-01.ibm.com/support/docview.wss?uid=swg21410038) but most of the time it happens when you are trying to connect in `Bindings` mode and machine agent is not on the same machine on which WMQ server is running. If you want to connect to WMQ server from a remote machine then connect using `Client` mode. + This might occur due to various reasons ranging from incorrect installation to applying [ibm fix packs](http://www-01.ibm.com/support/docview.wss?uid=swg21410038) but most of the time it happens when you are trying to connect in `Bindings` mode and machine agent is not on the same machine on which WMQ server is running. If you want to connect to WMQ server from a remote machine then connect using `Client` mode. Another way to get around this issue is to avoid using the Bindings mode. Connect using CLIENT transport type from a remote box. @@ -195,13 +195,16 @@ See [docs/metrics.md](docs/metrics.md). This could happen if unsupported cipherSuite is provided or JRE not having/enabled unlimited jurisdiction policy files. Please check SSL Support section. 6. If you are seeing "NoClassDefFoundError" or "ClassNotFound" error for any of the MQ dependency even after providing correct path in monitor.xml, then you can also try copying all the required jars in WMQMonitor (MAHome/monitors/WMQMonitor) folder and provide classpath in monitor.xml like below + ``` ibm-mq-monitoring--all.jar;com.ibm.mq.allclient.jar ``` OR + ``` ibm-mq-monitoring--all.jar;com.ibm.mq.jar;com.ibm.mq.jmqi.jar;com.ibm.mq.commonservices.jar;com.ibm.mq.headers.jar;com.ibm.mq.pcf.jar;connector.jar;dhbcore.jar ``` + ## Component Owners - [Antoine Toulme Sharma](https://github.com/atoulme), Splunk From c42c0cb664be206c3689edd7c4c48781b9c0e076 Mon Sep 17 00:00:00 2001 From: otelbot <197425009+otelbot@users.noreply.github.com> Date: Fri, 13 Jun 2025 22:57:14 +0000 Subject: [PATCH 20/66] ./gradlew spotlessApply --- ibm-mq-metrics/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ibm-mq-metrics/README.md b/ibm-mq-metrics/README.md index da1ebad43..368129928 100644 --- a/ibm-mq-metrics/README.md +++ b/ibm-mq-metrics/README.md @@ -153,7 +153,7 @@ This software extracts metrics through [PCF framework](https://www.ibm.com/suppo [A complete list of PCF commands are listed here](https://www.ibm.com/support/knowledgecenter/SSFKSJ_7.5.0/com.ibm.mq.ref.adm.doc/q086870_.htm). Each queue manager has an administration queue with a standard queue name and the extension sends PCF command messages to that queue. On Windows and Unix platforms, the PCF -commands are sent is always sent to the SYSTEM.ADMIN.COMMAND.QUEUE queue. +commands are sent is always sent to the SYSTEM.ADMIN.COMMAND.QUEUE queue. [More details mentioned here](https://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.adm.doc/q020010_.htm) By default, the PCF responses are sent to the SYSTEM.DEFAULT.MODEL.QUEUE. Using this queue causes From 2a7221879b86930edad8defc42a0b61eb8ea0e40 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 13 Jun 2025 15:58:14 -0700 Subject: [PATCH 21/66] markdown fixes --- ibm-mq-metrics/README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ibm-mq-metrics/README.md b/ibm-mq-metrics/README.md index 368129928..877e41c31 100644 --- a/ibm-mq-metrics/README.md +++ b/ibm-mq-metrics/README.md @@ -44,11 +44,12 @@ These jar files are typically found in ```/opt/mqm/java/lib``` on a UNIX server found in an alternate location depending upon your environment. In case of **CLIENT** transport type, IBM MQ Client must be installed to get the MQ jars. -To download IBM MQ Client jars, see [here](https://developer.ibm.com/messaging/mq-downloads/) +[The IBM MQ Client jars can be downloaded here](https://developer.ibm.com/messaging/mq-downloads/). ### MQ monitoring configuration This software reads events from event queues associated with the queue manager: + * `SYSTEM.ADMIN.PERFM.EVENT`: Performance events, such as low, high, and full queue depth events. * `SYSTEM.ADMIN.QMGR.EVENT`: Authority events * `SYSTEM.ADMIN.CONFIG.EVENT`: Configuration events @@ -58,6 +59,7 @@ Please turn on those events to take advantage of this monitoring. ## Build Build the package with: + ```shell ./gradlew shadowJar ``` @@ -82,6 +84,7 @@ java \ ## Connection There are two transport modes in which this extension can be run: + * **Binding** : Requires WMQ Extension to be deployed in machine agent on the same machine where WMQ server is installed. * **Client** : In this mode, the WMQ extension is installed on a different host than the IBM MQ @@ -166,6 +169,7 @@ a temporary dynamic queue to be created. You can override the default here by us See [docs/metrics.md](docs/metrics.md). ## Troubleshooting + 1. Please follow the steps listed in this [troubleshooting-document](https://community.appdynamics.com/t5/Knowledge-Base/How-to-troubleshoot-missing-custom-metrics-or-extensions-metrics/ta-p/28695) in order to troubleshoot your issue. These are a set of common issues that customers might have faced during the installation of the extension. 2. Error `Completion Code '2', Reason '2495'` Normally this error occurs if the environment variables are not set up correctly for this extension to work MQ in Bindings Mode. @@ -199,6 +203,7 @@ See [docs/metrics.md](docs/metrics.md). ``` ibm-mq-monitoring--all.jar;com.ibm.mq.allclient.jar ``` + OR ``` From 924799531efa95ee8d8062ce124e13158d8d0db4 Mon Sep 17 00:00:00 2001 From: otelbot <197425009+otelbot@users.noreply.github.com> Date: Fri, 13 Jun 2025 22:59:23 +0000 Subject: [PATCH 22/66] ./gradlew spotlessApply --- ibm-mq-metrics/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ibm-mq-metrics/README.md b/ibm-mq-metrics/README.md index 877e41c31..33794bdbe 100644 --- a/ibm-mq-metrics/README.md +++ b/ibm-mq-metrics/README.md @@ -49,7 +49,7 @@ In case of **CLIENT** transport type, IBM MQ Client must be installed to get the ### MQ monitoring configuration This software reads events from event queues associated with the queue manager: - + * `SYSTEM.ADMIN.PERFM.EVENT`: Performance events, such as low, high, and full queue depth events. * `SYSTEM.ADMIN.QMGR.EVENT`: Authority events * `SYSTEM.ADMIN.CONFIG.EVENT`: Configuration events @@ -84,7 +84,7 @@ java \ ## Connection There are two transport modes in which this extension can be run: - + * **Binding** : Requires WMQ Extension to be deployed in machine agent on the same machine where WMQ server is installed. * **Client** : In this mode, the WMQ extension is installed on a different host than the IBM MQ From c3538941ff0bc253f9bf65b85fd4597fc30e329d Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 13 Jun 2025 16:01:11 -0700 Subject: [PATCH 23/66] markdown fixes --- ibm-mq-metrics/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ibm-mq-metrics/README.md b/ibm-mq-metrics/README.md index 33794bdbe..8e98e1d4a 100644 --- a/ibm-mq-metrics/README.md +++ b/ibm-mq-metrics/README.md @@ -92,6 +92,7 @@ There are two transport modes in which this extension can be run: for this mode to get the necessary jars as mentioned previously. If this extension is configured for **CLIENT** transport type + 1. Please make sure the MQ's host and port is accessible. 2. Credentials of user with correct access rights would be needed in config.yml [(Access Permissions section)](https://github.com/signalfx/opentelemetry-ibm-mq-monitoring-extension#access-permissions). From 61dfb1d67395a9149ab5012e72de7f71321ea2d7 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 13 Jun 2025 16:07:37 -0700 Subject: [PATCH 24/66] generated classes fixes --- .../opentelemetry/ibm/mq/metrics/Metrics.java | 320 +++--------------- .../ibm/mq/metrics/MetricsConfig.java | 5 +- .../templates/registry/java/Metrics.java.j2 | 2 + .../registry/java/MetricsConfig.java.j2 | 1 - 4 files changed, 53 insertions(+), 275 deletions(-) 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 4d64f27b9..5f9894ddd 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 @@ -2,7 +2,6 @@ * Copyright The OpenTelemetry Authors * SPDX-License-Identifier: Apache-2.0 */ - package io.opentelemetry.ibm.mq.metrics; import io.opentelemetry.api.metrics.LongCounter; @@ -13,408 +12,187 @@ /** Metric definitions generated from a Weaver model. Do not edit manually. */ public final class Metrics { +private Metrics(){ +} public static LongGauge createMqMessageRetryCount(Meter meter) { - return meter - .gaugeBuilder("mq.message.retry.count") - .ofLongs() - .setUnit("{messages}") - .setDescription("Number of message retries") - .build(); + return meter.gaugeBuilder("mq.message.retry.count").ofLongs().setUnit("{messages}").setDescription("Number of message retries").build(); } public static LongGauge createMqStatus(Meter meter) { - return meter - .gaugeBuilder("mq.status") - .ofLongs() - .setUnit("1") - .setDescription("Channel status") - .build(); + return meter.gaugeBuilder("mq.status").ofLongs().setUnit("1").setDescription("Channel status").build(); } public static LongGauge createMqMaxSharingConversations(Meter meter) { - return meter - .gaugeBuilder("mq.max.sharing.conversations") - .ofLongs() - .setUnit("{conversations}") - .setDescription("Maximum number of conversations permitted on this channel instance.") - .build(); + return meter.gaugeBuilder("mq.max.sharing.conversations").ofLongs().setUnit("{conversations}").setDescription("Maximum number of conversations permitted on this channel instance.").build(); } public static LongGauge createMqCurrentSharingConversations(Meter meter) { - return meter - .gaugeBuilder("mq.current.sharing.conversations") - .ofLongs() - .setUnit("{conversations}") - .setDescription("Current number of conversations permitted on this channel instance.") - .build(); + return meter.gaugeBuilder("mq.current.sharing.conversations").ofLongs().setUnit("{conversations}").setDescription("Current number of conversations permitted on this channel instance.").build(); } public static LongGauge createMqByteReceived(Meter meter) { - return meter - .gaugeBuilder("mq.byte.received") - .ofLongs() - .setUnit("{bytes}") - .setDescription("Number of bytes received") - .build(); + return meter.gaugeBuilder("mq.byte.received").ofLongs().setUnit("{bytes}").setDescription("Number of bytes received").build(); } public static LongGauge createMqByteSent(Meter meter) { - return meter - .gaugeBuilder("mq.byte.sent") - .ofLongs() - .setUnit("{bytes}") - .setDescription("Number of bytes sent") - .build(); + return meter.gaugeBuilder("mq.byte.sent").ofLongs().setUnit("{bytes}").setDescription("Number of bytes sent").build(); } public static LongGauge createMqBuffersReceived(Meter meter) { - return meter - .gaugeBuilder("mq.buffers.received") - .ofLongs() - .setUnit("{buffers}") - .setDescription("Buffers received") - .build(); + return meter.gaugeBuilder("mq.buffers.received").ofLongs().setUnit("{buffers}").setDescription("Buffers received").build(); } public static LongGauge createMqBuffersSent(Meter meter) { - return meter - .gaugeBuilder("mq.buffers.sent") - .ofLongs() - .setUnit("{buffers}") - .setDescription("Buffers sent") - .build(); + return meter.gaugeBuilder("mq.buffers.sent").ofLongs().setUnit("{buffers}").setDescription("Buffers sent").build(); } public static LongGauge createMqMessageCount(Meter meter) { - return meter - .gaugeBuilder("mq.message.count") - .ofLongs() - .setUnit("{messages}") - .setDescription("Message count") - .build(); + return meter.gaugeBuilder("mq.message.count").ofLongs().setUnit("{messages}").setDescription("Message count").build(); } public static LongGauge createMqOpenInputCount(Meter meter) { - return meter - .gaugeBuilder("mq.open.input.count") - .ofLongs() - .setUnit("{applications}") - .setDescription("Count of applications sending messages to the queue") - .build(); + return meter.gaugeBuilder("mq.open.input.count").ofLongs().setUnit("{applications}").setDescription("Count of applications sending messages to the queue").build(); } public static LongGauge createMqOpenOutputCount(Meter meter) { - return meter - .gaugeBuilder("mq.open.output.count") - .ofLongs() - .setUnit("{applications}") - .setDescription("Count of applications consuming messages from the queue") - .build(); + return meter.gaugeBuilder("mq.open.output.count").ofLongs().setUnit("{applications}").setDescription("Count of applications consuming messages from the queue").build(); } public static LongGauge createMqHighQueueDepth(Meter meter) { - return meter - .gaugeBuilder("mq.high.queue.depth") - .ofLongs() - .setUnit("{percent}") - .setDescription("The current high queue depth") - .build(); + return meter.gaugeBuilder("mq.high.queue.depth").ofLongs().setUnit("{percent}").setDescription("The current high queue depth").build(); } public static LongGauge createMqServiceInterval(Meter meter) { - return meter - .gaugeBuilder("mq.service.interval") - .ofLongs() - .setUnit("{percent}") - .setDescription("The queue service interval") - .build(); + return meter.gaugeBuilder("mq.service.interval").ofLongs().setUnit("{percent}").setDescription("The queue service interval").build(); } public static LongCounter createMqQueueDepthFullEvent(Meter meter) { - return meter - .counterBuilder("mq.queue.depth.full.event") - .setUnit("{events}") - .setDescription("The number of full queue events") - .build(); + return meter.counterBuilder("mq.queue.depth.full.event").setUnit("{events}").setDescription("The number of full queue events").build(); } public static LongCounter createMqQueueDepthHighEvent(Meter meter) { - return meter - .counterBuilder("mq.queue.depth.high.event") - .setUnit("{events}") - .setDescription("The number of high queue events") - .build(); + return meter.counterBuilder("mq.queue.depth.high.event").setUnit("{events}").setDescription("The number of high queue events").build(); } public static LongCounter createMqQueueDepthLowEvent(Meter meter) { - return meter - .counterBuilder("mq.queue.depth.low.event") - .setUnit("{events}") - .setDescription("The number of low queue events") - .build(); + return meter.counterBuilder("mq.queue.depth.low.event").setUnit("{events}").setDescription("The number of low queue events").build(); } public static LongGauge createMqUncommittedMessages(Meter meter) { - return meter - .gaugeBuilder("mq.uncommitted.messages") - .ofLongs() - .setUnit("{messages}") - .setDescription("Number of uncommitted messages") - .build(); + return meter.gaugeBuilder("mq.uncommitted.messages").ofLongs().setUnit("{messages}").setDescription("Number of uncommitted messages").build(); } public static LongGauge createMqOldestMsgAge(Meter meter) { - return meter - .gaugeBuilder("mq.oldest.msg.age") - .ofLongs() - .setUnit("microseconds") - .setDescription("Queue message oldest age") - .build(); + return meter.gaugeBuilder("mq.oldest.msg.age").ofLongs().setUnit("microseconds").setDescription("Queue message oldest age").build(); } public static LongGauge createMqCurrentMaxQueueFilesize(Meter meter) { - return meter - .gaugeBuilder("mq.current.max.queue.filesize") - .ofLongs() - .setUnit("mib") - .setDescription("Current maximum queue file size") - .build(); + return meter.gaugeBuilder("mq.current.max.queue.filesize").ofLongs().setUnit("mib").setDescription("Current maximum queue file size").build(); } public static LongGauge createMqCurrentQueueFilesize(Meter meter) { - return meter - .gaugeBuilder("mq.current.queue.filesize") - .ofLongs() - .setUnit("mib") - .setDescription("Current queue file size") - .build(); + return meter.gaugeBuilder("mq.current.queue.filesize").ofLongs().setUnit("mib").setDescription("Current queue file size").build(); } public static LongGauge createMqInstancesPerClient(Meter meter) { - return meter - .gaugeBuilder("mq.instances.per.client") - .ofLongs() - .setUnit("{instances}") - .setDescription("Instances per client") - .build(); + return meter.gaugeBuilder("mq.instances.per.client").ofLongs().setUnit("{instances}").setDescription("Instances per client").build(); } public static LongGauge createMqMessageDeqCount(Meter meter) { - return meter - .gaugeBuilder("mq.message.deq.count") - .ofLongs() - .setUnit("{messages}") - .setDescription("Message dequeue count") - .build(); + return meter.gaugeBuilder("mq.message.deq.count").ofLongs().setUnit("{messages}").setDescription("Message dequeue count").build(); } public static LongGauge createMqMessageEnqCount(Meter meter) { - return meter - .gaugeBuilder("mq.message.enq.count") - .ofLongs() - .setUnit("{messages}") - .setDescription("Message enqueue count") - .build(); + return meter.gaugeBuilder("mq.message.enq.count").ofLongs().setUnit("{messages}").setDescription("Message enqueue count").build(); } public static LongGauge createMqQueueDepth(Meter meter) { - return meter - .gaugeBuilder("mq.queue.depth") - .ofLongs() - .setUnit("{messages}") - .setDescription("Current queue depth") - .build(); + return meter.gaugeBuilder("mq.queue.depth").ofLongs().setUnit("{messages}").setDescription("Current queue depth").build(); } public static LongGauge createMqServiceIntervalEvent(Meter meter) { - return meter - .gaugeBuilder("mq.service.interval.event") - .ofLongs() - .setUnit("1") - .setDescription("Queue service interval event") - .build(); + return meter.gaugeBuilder("mq.service.interval.event").ofLongs().setUnit("1").setDescription("Queue service interval event").build(); } public static LongGauge createMqReusableLogSize(Meter meter) { - return meter - .gaugeBuilder("mq.reusable.log.size") - .ofLongs() - .setUnit("mib") - .setDescription( - "The amount of space occupied, in megabytes, by log extents available to be reused.") - .build(); + return meter.gaugeBuilder("mq.reusable.log.size").ofLongs().setUnit("mib").setDescription("The amount of space occupied, in megabytes, by log extents available to be reused.").build(); } public static LongGauge createMqManagerActiveChannels(Meter meter) { - return meter - .gaugeBuilder("mq.manager.active.channels") - .ofLongs() - .setUnit("{channels}") - .setDescription("The queue manager active maximum channels limit") - .build(); + return meter.gaugeBuilder("mq.manager.active.channels").ofLongs().setUnit("{channels}").setDescription("The queue manager active maximum channels limit").build(); } public static LongGauge createMqRestartLogSize(Meter meter) { - return meter - .gaugeBuilder("mq.restart.log.size") - .ofLongs() - .setUnit("mib") - .setDescription("Size of the log data required for restart recovery in megabytes.") - .build(); + return meter.gaugeBuilder("mq.restart.log.size").ofLongs().setUnit("mib").setDescription("Size of the log data required for restart recovery in megabytes.").build(); } public static LongGauge createMqMaxQueueDepth(Meter meter) { - return meter - .gaugeBuilder("mq.max.queue.depth") - .ofLongs() - .setUnit("{messages}") - .setDescription("Maximum queue depth") - .build(); + return meter.gaugeBuilder("mq.max.queue.depth").ofLongs().setUnit("{messages}").setDescription("Maximum queue depth").build(); } public static LongGauge createMqOnqtime1(Meter meter) { - return meter - .gaugeBuilder("mq.onqtime.1") - .ofLongs() - .setUnit("microseconds") - .setDescription( - "Amount of time, in microseconds, that a message spent on the queue, over a short period") - .build(); + return meter.gaugeBuilder("mq.onqtime.1").ofLongs().setUnit("microseconds").setDescription("Amount of time, in microseconds, that a message spent on the queue, over a short period").build(); } public static LongGauge createMqOnqtime2(Meter meter) { - return meter - .gaugeBuilder("mq.onqtime.2") - .ofLongs() - .setUnit("microseconds") - .setDescription( - "Amount of time, in microseconds, that a message spent on the queue, over a longer period") - .build(); + return meter.gaugeBuilder("mq.onqtime.2").ofLongs().setUnit("microseconds").setDescription("Amount of time, in microseconds, that a message spent on the queue, over a longer period").build(); } public static LongGauge createMqMessageReceivedCount(Meter meter) { - return meter - .gaugeBuilder("mq.message.received.count") - .ofLongs() - .setUnit("{messages}") - .setDescription("Number of messages received") - .build(); + return meter.gaugeBuilder("mq.message.received.count").ofLongs().setUnit("{messages}").setDescription("Number of messages received").build(); } public static LongGauge createMqMessageSentCount(Meter meter) { - return meter - .gaugeBuilder("mq.message.sent.count") - .ofLongs() - .setUnit("{messages}") - .setDescription("Number of messages sent") - .build(); + return meter.gaugeBuilder("mq.message.sent.count").ofLongs().setUnit("{messages}").setDescription("Number of messages sent").build(); } public static LongGauge createMqMaxInstances(Meter meter) { - return meter - .gaugeBuilder("mq.max.instances") - .ofLongs() - .setUnit("{instances}") - .setDescription("Max channel instances") - .build(); + return meter.gaugeBuilder("mq.max.instances").ofLongs().setUnit("{instances}").setDescription("Max channel instances").build(); } public static LongGauge createMqConnectionCount(Meter meter) { - return meter - .gaugeBuilder("mq.connection.count") - .ofLongs() - .setUnit("{connections}") - .setDescription("Active connections count") - .build(); + return meter.gaugeBuilder("mq.connection.count").ofLongs().setUnit("{connections}").setDescription("Active connections count").build(); } public static LongGauge createMqManagerStatus(Meter meter) { - return meter - .gaugeBuilder("mq.manager.status") - .ofLongs() - .setUnit("1") - .setDescription("Queue manager status") - .build(); + return meter.gaugeBuilder("mq.manager.status").ofLongs().setUnit("1").setDescription("Queue manager status").build(); } public static LongGauge createMqHeartbeat(Meter meter) { - return meter - .gaugeBuilder("mq.heartbeat") - .ofLongs() - .setUnit("1") - .setDescription("Queue manager heartbeat") - .build(); + return meter.gaugeBuilder("mq.heartbeat").ofLongs().setUnit("1").setDescription("Queue manager heartbeat").build(); } public static LongGauge createMqArchiveLogSize(Meter meter) { - return meter - .gaugeBuilder("mq.archive.log.size") - .ofLongs() - .setUnit("mib") - .setDescription("Queue manager archive log size") - .build(); + return meter.gaugeBuilder("mq.archive.log.size").ofLongs().setUnit("mib").setDescription("Queue manager archive log size").build(); } public static LongGauge createMqManagerMaxActiveChannels(Meter meter) { - return meter - .gaugeBuilder("mq.manager.max.active.channels") - .ofLongs() - .setUnit("{channels}") - .setDescription("Queue manager max active channels") - .build(); + return meter.gaugeBuilder("mq.manager.max.active.channels").ofLongs().setUnit("{channels}").setDescription("Queue manager max active channels").build(); } public static LongGauge createMqManagerStatisticsInterval(Meter meter) { - return meter - .gaugeBuilder("mq.manager.statistics.interval") - .ofLongs() - .setUnit("1") - .setDescription("Queue manager statistics interval") - .build(); + return meter.gaugeBuilder("mq.manager.statistics.interval").ofLongs().setUnit("1").setDescription("Queue manager statistics interval").build(); } public static LongGauge createMqPublishCount(Meter meter) { - return meter - .gaugeBuilder("mq.publish.count") - .ofLongs() - .setUnit("{publications}") - .setDescription("Topic publication count") - .build(); + return meter.gaugeBuilder("mq.publish.count").ofLongs().setUnit("{publications}").setDescription("Topic publication count").build(); } public static LongGauge createMqSubscriptionCount(Meter meter) { - return meter - .gaugeBuilder("mq.subscription.count") - .ofLongs() - .setUnit("{subscriptions}") - .setDescription("Topic subscription count") - .build(); + return meter.gaugeBuilder("mq.subscription.count").ofLongs().setUnit("{subscriptions}").setDescription("Topic subscription count").build(); } public static LongGauge createMqListenerStatus(Meter meter) { - return meter - .gaugeBuilder("mq.listener.status") - .ofLongs() - .setUnit("1") - .setDescription("Listener status") - .build(); + return meter.gaugeBuilder("mq.listener.status").ofLongs().setUnit("1").setDescription("Listener status").build(); } public static LongCounter createMqUnauthorizedEvent(Meter meter) { - return meter - .counterBuilder("mq.unauthorized.event") - .setUnit("{events}") - .setDescription("Number of authentication error events") - .build(); + return meter.counterBuilder("mq.unauthorized.event").setUnit("{events}").setDescription("Number of authentication error events").build(); } public static LongGauge createMqManagerMaxHandles(Meter meter) { - return meter - .gaugeBuilder("mq.manager.max.handles") - .ofLongs() - .setUnit("{events}") - .setDescription("Max open handles") - .build(); + return meter.gaugeBuilder("mq.manager.max.handles").ofLongs().setUnit("{events}").setDescription("Max open handles").build(); } -} + +} \ No newline at end of file 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 1fe9fb337..f0b53ab14 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 @@ -2,7 +2,6 @@ * Copyright The OpenTelemetry Authors * SPDX-License-Identifier: Apache-2.0 */ - package io.opentelemetry.ibm.mq.metrics; import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; @@ -16,7 +15,7 @@ public final class MetricsConfig { private final Map config; public MetricsConfig(ConfigWrapper config) { - this.config = config.getMetrics(); + this.config = config.getMetrics(); } public boolean isMqMessageRetryCountEnabled() { @@ -210,4 +209,4 @@ private boolean isEnabled(String key) { } return false; } -} +} \ No newline at end of file diff --git a/ibm-mq-metrics/templates/registry/java/Metrics.java.j2 b/ibm-mq-metrics/templates/registry/java/Metrics.java.j2 index 834343df7..c342859b2 100644 --- a/ibm-mq-metrics/templates/registry/java/Metrics.java.j2 +++ b/ibm-mq-metrics/templates/registry/java/Metrics.java.j2 @@ -12,6 +12,8 @@ import io.opentelemetry.api.metrics.Meter; /** Metric definitions generated from a Weaver model. Do not edit manually. */ public final class Metrics { +private Metrics(){ +} {% for metric in ctx %} public static {% if metric.instrument == "gauge" %}LongGauge{% elif metric.instrument == "counter" %}LongCounter{% endif %} create{{ metric.metric_name.split('.')|map('capitalize')|join }}(Meter meter) { return meter.{% if metric.instrument == "gauge" %}gauge{% elif metric.instrument == "counter" %}counter{% endif %}Builder("{{ metric.metric_name }}").{% if metric.instrument == "gauge" %}ofLongs().{% endif %}setUnit("{{ metric.unit }}").setDescription("{{ metric.brief }}").build(); diff --git a/ibm-mq-metrics/templates/registry/java/MetricsConfig.java.j2 b/ibm-mq-metrics/templates/registry/java/MetricsConfig.java.j2 index 2a5992308..7c17bbb25 100644 --- a/ibm-mq-metrics/templates/registry/java/MetricsConfig.java.j2 +++ b/ibm-mq-metrics/templates/registry/java/MetricsConfig.java.j2 @@ -17,7 +17,6 @@ public final class MetricsConfig { public MetricsConfig(ConfigWrapper config) { this.config = config.getMetrics(); } - {% for metric in ctx %} public boolean is{{ metric.metric_name.split('.')|map('capitalize')|join }}Enabled() { return isEnabled("{{ metric.metric_name }}"); From b33e85a699f8b54d3cde5b435e189837a5b87302 Mon Sep 17 00:00:00 2001 From: otelbot <197425009+otelbot@users.noreply.github.com> Date: Fri, 13 Jun 2025 23:08:45 +0000 Subject: [PATCH 25/66] ./gradlew spotlessApply --- .../opentelemetry/ibm/mq/metrics/Metrics.java | 321 +++++++++++++++--- .../ibm/mq/metrics/MetricsConfig.java | 5 +- 2 files changed, 275 insertions(+), 51 deletions(-) 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 5f9894ddd..1878e9205 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 @@ -2,6 +2,7 @@ * Copyright The OpenTelemetry Authors * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metrics; import io.opentelemetry.api.metrics.LongCounter; @@ -12,187 +13,409 @@ /** Metric definitions generated from a Weaver model. Do not edit manually. */ public final class Metrics { -private Metrics(){ -} + private Metrics() {} public static LongGauge createMqMessageRetryCount(Meter meter) { - return meter.gaugeBuilder("mq.message.retry.count").ofLongs().setUnit("{messages}").setDescription("Number of message retries").build(); + return meter + .gaugeBuilder("mq.message.retry.count") + .ofLongs() + .setUnit("{messages}") + .setDescription("Number of message retries") + .build(); } public static LongGauge createMqStatus(Meter meter) { - return meter.gaugeBuilder("mq.status").ofLongs().setUnit("1").setDescription("Channel status").build(); + return meter + .gaugeBuilder("mq.status") + .ofLongs() + .setUnit("1") + .setDescription("Channel status") + .build(); } public static LongGauge createMqMaxSharingConversations(Meter meter) { - return meter.gaugeBuilder("mq.max.sharing.conversations").ofLongs().setUnit("{conversations}").setDescription("Maximum number of conversations permitted on this channel instance.").build(); + return meter + .gaugeBuilder("mq.max.sharing.conversations") + .ofLongs() + .setUnit("{conversations}") + .setDescription("Maximum number of conversations permitted on this channel instance.") + .build(); } public static LongGauge createMqCurrentSharingConversations(Meter meter) { - return meter.gaugeBuilder("mq.current.sharing.conversations").ofLongs().setUnit("{conversations}").setDescription("Current number of conversations permitted on this channel instance.").build(); + return meter + .gaugeBuilder("mq.current.sharing.conversations") + .ofLongs() + .setUnit("{conversations}") + .setDescription("Current number of conversations permitted on this channel instance.") + .build(); } public static LongGauge createMqByteReceived(Meter meter) { - return meter.gaugeBuilder("mq.byte.received").ofLongs().setUnit("{bytes}").setDescription("Number of bytes received").build(); + return meter + .gaugeBuilder("mq.byte.received") + .ofLongs() + .setUnit("{bytes}") + .setDescription("Number of bytes received") + .build(); } public static LongGauge createMqByteSent(Meter meter) { - return meter.gaugeBuilder("mq.byte.sent").ofLongs().setUnit("{bytes}").setDescription("Number of bytes sent").build(); + return meter + .gaugeBuilder("mq.byte.sent") + .ofLongs() + .setUnit("{bytes}") + .setDescription("Number of bytes sent") + .build(); } public static LongGauge createMqBuffersReceived(Meter meter) { - return meter.gaugeBuilder("mq.buffers.received").ofLongs().setUnit("{buffers}").setDescription("Buffers received").build(); + return meter + .gaugeBuilder("mq.buffers.received") + .ofLongs() + .setUnit("{buffers}") + .setDescription("Buffers received") + .build(); } public static LongGauge createMqBuffersSent(Meter meter) { - return meter.gaugeBuilder("mq.buffers.sent").ofLongs().setUnit("{buffers}").setDescription("Buffers sent").build(); + return meter + .gaugeBuilder("mq.buffers.sent") + .ofLongs() + .setUnit("{buffers}") + .setDescription("Buffers sent") + .build(); } public static LongGauge createMqMessageCount(Meter meter) { - return meter.gaugeBuilder("mq.message.count").ofLongs().setUnit("{messages}").setDescription("Message count").build(); + return meter + .gaugeBuilder("mq.message.count") + .ofLongs() + .setUnit("{messages}") + .setDescription("Message count") + .build(); } public static LongGauge createMqOpenInputCount(Meter meter) { - return meter.gaugeBuilder("mq.open.input.count").ofLongs().setUnit("{applications}").setDescription("Count of applications sending messages to the queue").build(); + return meter + .gaugeBuilder("mq.open.input.count") + .ofLongs() + .setUnit("{applications}") + .setDescription("Count of applications sending messages to the queue") + .build(); } public static LongGauge createMqOpenOutputCount(Meter meter) { - return meter.gaugeBuilder("mq.open.output.count").ofLongs().setUnit("{applications}").setDescription("Count of applications consuming messages from the queue").build(); + return meter + .gaugeBuilder("mq.open.output.count") + .ofLongs() + .setUnit("{applications}") + .setDescription("Count of applications consuming messages from the queue") + .build(); } public static LongGauge createMqHighQueueDepth(Meter meter) { - return meter.gaugeBuilder("mq.high.queue.depth").ofLongs().setUnit("{percent}").setDescription("The current high queue depth").build(); + return meter + .gaugeBuilder("mq.high.queue.depth") + .ofLongs() + .setUnit("{percent}") + .setDescription("The current high queue depth") + .build(); } public static LongGauge createMqServiceInterval(Meter meter) { - return meter.gaugeBuilder("mq.service.interval").ofLongs().setUnit("{percent}").setDescription("The queue service interval").build(); + return meter + .gaugeBuilder("mq.service.interval") + .ofLongs() + .setUnit("{percent}") + .setDescription("The queue service interval") + .build(); } public static LongCounter createMqQueueDepthFullEvent(Meter meter) { - return meter.counterBuilder("mq.queue.depth.full.event").setUnit("{events}").setDescription("The number of full queue events").build(); + return meter + .counterBuilder("mq.queue.depth.full.event") + .setUnit("{events}") + .setDescription("The number of full queue events") + .build(); } public static LongCounter createMqQueueDepthHighEvent(Meter meter) { - return meter.counterBuilder("mq.queue.depth.high.event").setUnit("{events}").setDescription("The number of high queue events").build(); + return meter + .counterBuilder("mq.queue.depth.high.event") + .setUnit("{events}") + .setDescription("The number of high queue events") + .build(); } public static LongCounter createMqQueueDepthLowEvent(Meter meter) { - return meter.counterBuilder("mq.queue.depth.low.event").setUnit("{events}").setDescription("The number of low queue events").build(); + return meter + .counterBuilder("mq.queue.depth.low.event") + .setUnit("{events}") + .setDescription("The number of low queue events") + .build(); } public static LongGauge createMqUncommittedMessages(Meter meter) { - return meter.gaugeBuilder("mq.uncommitted.messages").ofLongs().setUnit("{messages}").setDescription("Number of uncommitted messages").build(); + return meter + .gaugeBuilder("mq.uncommitted.messages") + .ofLongs() + .setUnit("{messages}") + .setDescription("Number of uncommitted messages") + .build(); } public static LongGauge createMqOldestMsgAge(Meter meter) { - return meter.gaugeBuilder("mq.oldest.msg.age").ofLongs().setUnit("microseconds").setDescription("Queue message oldest age").build(); + return meter + .gaugeBuilder("mq.oldest.msg.age") + .ofLongs() + .setUnit("microseconds") + .setDescription("Queue message oldest age") + .build(); } public static LongGauge createMqCurrentMaxQueueFilesize(Meter meter) { - return meter.gaugeBuilder("mq.current.max.queue.filesize").ofLongs().setUnit("mib").setDescription("Current maximum queue file size").build(); + return meter + .gaugeBuilder("mq.current.max.queue.filesize") + .ofLongs() + .setUnit("mib") + .setDescription("Current maximum queue file size") + .build(); } public static LongGauge createMqCurrentQueueFilesize(Meter meter) { - return meter.gaugeBuilder("mq.current.queue.filesize").ofLongs().setUnit("mib").setDescription("Current queue file size").build(); + return meter + .gaugeBuilder("mq.current.queue.filesize") + .ofLongs() + .setUnit("mib") + .setDescription("Current queue file size") + .build(); } public static LongGauge createMqInstancesPerClient(Meter meter) { - return meter.gaugeBuilder("mq.instances.per.client").ofLongs().setUnit("{instances}").setDescription("Instances per client").build(); + return meter + .gaugeBuilder("mq.instances.per.client") + .ofLongs() + .setUnit("{instances}") + .setDescription("Instances per client") + .build(); } public static LongGauge createMqMessageDeqCount(Meter meter) { - return meter.gaugeBuilder("mq.message.deq.count").ofLongs().setUnit("{messages}").setDescription("Message dequeue count").build(); + return meter + .gaugeBuilder("mq.message.deq.count") + .ofLongs() + .setUnit("{messages}") + .setDescription("Message dequeue count") + .build(); } public static LongGauge createMqMessageEnqCount(Meter meter) { - return meter.gaugeBuilder("mq.message.enq.count").ofLongs().setUnit("{messages}").setDescription("Message enqueue count").build(); + return meter + .gaugeBuilder("mq.message.enq.count") + .ofLongs() + .setUnit("{messages}") + .setDescription("Message enqueue count") + .build(); } public static LongGauge createMqQueueDepth(Meter meter) { - return meter.gaugeBuilder("mq.queue.depth").ofLongs().setUnit("{messages}").setDescription("Current queue depth").build(); + return meter + .gaugeBuilder("mq.queue.depth") + .ofLongs() + .setUnit("{messages}") + .setDescription("Current queue depth") + .build(); } public static LongGauge createMqServiceIntervalEvent(Meter meter) { - return meter.gaugeBuilder("mq.service.interval.event").ofLongs().setUnit("1").setDescription("Queue service interval event").build(); + return meter + .gaugeBuilder("mq.service.interval.event") + .ofLongs() + .setUnit("1") + .setDescription("Queue service interval event") + .build(); } public static LongGauge createMqReusableLogSize(Meter meter) { - return meter.gaugeBuilder("mq.reusable.log.size").ofLongs().setUnit("mib").setDescription("The amount of space occupied, in megabytes, by log extents available to be reused.").build(); + return meter + .gaugeBuilder("mq.reusable.log.size") + .ofLongs() + .setUnit("mib") + .setDescription( + "The amount of space occupied, in megabytes, by log extents available to be reused.") + .build(); } public static LongGauge createMqManagerActiveChannels(Meter meter) { - return meter.gaugeBuilder("mq.manager.active.channels").ofLongs().setUnit("{channels}").setDescription("The queue manager active maximum channels limit").build(); + return meter + .gaugeBuilder("mq.manager.active.channels") + .ofLongs() + .setUnit("{channels}") + .setDescription("The queue manager active maximum channels limit") + .build(); } public static LongGauge createMqRestartLogSize(Meter meter) { - return meter.gaugeBuilder("mq.restart.log.size").ofLongs().setUnit("mib").setDescription("Size of the log data required for restart recovery in megabytes.").build(); + return meter + .gaugeBuilder("mq.restart.log.size") + .ofLongs() + .setUnit("mib") + .setDescription("Size of the log data required for restart recovery in megabytes.") + .build(); } public static LongGauge createMqMaxQueueDepth(Meter meter) { - return meter.gaugeBuilder("mq.max.queue.depth").ofLongs().setUnit("{messages}").setDescription("Maximum queue depth").build(); + return meter + .gaugeBuilder("mq.max.queue.depth") + .ofLongs() + .setUnit("{messages}") + .setDescription("Maximum queue depth") + .build(); } public static LongGauge createMqOnqtime1(Meter meter) { - return meter.gaugeBuilder("mq.onqtime.1").ofLongs().setUnit("microseconds").setDescription("Amount of time, in microseconds, that a message spent on the queue, over a short period").build(); + return meter + .gaugeBuilder("mq.onqtime.1") + .ofLongs() + .setUnit("microseconds") + .setDescription( + "Amount of time, in microseconds, that a message spent on the queue, over a short period") + .build(); } public static LongGauge createMqOnqtime2(Meter meter) { - return meter.gaugeBuilder("mq.onqtime.2").ofLongs().setUnit("microseconds").setDescription("Amount of time, in microseconds, that a message spent on the queue, over a longer period").build(); + return meter + .gaugeBuilder("mq.onqtime.2") + .ofLongs() + .setUnit("microseconds") + .setDescription( + "Amount of time, in microseconds, that a message spent on the queue, over a longer period") + .build(); } public static LongGauge createMqMessageReceivedCount(Meter meter) { - return meter.gaugeBuilder("mq.message.received.count").ofLongs().setUnit("{messages}").setDescription("Number of messages received").build(); + return meter + .gaugeBuilder("mq.message.received.count") + .ofLongs() + .setUnit("{messages}") + .setDescription("Number of messages received") + .build(); } public static LongGauge createMqMessageSentCount(Meter meter) { - return meter.gaugeBuilder("mq.message.sent.count").ofLongs().setUnit("{messages}").setDescription("Number of messages sent").build(); + return meter + .gaugeBuilder("mq.message.sent.count") + .ofLongs() + .setUnit("{messages}") + .setDescription("Number of messages sent") + .build(); } public static LongGauge createMqMaxInstances(Meter meter) { - return meter.gaugeBuilder("mq.max.instances").ofLongs().setUnit("{instances}").setDescription("Max channel instances").build(); + return meter + .gaugeBuilder("mq.max.instances") + .ofLongs() + .setUnit("{instances}") + .setDescription("Max channel instances") + .build(); } public static LongGauge createMqConnectionCount(Meter meter) { - return meter.gaugeBuilder("mq.connection.count").ofLongs().setUnit("{connections}").setDescription("Active connections count").build(); + return meter + .gaugeBuilder("mq.connection.count") + .ofLongs() + .setUnit("{connections}") + .setDescription("Active connections count") + .build(); } public static LongGauge createMqManagerStatus(Meter meter) { - return meter.gaugeBuilder("mq.manager.status").ofLongs().setUnit("1").setDescription("Queue manager status").build(); + return meter + .gaugeBuilder("mq.manager.status") + .ofLongs() + .setUnit("1") + .setDescription("Queue manager status") + .build(); } public static LongGauge createMqHeartbeat(Meter meter) { - return meter.gaugeBuilder("mq.heartbeat").ofLongs().setUnit("1").setDescription("Queue manager heartbeat").build(); + return meter + .gaugeBuilder("mq.heartbeat") + .ofLongs() + .setUnit("1") + .setDescription("Queue manager heartbeat") + .build(); } public static LongGauge createMqArchiveLogSize(Meter meter) { - return meter.gaugeBuilder("mq.archive.log.size").ofLongs().setUnit("mib").setDescription("Queue manager archive log size").build(); + return meter + .gaugeBuilder("mq.archive.log.size") + .ofLongs() + .setUnit("mib") + .setDescription("Queue manager archive log size") + .build(); } public static LongGauge createMqManagerMaxActiveChannels(Meter meter) { - return meter.gaugeBuilder("mq.manager.max.active.channels").ofLongs().setUnit("{channels}").setDescription("Queue manager max active channels").build(); + return meter + .gaugeBuilder("mq.manager.max.active.channels") + .ofLongs() + .setUnit("{channels}") + .setDescription("Queue manager max active channels") + .build(); } public static LongGauge createMqManagerStatisticsInterval(Meter meter) { - return meter.gaugeBuilder("mq.manager.statistics.interval").ofLongs().setUnit("1").setDescription("Queue manager statistics interval").build(); + return meter + .gaugeBuilder("mq.manager.statistics.interval") + .ofLongs() + .setUnit("1") + .setDescription("Queue manager statistics interval") + .build(); } public static LongGauge createMqPublishCount(Meter meter) { - return meter.gaugeBuilder("mq.publish.count").ofLongs().setUnit("{publications}").setDescription("Topic publication count").build(); + return meter + .gaugeBuilder("mq.publish.count") + .ofLongs() + .setUnit("{publications}") + .setDescription("Topic publication count") + .build(); } public static LongGauge createMqSubscriptionCount(Meter meter) { - return meter.gaugeBuilder("mq.subscription.count").ofLongs().setUnit("{subscriptions}").setDescription("Topic subscription count").build(); + return meter + .gaugeBuilder("mq.subscription.count") + .ofLongs() + .setUnit("{subscriptions}") + .setDescription("Topic subscription count") + .build(); } public static LongGauge createMqListenerStatus(Meter meter) { - return meter.gaugeBuilder("mq.listener.status").ofLongs().setUnit("1").setDescription("Listener status").build(); + return meter + .gaugeBuilder("mq.listener.status") + .ofLongs() + .setUnit("1") + .setDescription("Listener status") + .build(); } public static LongCounter createMqUnauthorizedEvent(Meter meter) { - return meter.counterBuilder("mq.unauthorized.event").setUnit("{events}").setDescription("Number of authentication error events").build(); + return meter + .counterBuilder("mq.unauthorized.event") + .setUnit("{events}") + .setDescription("Number of authentication error events") + .build(); } public static LongGauge createMqManagerMaxHandles(Meter meter) { - return meter.gaugeBuilder("mq.manager.max.handles").ofLongs().setUnit("{events}").setDescription("Max open handles").build(); + return meter + .gaugeBuilder("mq.manager.max.handles") + .ofLongs() + .setUnit("{events}") + .setDescription("Max open handles") + .build(); } - -} \ No newline at end of file +} 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 f0b53ab14..1fe9fb337 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 @@ -2,6 +2,7 @@ * Copyright The OpenTelemetry Authors * SPDX-License-Identifier: Apache-2.0 */ + package io.opentelemetry.ibm.mq.metrics; import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; @@ -15,7 +16,7 @@ public final class MetricsConfig { private final Map config; public MetricsConfig(ConfigWrapper config) { - this.config = config.getMetrics(); + this.config = config.getMetrics(); } public boolean isMqMessageRetryCountEnabled() { @@ -209,4 +210,4 @@ private boolean isEnabled(String key) { } return false; } -} \ No newline at end of file +} From f56faed1ef8f791f3810baa7d29ca205ead250df Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 13 Jun 2025 16:12:53 -0700 Subject: [PATCH 26/66] add missing files and nerf integration test until we can figure out docker container --- .../tests/WMQMonitorIntegrationTest.java | 2 + .../resources/conf/test-config.yml | 197 ++++++++++++++++++ .../resources/conf/test-queuemgr-config.yml | 170 +++++++++++++++ .../src/integrationTest/resources/log4j2.xml | 29 +++ 4 files changed, 398 insertions(+) create mode 100644 ibm-mq-metrics/src/integrationTest/resources/conf/test-config.yml create mode 100644 ibm-mq-metrics/src/integrationTest/resources/conf/test-queuemgr-config.yml create mode 100644 ibm-mq-metrics/src/integrationTest/resources/log4j2.xml diff --git a/ibm-mq-metrics/src/integrationTest/java/io/opentelemetry/ibm/mq/integration/tests/WMQMonitorIntegrationTest.java b/ibm-mq-metrics/src/integrationTest/java/io/opentelemetry/ibm/mq/integration/tests/WMQMonitorIntegrationTest.java index 425889214..d37a85386 100644 --- a/ibm-mq-metrics/src/integrationTest/java/io/opentelemetry/ibm/mq/integration/tests/WMQMonitorIntegrationTest.java +++ b/ibm-mq-metrics/src/integrationTest/java/io/opentelemetry/ibm/mq/integration/tests/WMQMonitorIntegrationTest.java @@ -45,12 +45,14 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** Integration Test for WMQMonitor */ +@Disabled class WMQMonitorIntegrationTest { private static final Logger logger = LoggerFactory.getLogger(WMQMonitorIntegrationTest.class); diff --git a/ibm-mq-metrics/src/integrationTest/resources/conf/test-config.yml b/ibm-mq-metrics/src/integrationTest/resources/conf/test-config.yml new file mode 100644 index 000000000..964ef590d --- /dev/null +++ b/ibm-mq-metrics/src/integrationTest/resources/conf/test-config.yml @@ -0,0 +1,197 @@ + +#This is the timeout on queue metrics and channel metrics threads.Default value is 20 seconds. +#No need to change the default unless you know what you are doing. +#queueMetricsCollectionTimeoutInSeconds: 40 +#channelMetricsCollectionTimeoutInSeconds: 40 +#topicMetricsCollectionTimeoutInSeconds: 40 + +queueManagers: + - name: "QM1" + host: "localhost" + port: 1414 + + #The transport type for the queue manager connection, the default is "Bindings" for a binding type connection + #For bindings type, connection WMQ extension (i.e machine agent) need to be on the same machine on which WebbsphereMQ server is running + #For client type, connection change it to "Client". + transportType: "Client" + + #Channel name of the queue manager, channel should be server-conn type. + #This field is not required in case of transportType: Bindings + channelName: DEV.ADMIN.SVRCONN + + #for user access level, please check "Access Permissions" section on the extensions page + #comment out the username and password in case of transportType: Bindings. + username: "admin" + password: "passw0rd" + + #PCF requests are always sent to SYSTEM.ADMIN.COMMAND.QUEUE. The PCF responses to these requests are sent to the default reply-to queue called + #SYSTEM.DEFAULT.MODEL.QUEUE. However, you can override this behavior and send it to a temporary dynamic queue by changing the modelQueueName and replyQueuePrefix fields. + #For more details around this https://www.ibm.com/support/knowledgecenter/SSFKSJ_7.5.0/com.ibm.mq.ref.adm.doc/q083240_.htm & https://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.adm.doc/q020010_.htm + #modelQueueName: "" + #replyQueuePrefix: "" + + + #Sets the CCSID used in the message descriptor of request and response messages. The default value is MQC.MQCCSI_Q_MGR. + #To set this, please use the integer value. + #ccsid: + + #Sets the encoding used in the message descriptor of request and response messages. The default value is MQC.MQENC_NATIVE. + #To set this, please use the integer value. + #encoding: + + # IBM Cipher Suite e.g. "SSL_RSA_WITH_AES_128_CBC_SHA256".. + # For translation to IBM Cipher http://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.dev.doc/q113210_.htm + # A cipher working for IBM Cloud MQ and Temurin JDK 8 is TLS_AES_128_GCM_SHA256 + #cipherSuite: "TLS_AES_128_GCM_SHA256" + + + queueFilters: + #Can provide complete queue name or generic names. A generic name is a character string followed by an asterisk (*), + #for example ABC*, and it selects all objects having names that start with the selected character string. + #An asterisk on its own matches all possible names. + include: ["*"] + exclude: + #type value: STARTSWITH, EQUALS, ENDSWITH, CONTAINS + - type: "STARTSWITH" + #The name of the queue or queue name pattern as per queue filter, comma separated values + values: ["SYSTEM","AMQ"] + + + channelFilters: + #Can provide complete channel name or generic names. A generic name is a character string followed by an asterisk (*), + #for example ABC*, and it selects all objects having names that start with the selected character string. + #An asterisk on its own matches all possible names. + include: ["*"] + exclude: + #type value: STARTSWITH, EQUALS, ENDSWITH, CONTAINS + - type: "STARTSWITH" + #The name of the queue or queue name pattern as per queue filter, comma separated values + values: ["SYSTEM"] + + listenerFilters: + #Can provide complete channel name or generic names. A generic name is a character string followed by an asterisk (*), + #for example ABC*, and it selects all objects having names that start with the selected character string. + #An asterisk on its own matches all possible names. + include: ["*"] + exclude: + #type value: STARTSWITH, EQUALS, ENDSWITH, CONTAINS + - type: "STARTSWITH" + #The name of the queue or queue name pattern as per queue filter, comma separated values + values: ["SYSTEM"] + + topicFilters: + # For topics, IBM MQ uses the topic wildcard characters ('#' and '+') and does not treat a trailing asterisk as a wildcard + # https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.5.0/com.ibm.mq.pla.doc/q005020_.htm + include: ["#"] + exclude: + #type value: STARTSWITH, EQUALS, ENDSWITH, CONTAINS + - type: "STARTSWITH" + #The name of the queue or queue name pattern as per queue filter, comma separated values + values: ["SYSTEM","$SYS"] + +metrics: + "mq.message.retry.count": # Number of message retries + enabled: true + "mq.status": # Channel status + enabled: true + "mq.max.sharing.conversations": # Maximum number of conversations permitted on this channel instance. + enabled: true + "mq.current.sharing.conversations": # Current number of conversations permitted on this channel instance. + enabled: true + "mq.byte.received": # Number of bytes received + enabled: true + "mq.byte.sent": # Number of bytes sent + enabled: true + "mq.buffers.received": # Buffers received + enabled: true + "mq.buffers.sent": # Buffers sent + enabled: true + "mq.message.count": # Message count + enabled: true + "mq.open.input.count": # Count of applications sending messages to the queue + enabled: true + "mq.open.output.count": # Count of applications consuming messages from the queue + enabled: true + "mq.high.queue.depth": # The current high queue depth + enabled: true + "mq.service.interval": # The queue service interval + enabled: true + "mq.queue.depth.full.event": # The number of full queue events + enabled: true + "mq.queue.depth.high.event": # The number of high queue events + enabled: true + "mq.queue.depth.low.event": # The number of low queue events + enabled: true + "mq.uncommitted.messages": # Number of uncommitted messages + enabled: true + "mq.oldest.msg.age": # Queue message oldest age + enabled: true + "mq.current.max.queue.filesize": # Current maximum queue file size + enabled: true + "mq.current.queue.filesize": # Current queue file size + enabled: true + "mq.instances.per.client": # Instances per client + enabled: true + "mq.message.deq.count": # Message dequeue count + enabled: true + "mq.message.enq.count": # Message enqueue count + enabled: true + "mq.queue.depth": # Current queue depth + enabled: true + "mq.service.interval.event": # Queue service interval event + enabled: true + "mq.reusable.log.size": # The amount of space occupied, in megabytes, by log extents available to be reused. + enabled: true + "mq.manager.active.channels": # The queue manager active maximum channels limit + enabled: true + "mq.restart.log.size": # Size of the log data required for restart recovery in megabytes. + enabled: true + "mq.max.queue.depth": # Maximum queue depth + enabled: true + "mq.onqtime.1": # Amount of time, in microseconds, that a message spent on the queue, over a short period + enabled: true + "mq.onqtime.2": # Amount of time, in microseconds, that a message spent on the queue, over a longer period + enabled: true + "mq.message.received.count": # Number of messages received + enabled: true + "mq.message.sent.count": # Number of messages sent + enabled: true + "mq.max.instances": # Max channel instances + enabled: true + "mq.connection.count": # Active connections count + enabled: true + "mq.manager.status": # Queue manager status + enabled: true + "mq.heartbeat": # Queue manager heartbeat + enabled: true + "mq.archive.log.size": # Queue manager archive log size + enabled: true + "mq.manager.max.active.channels": # Queue manager max active channels + enabled: true + "mq.manager.statistics.interval": # Queue manager statistics interval + enabled: true + "mq.publish.count": # Topic publication count + enabled: true + "mq.subscription.count": # Topic subscription count + enabled: true + "mq.listener.status": # Listener status + enabled: true + "mq.unauthorized.event": # Number of authentication error events + enabled: true + "mq.manager.max.handles": # Max open handles + enabled: true + +sslConnection: + trustStorePath: "" + trustStorePassword: "" + + keyStorePath: "" + keyStorePassword: "" + +# Configure the OTLP exporter using system properties keys following the specification https://opentelemetry.io/docs/languages/java/configuration/ +otlpExporter: + otel.exporter.otlp.endpoint: http://0.0.0.0:4318 + otel.exporter.otlp.protocol: http/protobuf + otel.metric.export.interval: 5s + otel.logs.exporter: none + otel.traces.exporter: none \ No newline at end of file diff --git a/ibm-mq-metrics/src/integrationTest/resources/conf/test-queuemgr-config.yml b/ibm-mq-metrics/src/integrationTest/resources/conf/test-queuemgr-config.yml new file mode 100644 index 000000000..840dd3f1d --- /dev/null +++ b/ibm-mq-metrics/src/integrationTest/resources/conf/test-queuemgr-config.yml @@ -0,0 +1,170 @@ +queueManagers: + - name: "QM1" + host: "localhost" + port: 1414 + + #The transport type for the queue manager connection, the default is "Bindings" for a binding type connection + #For bindings type, connection WMQ extension (i.e machine agent) need to be on the same machine on which WebbsphereMQ server is running + #For client type, connection change it to "Client". + transportType: "Client" + + #Channel name of the queue manager, channel should be server-conn type. + #This field is not required in case of transportType: Bindings + channelName: DEV.ADMIN.SVRCONN + + #for user access level, please check "Access Permissions" section on the extensions page + #comment out the username and password in case of transportType: Bindings. + username: "admin" + password: "passw0rd" + + queueFilters: + #Can provide complete queue name or generic names. A generic name is a character string followed by an asterisk (*), + #for example ABC*, and it selects all objects having names that start with the selected character string. + #An asterisk on its own matches all possible names. + include: ["*"] + exclude: + #type value: STARTSWITH, EQUALS, ENDSWITH, CONTAINS + - type: "STARTSWITH" + #The name of the queue or queue name pattern as per queue filter, comma separated values + values: ["SYSTEM","AMQ"] + + + channelFilters: + #Can provide complete channel name or generic names. A generic name is a character string followed by an asterisk (*), + #for example ABC*, and it selects all objects having names that start with the selected character string. + #An asterisk on its own matches all possible names. + include: ["*"] + exclude: + #type value: STARTSWITH, EQUALS, ENDSWITH, CONTAINS + - type: "STARTSWITH" + #The name of the queue or queue name pattern as per queue filter, comma separated values + values: ["SYSTEM"] + + listenerFilters: + #Can provide complete channel name or generic names. A generic name is a character string followed by an asterisk (*), + #for example ABC*, and it selects all objects having names that start with the selected character string. + #An asterisk on its own matches all possible names. + include: ["*"] + exclude: + #type value: STARTSWITH, EQUALS, ENDSWITH, CONTAINS + - type: "STARTSWITH" + #The name of the queue or queue name pattern as per queue filter, comma separated values + values: ["SYSTEM"] + + topicFilters: + # For topics, IBM MQ uses the topic wildcard characters ('#' and '+') and does not treat a trailing asterisk as a wildcard + # https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.5.0/com.ibm.mq.pla.doc/q005020_.htm + include: ["#"] + exclude: + #type value: STARTSWITH, EQUALS, ENDSWITH, CONTAINS + - type: "STARTSWITH" + #The name of the queue or queue name pattern as per queue filter, comma separated values + values: ["SYSTEM","$SYS"] + +metrics: + "mq.message.retry.count": # Number of message retries + enabled: true + "mq.status": # Channel status + enabled: true + "mq.max.sharing.conversations": # Maximum number of conversations permitted on this channel instance. + enabled: true + "mq.current.sharing.conversations": # Current number of conversations permitted on this channel instance. + enabled: true + "mq.byte.received": # Number of bytes received + enabled: true + "mq.byte.sent": # Number of bytes sent + enabled: true + "mq.buffers.received": # Buffers received + enabled: true + "mq.buffers.sent": # Buffers sent + enabled: true + "mq.message.count": # Message count + enabled: true + "mq.open.input.count": # Count of applications sending messages to the queue + enabled: true + "mq.open.output.count": # Count of applications consuming messages from the queue + enabled: true + "mq.high.queue.depth": # The current high queue depth + enabled: true + "mq.service.interval": # The queue service interval + enabled: true + "mq.queue.depth.full.event": # The number of full queue events + enabled: true + "mq.queue.depth.high.event": # The number of high queue events + enabled: true + "mq.queue.depth.low.event": # The number of low queue events + enabled: true + "mq.uncommitted.messages": # Number of uncommitted messages + enabled: true + "mq.oldest.msg.age": # Queue message oldest age + enabled: true + "mq.current.max.queue.filesize": # Current maximum queue file size + enabled: true + "mq.current.queue.filesize": # Current queue file size + enabled: true + "mq.instances.per.client": # Instances per client + enabled: true + "mq.message.deq.count": # Message dequeue count + enabled: true + "mq.message.enq.count": # Message enqueue count + enabled: true + "mq.queue.depth": # Current queue depth + enabled: true + "mq.service.interval.event": # Queue service interval event + enabled: true + "mq.reusable.log.size": # The amount of space occupied, in megabytes, by log extents available to be reused. + enabled: true + "mq.manager.active.channels": # The queue manager active maximum channels limit + enabled: true + "mq.restart.log.size": # Size of the log data required for restart recovery in megabytes. + enabled: true + "mq.max.queue.depth": # Maximum queue depth + enabled: true + "mq.onqtime.1": # Amount of time, in microseconds, that a message spent on the queue, over a short period + enabled: true + "mq.onqtime.2": # Amount of time, in microseconds, that a message spent on the queue, over a longer period + enabled: true + "mq.message.received.count": # Number of messages received + enabled: true + "mq.message.sent.count": # Number of messages sent + enabled: true + "mq.max.instances": # Max channel instances + enabled: true + "mq.connection.count": # Active connections count + enabled: true + "mq.manager.status": # Queue manager status + enabled: true + "mq.heartbeat": # Queue manager heartbeat + enabled: true + "mq.archive.log.size": # Queue manager archive log size + enabled: true + "mq.manager.max.active.channels": # Queue manager max active channels + enabled: true + "mq.manager.statistics.interval": # Queue manager statistics interval + enabled: true + "mq.publish.count": # Topic publication count + enabled: true + "mq.subscription.count": # Topic subscription count + enabled: true + "mq.listener.status": # Listener status + enabled: true + "mq.unauthorized.event": # Number of authentication error events + enabled: true + "mq.manager.max.handles": # Max open handles + enabled: true + + +sslConnection: + trustStorePath: "" + trustStorePassword: "" + trustStoreEncryptedPassword: "" + + keyStorePath: "" + keyStorePassword: "" + keyStoreEncryptedPassword: "" + +# Configure the OTLP exporter using system properties keys following the specification https://opentelemetry.io/docs/languages/java/configuration/ +otlpExporter: + otel.metric.export.interval: 5s + otel.logs.exporter: none + otel.traces.exporter: none \ No newline at end of file diff --git a/ibm-mq-metrics/src/integrationTest/resources/log4j2.xml b/ibm-mq-metrics/src/integrationTest/resources/log4j2.xml new file mode 100644 index 000000000..57fb99df6 --- /dev/null +++ b/ibm-mq-metrics/src/integrationTest/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 319f2d9c15440314004126839d7cd8fb6a858e91 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Mon, 16 Jun 2025 16:21:53 -0700 Subject: [PATCH 27/66] remove terrible ibm.com links --- ibm-mq-metrics/README.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/ibm-mq-metrics/README.md b/ibm-mq-metrics/README.md index 8e98e1d4a..81baf9a2c 100644 --- a/ibm-mq-metrics/README.md +++ b/ibm-mq-metrics/README.md @@ -185,13 +185,20 @@ See [docs/metrics.md](docs/metrics.md). For more details, please check this [doc](https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.1.0/com.ibm.mq.doc/zr00610_.htm) - This might occur due to various reasons ranging from incorrect installation to applying [ibm fix packs](http://www-01.ibm.com/support/docview.wss?uid=swg21410038) but most of the time it happens when you are trying to connect in `Bindings` mode and machine agent is not on the same machine on which WMQ server is running. If you want to connect to WMQ server from a remote machine then connect using `Client` mode. + This might occur due to various reasons ranging from incorrect installation to applying + IBM Fix Packs, but most of the time it happens when you are trying to connect in `Bindings` + mode and machine agent is not on the same machine on which WMQ server is running. If you want + to connect to WMQ server from a remote machine then connect using `Client` mode. - Another way to get around this issue is to avoid using the Bindings mode. Connect using CLIENT transport type from a remote box. + Another way to get around this issue is to avoid using the Bindings mode. Connect using CLIENT + transport type from a remote box. 3. Error `Completion Code '2', Reason '2035'` - This could happen for various reasons but for most of the cases, for **Client** mode the user specified in config.yml is not authorized to access the queue manager. Also sometimes even if userid and password are correct, channel auth (CHLAUTH) for that queue manager blocks traffics from other ips, you need to contact admin to provide you access to the queue manager. - For Bindings mode, please make sure that the MA is owned by a mqm user. Please check [this doc](https://www-01.ibm.com/support/docview.wss?uid=swg21636093) + This could happen for various reasons but for most of the cases, for **Client** mode the + user specified in config.yml is not authorized to access the queue manager. Also sometimes + even if userid and password are correct, channel auth (CHLAUTH) for that queue manager blocks + traffics from other ips, you need to contact admin to provide you access to the queue manager. + For Bindings mode, please make sure that the MA is owned by a mqm user. 4. `MQJE001: Completion Code '2', Reason '2195'` This could happen in **Client** mode. Please make sure that the IBM MQ dependency jars are correctly referenced in classpath of monitor.xml From 245793ad54377ce3aea66d48db48f0efdce25138 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Mon, 23 Jun 2025 09:01:55 -0700 Subject: [PATCH 28/66] remove bad link --- ibm-mq-metrics/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ibm-mq-metrics/README.md b/ibm-mq-metrics/README.md index 81baf9a2c..a22345577 100644 --- a/ibm-mq-metrics/README.md +++ b/ibm-mq-metrics/README.md @@ -94,8 +94,7 @@ There are two transport modes in which this extension can be run: If this extension is configured for **CLIENT** transport type 1. Please make sure the MQ's host and port is accessible. -2. Credentials of user with correct access rights would be needed in config.yml - [(Access Permissions section)](https://github.com/signalfx/opentelemetry-ibm-mq-monitoring-extension#access-permissions). +2. Credentials of user with correct access rights would be needed in config.yml. 3. If the hosting OS for IBM MQ is Windows, Windows user credentials will be needed. If you are in **Bindings** mode, please make sure to start the MA process under a user which has From c9ba9a9edb1c02f2118f019161093a7f9570e462 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Mon, 7 Jul 2025 15:23:35 -0700 Subject: [PATCH 29/66] try and fix resource path on windows --- .../ibm/mq/opentelemetry/ConfigWrapper.java | 16 ++++++++++------ .../ibm/mq/opentelemetry/ConfigWrapperTest.java | 13 +++++++------ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapper.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapper.java index 5f1d71e65..1ef69b034 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapper.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapper.java @@ -8,9 +8,8 @@ import static java.util.Collections.emptyList; import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Paths; +import java.io.InputStream; +import java.net.URL; import java.time.Duration; import java.util.Collections; import java.util.List; @@ -37,10 +36,15 @@ private ConfigWrapper(Map config) { } public static ConfigWrapper parse(String configFile) throws IOException { + return parse(new URL("file://" + configFile)); + } + + public static ConfigWrapper parse(URL configFile) throws IOException { Yaml yaml = new Yaml(); - Map config = - yaml.load(Files.newBufferedReader(Paths.get(configFile), Charset.defaultCharset())); - return new ConfigWrapper(config); + try (InputStream in = configFile.openStream()) { + Map config = yaml.load(in); + return new ConfigWrapper(config); + } } public int getNumberOfThreads() { diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java index 835caed37..f1d728885 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java @@ -8,6 +8,7 @@ import static java.util.Collections.singletonList; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import java.net.URL; import java.time.Duration; import java.time.temporal.ChronoUnit; import org.junit.jupiter.api.BeforeEach; @@ -15,34 +16,34 @@ class ConfigWrapperTest { - String file; + URL configFile; @BeforeEach void setUp() { - file = ConfigWrapperTest.class.getResource("/conf/config.yml").getFile(); + configFile = ConfigWrapperTest.class.getResource("/conf/config.yml"); } @Test void testQueueManagerNames() throws Exception { - ConfigWrapper config = ConfigWrapper.parse(file); + ConfigWrapper config = ConfigWrapper.parse(configFile); assertThat(config.getQueueManagerNames()).isEqualTo(singletonList("QM1")); } @Test void testNumberOfThreads() throws Exception { - ConfigWrapper config = ConfigWrapper.parse(file); + ConfigWrapper config = ConfigWrapper.parse(configFile); assertThat(config.getNumberOfThreads()).isEqualTo(20); } @Test void testTaskDelay() throws Exception { - ConfigWrapper config = ConfigWrapper.parse(file); + ConfigWrapper config = ConfigWrapper.parse(configFile); assertThat(config.getTaskDelay()).isEqualTo(Duration.of(27, ChronoUnit.SECONDS)); } @Test void testTaskInitialDelay() throws Exception { - ConfigWrapper config = ConfigWrapper.parse(file); + ConfigWrapper config = ConfigWrapper.parse(configFile); assertThat(config.getTaskInitialDelaySeconds()).isEqualTo(0); } } From a5942fe325f30fa298588363ed60f9f2fd7d9496 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Mon, 7 Jul 2025 15:32:04 -0700 Subject: [PATCH 30/66] Revert "try and fix resource path on windows" This reverts commit c9ba9a9edb1c02f2118f019161093a7f9570e462. --- .../ibm/mq/opentelemetry/ConfigWrapper.java | 16 ++++++---------- .../ibm/mq/opentelemetry/ConfigWrapperTest.java | 13 ++++++------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapper.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapper.java index 1ef69b034..5f1d71e65 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapper.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapper.java @@ -8,8 +8,9 @@ import static java.util.Collections.emptyList; import java.io.IOException; -import java.io.InputStream; -import java.net.URL; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Paths; import java.time.Duration; import java.util.Collections; import java.util.List; @@ -36,15 +37,10 @@ private ConfigWrapper(Map config) { } public static ConfigWrapper parse(String configFile) throws IOException { - return parse(new URL("file://" + configFile)); - } - - public static ConfigWrapper parse(URL configFile) throws IOException { Yaml yaml = new Yaml(); - try (InputStream in = configFile.openStream()) { - Map config = yaml.load(in); - return new ConfigWrapper(config); - } + Map config = + yaml.load(Files.newBufferedReader(Paths.get(configFile), Charset.defaultCharset())); + return new ConfigWrapper(config); } public int getNumberOfThreads() { diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java index f1d728885..835caed37 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java @@ -8,7 +8,6 @@ import static java.util.Collections.singletonList; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import java.net.URL; import java.time.Duration; import java.time.temporal.ChronoUnit; import org.junit.jupiter.api.BeforeEach; @@ -16,34 +15,34 @@ class ConfigWrapperTest { - URL configFile; + String file; @BeforeEach void setUp() { - configFile = ConfigWrapperTest.class.getResource("/conf/config.yml"); + file = ConfigWrapperTest.class.getResource("/conf/config.yml").getFile(); } @Test void testQueueManagerNames() throws Exception { - ConfigWrapper config = ConfigWrapper.parse(configFile); + ConfigWrapper config = ConfigWrapper.parse(file); assertThat(config.getQueueManagerNames()).isEqualTo(singletonList("QM1")); } @Test void testNumberOfThreads() throws Exception { - ConfigWrapper config = ConfigWrapper.parse(configFile); + ConfigWrapper config = ConfigWrapper.parse(file); assertThat(config.getNumberOfThreads()).isEqualTo(20); } @Test void testTaskDelay() throws Exception { - ConfigWrapper config = ConfigWrapper.parse(configFile); + ConfigWrapper config = ConfigWrapper.parse(file); assertThat(config.getTaskDelay()).isEqualTo(Duration.of(27, ChronoUnit.SECONDS)); } @Test void testTaskInitialDelay() throws Exception { - ConfigWrapper config = ConfigWrapper.parse(configFile); + ConfigWrapper config = ConfigWrapper.parse(file); assertThat(config.getTaskInitialDelaySeconds()).isEqualTo(0); } } From 6f6e51e18ff0ce048123cda782b54d777b1907f3 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Mon, 7 Jul 2025 15:34:25 -0700 Subject: [PATCH 31/66] rollback and try another approach at making windows happy --- .../opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java index 835caed37..adaba260e 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java @@ -20,6 +20,10 @@ class ConfigWrapperTest { @BeforeEach void setUp() { file = ConfigWrapperTest.class.getResource("/conf/config.yml").getFile(); + // Windows resources can contain a colon, which can't be mapped to a Path cleanly + if(file.contains(":")){ + file = file.replaceFirst(":", ""); + } } @Test From 2e7f41ccd54101ce056e77c055b8e6241182a87e Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Mon, 7 Jul 2025 15:34:36 -0700 Subject: [PATCH 32/66] spotless --- .../opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java index adaba260e..534ca4150 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java @@ -21,7 +21,7 @@ class ConfigWrapperTest { void setUp() { file = ConfigWrapperTest.class.getResource("/conf/config.yml").getFile(); // Windows resources can contain a colon, which can't be mapped to a Path cleanly - if(file.contains(":")){ + if (file.contains(":")) { file = file.replaceFirst(":", ""); } } From 3d73a463ae39a47a2a7470a7444242babcb4f2af Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Mon, 7 Jul 2025 15:43:18 -0700 Subject: [PATCH 33/66] more windows help --- .../opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java index 534ca4150..2e0364da0 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java @@ -22,6 +22,10 @@ void setUp() { file = ConfigWrapperTest.class.getResource("/conf/config.yml").getFile(); // Windows resources can contain a colon, which can't be mapped to a Path cleanly if (file.contains(":")) { + System.err.println("resource => " + ConfigWrapperTest.class.getResource("/conf/config.yml")); + System.err.println("config file => " + file); + String userDir = System.getProperty("user.dir"); + System.err.println("user.dir => " + userDir); file = file.replaceFirst(":", ""); } } From 97fee7594f02e5db0adce7fb3fc522198d5ce8ae Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Mon, 7 Jul 2025 15:45:46 -0700 Subject: [PATCH 34/66] ugh --- .../io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java index 2e0364da0..a7124d87c 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java @@ -18,6 +18,7 @@ class ConfigWrapperTest { String file; @BeforeEach + @SuppressWarnings("SystemOut") void setUp() { file = ConfigWrapperTest.class.getResource("/conf/config.yml").getFile(); // Windows resources can contain a colon, which can't be mapped to a Path cleanly From bc2ebb7a9bdd1eebf9ea51ea2136f62f0a1bd569 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Tue, 8 Jul 2025 08:53:34 -0700 Subject: [PATCH 35/66] more windows --- .../opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java index a7124d87c..3eb259326 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java @@ -25,9 +25,11 @@ void setUp() { if (file.contains(":")) { System.err.println("resource => " + ConfigWrapperTest.class.getResource("/conf/config.yml")); System.err.println("config file => " + file); + String file2 = file.replaceFirst("^/([A-Z]:)/", "$1/"); + System.err.println("file2 => " + file2); String userDir = System.getProperty("user.dir"); System.err.println("user.dir => " + userDir); - file = file.replaceFirst(":", ""); + file = file2; } } From 7c6f9b1b7ed6575794bad49849d12c18e10effcc Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Tue, 8 Jul 2025 10:30:47 -0700 Subject: [PATCH 36/66] cleanup --- .../ibm/mq/opentelemetry/ConfigWrapperTest.java | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java index 3eb259326..3d2397cc0 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/opentelemetry/ConfigWrapperTest.java @@ -18,19 +18,11 @@ class ConfigWrapperTest { String file; @BeforeEach - @SuppressWarnings("SystemOut") void setUp() { file = ConfigWrapperTest.class.getResource("/conf/config.yml").getFile(); // Windows resources can contain a colon, which can't be mapped to a Path cleanly - if (file.contains(":")) { - System.err.println("resource => " + ConfigWrapperTest.class.getResource("/conf/config.yml")); - System.err.println("config file => " + file); - String file2 = file.replaceFirst("^/([A-Z]:)/", "$1/"); - System.err.println("file2 => " + file2); - String userDir = System.getProperty("user.dir"); - System.err.println("user.dir => " + userDir); - file = file2; - } + // They look like /D:/a/path/to/whatever + file = file.replaceFirst("^/([A-Z]:)/", "$1/"); } @Test From 45df2682ca365168cfea4d941ab05920dda59ccd Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 16 Jul 2025 08:23:51 -0700 Subject: [PATCH 37/66] update all metric names to have ibm prefix --- ibm-mq-metrics/model/metrics.yaml | 86 +++++++++++++++---------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/ibm-mq-metrics/model/metrics.yaml b/ibm-mq-metrics/model/metrics.yaml index 2cf42d3e3..86f9c3b05 100644 --- a/ibm-mq-metrics/model/metrics.yaml +++ b/ibm-mq-metrics/model/metrics.yaml @@ -1,7 +1,7 @@ groups: - id: mq.message.retry.count type: metric - metric_name: mq.message.retry.count + metric_name: ibm.mq.message.retry.count stability: development brief: "Number of message retries" instrument: gauge @@ -15,7 +15,7 @@ groups: requirement_level: required - id: mq.status type: metric - metric_name: mq.status + metric_name: ibm.mq.status stability: development brief: "Channel status" instrument: gauge @@ -33,7 +33,7 @@ groups: requirement_level: required - id: mq.max.sharing.conversations type: metric - metric_name: mq.max.sharing.conversations + metric_name: ibm.mq.max.sharing.conversations stability: development brief: "Maximum number of conversations permitted on this channel instance." instrument: gauge @@ -51,7 +51,7 @@ groups: requirement_level: required - id: mq.current.sharing.conversations type: metric - metric_name: mq.current.sharing.conversations + metric_name: ibm.mq.current.sharing.conversations stability: development unit: "{conversations}" brief: "Current number of conversations permitted on this channel instance." @@ -69,7 +69,7 @@ groups: requirement_level: required - id: mq.byte.received type: metric - metric_name: mq.byte.received + metric_name: ibm.mq.byte.received stability: development brief: "Number of bytes received" instrument: gauge @@ -87,7 +87,7 @@ groups: requirement_level: required - id: mq.byte.sent type: metric - metric_name: mq.byte.sent + metric_name: ibm.mq.byte.sent stability: development brief: "Number of bytes sent" instrument: gauge @@ -105,7 +105,7 @@ groups: requirement_level: required - id: mq.buffers.received type: metric - metric_name: mq.buffers.received + metric_name: ibm.mq.buffers.received stability: development brief: "Buffers received" instrument: gauge @@ -123,7 +123,7 @@ groups: requirement_level: required - id: mq.buffers.sent type: metric - metric_name: mq.buffers.sent + metric_name: ibm.mq.buffers.sent stability: development brief: "Buffers sent" unit: "{buffers}" @@ -141,7 +141,7 @@ groups: requirement_level: required - id: mq.message.count type: metric - metric_name: mq.message.count + metric_name: ibm.mq.message.count stability: development brief: "Message count" unit: "{messages}" @@ -159,7 +159,7 @@ groups: requirement_level: required - id: mq.open.input.count type: metric - metric_name: mq.open.input.count + metric_name: ibm.mq.open.input.count stability: development brief: "Count of applications sending messages to the queue" instrument: gauge @@ -173,7 +173,7 @@ groups: requirement_level: required - id: mq.open.output.count type: metric - metric_name: mq.open.output.count + metric_name: ibm.mq.open.output.count stability: development brief: "Count of applications consuming messages from the queue" instrument: gauge @@ -187,7 +187,7 @@ groups: requirement_level: required - id: mq.high.queue.depth type: metric - metric_name: mq.high.queue.depth + metric_name: ibm.mq.high.queue.depth stability: development brief: "The current high queue depth" instrument: gauge @@ -201,7 +201,7 @@ groups: requirement_level: required - id: mq.service.interval type: metric - metric_name: mq.service.interval + metric_name: ibm.mq.service.interval stability: development brief: "The queue service interval" instrument: gauge @@ -251,7 +251,7 @@ groups: requirement_level: required - id: mq.uncommitted.messages type: metric - metric_name: mq.uncommitted.messages + metric_name: ibm.mq.uncommitted.messages stability: development brief: "Number of uncommitted messages" instrument: gauge @@ -265,7 +265,7 @@ groups: requirement_level: required - id: mq.oldest.msg.age type: metric - metric_name: mq.oldest.msg.age + metric_name: ibm.mq.oldest.msg.age stability: development brief: "Queue message oldest age" instrument: gauge @@ -279,7 +279,7 @@ groups: requirement_level: required - id: mq.current.max.queue.filesize type: metric - metric_name: mq.current.max.queue.filesize + metric_name: ibm.mq.current.max.queue.filesize stability: development brief: "Current maximum queue file size" instrument: gauge @@ -293,7 +293,7 @@ groups: requirement_level: required - id: mq.current.queue.filesize type: metric - metric_name: mq.current.queue.filesize + metric_name: ibm.mq.current.queue.filesize stability: development brief: "Current queue file size" instrument: gauge @@ -307,7 +307,7 @@ groups: requirement_level: required - id: mq.instances.per.client type: metric - metric_name: mq.instances.per.client + metric_name: ibm.mq.instances.per.client stability: development brief: "Instances per client" instrument: gauge @@ -321,7 +321,7 @@ groups: requirement_level: required - id: mq.message.deq.count type: metric - metric_name: mq.message.deq.count + metric_name: ibm.mq.message.deq.count stability: development brief: "Message dequeue count" instrument: gauge @@ -335,7 +335,7 @@ groups: requirement_level: required - id: mq.message.enq.count type: metric - metric_name: mq.message.enq.count + metric_name: ibm.mq.message.enq.count stability: development brief: "Message enqueue count" instrument: gauge @@ -349,7 +349,7 @@ groups: requirement_level: required - id: mq.queue.depth type: metric - metric_name: mq.queue.depth + metric_name: ibm.mq.queue.depth stability: development brief: "Current queue depth" instrument: gauge @@ -363,7 +363,7 @@ groups: requirement_level: required - id: mq.service.interval.event type: metric - metric_name: mq.service.interval.event + metric_name: ibm.mq.service.interval.event stability: development brief: "Queue service interval event" instrument: gauge @@ -377,7 +377,7 @@ groups: requirement_level: required - id: mq.reusable.log.size type: metric - metric_name: mq.reusable.log.size + metric_name: ibm.mq.reusable.log.size stability: development brief: "The amount of space occupied, in megabytes, by log extents available to be reused." instrument: gauge @@ -387,7 +387,7 @@ groups: requirement_level: required - id: mq.manager.active.channels type: metric - metric_name: mq.manager.active.channels + metric_name: ibm.mq.manager.active.channels stability: development brief: "The queue manager active maximum channels limit" instrument: gauge @@ -397,7 +397,7 @@ groups: requirement_level: required - id: mq.restart.log.size type: metric - metric_name: mq.restart.log.size + metric_name: ibm.mq.restart.log.size stability: development brief: "Size of the log data required for restart recovery in megabytes." instrument: gauge @@ -407,7 +407,7 @@ groups: requirement_level: required - id: mq.max.queue.depth type: metric - metric_name: mq.max.queue.depth + metric_name: ibm.mq.max.queue.depth stability: development brief: "Maximum queue depth" instrument: gauge @@ -421,7 +421,7 @@ groups: requirement_level: required - id: mq.onqtime.1 type: metric - metric_name: mq.onqtime.1 + metric_name: ibm.mq.onqtime.1 stability: development brief: "Amount of time, in microseconds, that a message spent on the queue, over a short period" instrument: gauge @@ -435,7 +435,7 @@ groups: requirement_level: required - id: mq.onqtime.2 type: metric - metric_name: mq.onqtime.2 + metric_name: ibm.mq.onqtime.2 stability: development brief: "Amount of time, in microseconds, that a message spent on the queue, over a longer period" instrument: gauge @@ -449,7 +449,7 @@ groups: requirement_level: required - id: mq.message.received.count type: metric - metric_name: mq.message.received.count + metric_name: ibm.mq.message.received.count stability: development brief: "Number of messages received" instrument: gauge @@ -463,7 +463,7 @@ groups: requirement_level: required - id: mq.message.sent.count type: metric - metric_name: mq.message.sent.count + metric_name: ibm.mq.message.sent.count stability: development brief: "Number of messages sent" instrument: gauge @@ -477,7 +477,7 @@ groups: requirement_level: required - id: mq.max.instances type: metric - metric_name: mq.max.instances + metric_name: ibm.mq.max.instances stability: development brief: "Max channel instances" instrument: gauge @@ -491,7 +491,7 @@ groups: requirement_level: required - id: mq.connection.count type: metric - metric_name: mq.connection.count + metric_name: ibm.mq.connection.count stability: development brief: "Active connections count" instrument: gauge @@ -501,7 +501,7 @@ groups: requirement_level: required - id: mq.manager.status type: metric - metric_name: mq.manager.status + metric_name: ibm.mq.manager.status stability: development brief: "Queue manager status" instrument: gauge @@ -511,7 +511,7 @@ groups: requirement_level: required - id: mq.heartbeat type: metric - metric_name: mq.heartbeat + metric_name: ibm.mq.heartbeat stability: development brief: "Queue manager heartbeat" instrument: gauge @@ -521,7 +521,7 @@ groups: requirement_level: required - id: mq.archive.log.size type: metric - metric_name: mq.archive.log.size + metric_name: ibm.mq.archive.log.size stability: development brief: "Queue manager archive log size" instrument: gauge @@ -531,7 +531,7 @@ groups: requirement_level: required - id: mq.manager.max.active.channels type: metric - metric_name: mq.manager.max.active.channels + metric_name: ibm.mq.manager.max.active.channels stability: development brief: "Queue manager max active channels" instrument: gauge @@ -541,7 +541,7 @@ groups: requirement_level: required - id: mq.manager.statistics.interval type: metric - metric_name: mq.manager.statistics.interval + metric_name: ibm.mq.manager.statistics.interval stability: development brief: "Queue manager statistics interval" instrument: gauge @@ -551,7 +551,7 @@ groups: requirement_level: required - id: mq.publish.count type: metric - metric_name: mq.publish.count + metric_name: ibm.mq.publish.count stability: development brief: "Topic publication count" instrument: gauge @@ -563,7 +563,7 @@ groups: requirement_level: required - id: mq.subscription.count type: metric - metric_name: mq.subscription.count + metric_name: ibm.mq.subscription.count stability: development brief: "Topic subscription count" instrument: gauge @@ -575,7 +575,7 @@ groups: requirement_level: required - id: mq.listener.status type: metric - metric_name: mq.listener.status + metric_name: ibm.mq.listener.status stability: development brief: "Listener status" instrument: gauge @@ -587,7 +587,7 @@ groups: requirement_level: required - id: mq.unauthorized.event type: metric - metric_name: mq.unauthorized.event + metric_name: ibm.mq.unauthorized.event stability: development brief: "Number of authentication error events" instrument: counter @@ -601,11 +601,11 @@ groups: requirement_level: required - id: mq.manager.max.handles type: metric - metric_name: mq.manager.max.handles + metric_name: ibm.mq.manager.max.handles stability: development brief: "Max open handles" instrument: gauge unit: "{events}" attributes: - ref: queue.manager - requirement_level: required \ No newline at end of file + requirement_level: required From 0ae4b47493cb8fcdcc82c07cdf75bb0b66fcc816 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 16 Jul 2025 08:24:26 -0700 Subject: [PATCH 38/66] update all metric ids to have ibm prefix --- ibm-mq-metrics/model/metrics.yaml | 84 +++++++++++++++---------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/ibm-mq-metrics/model/metrics.yaml b/ibm-mq-metrics/model/metrics.yaml index 86f9c3b05..e2460367b 100644 --- a/ibm-mq-metrics/model/metrics.yaml +++ b/ibm-mq-metrics/model/metrics.yaml @@ -1,5 +1,5 @@ groups: - - id: mq.message.retry.count + - id: ibm.mq.message.retry.count type: metric metric_name: ibm.mq.message.retry.count stability: development @@ -13,7 +13,7 @@ groups: requirement_level: required - ref: queue.manager requirement_level: required - - id: mq.status + - id: ibm.mq.status type: metric metric_name: ibm.mq.status stability: development @@ -31,7 +31,7 @@ groups: requirement_level: required - ref: channel.start.time requirement_level: required - - id: mq.max.sharing.conversations + - id: ibm.mq.max.sharing.conversations type: metric metric_name: ibm.mq.max.sharing.conversations stability: development @@ -49,7 +49,7 @@ groups: requirement_level: required - ref: channel.start.time requirement_level: required - - id: mq.current.sharing.conversations + - id: ibm.mq.current.sharing.conversations type: metric metric_name: ibm.mq.current.sharing.conversations stability: development @@ -67,7 +67,7 @@ groups: requirement_level: required - ref: channel.start.time requirement_level: required - - id: mq.byte.received + - id: ibm.mq.byte.received type: metric metric_name: ibm.mq.byte.received stability: development @@ -85,7 +85,7 @@ groups: requirement_level: required - ref: channel.start.time requirement_level: required - - id: mq.byte.sent + - id: ibm.mq.byte.sent type: metric metric_name: ibm.mq.byte.sent stability: development @@ -103,7 +103,7 @@ groups: requirement_level: required - ref: channel.start.time requirement_level: required - - id: mq.buffers.received + - id: ibm.mq.buffers.received type: metric metric_name: ibm.mq.buffers.received stability: development @@ -121,7 +121,7 @@ groups: requirement_level: required - ref: channel.start.time requirement_level: required - - id: mq.buffers.sent + - id: ibm.mq.buffers.sent type: metric metric_name: ibm.mq.buffers.sent stability: development @@ -139,7 +139,7 @@ groups: requirement_level: required - ref: channel.start.time requirement_level: required - - id: mq.message.count + - id: ibm.mq.message.count type: metric metric_name: ibm.mq.message.count stability: development @@ -157,7 +157,7 @@ groups: requirement_level: required - ref: channel.start.time requirement_level: required - - id: mq.open.input.count + - id: ibm.mq.open.input.count type: metric metric_name: ibm.mq.open.input.count stability: development @@ -171,7 +171,7 @@ groups: requirement_level: required - ref: queue.type requirement_level: required - - id: mq.open.output.count + - id: ibm.mq.open.output.count type: metric metric_name: ibm.mq.open.output.count stability: development @@ -185,7 +185,7 @@ groups: requirement_level: required - ref: queue.type requirement_level: required - - id: mq.high.queue.depth + - id: ibm.mq.high.queue.depth type: metric metric_name: ibm.mq.high.queue.depth stability: development @@ -199,7 +199,7 @@ groups: requirement_level: required - ref: queue.type requirement_level: required - - id: mq.service.interval + - id: ibm.mq.service.interval type: metric metric_name: ibm.mq.service.interval stability: development @@ -249,7 +249,7 @@ groups: requirement_level: required - ref: queue.name requirement_level: required - - id: mq.uncommitted.messages + - id: ibm.mq.uncommitted.messages type: metric metric_name: ibm.mq.uncommitted.messages stability: development @@ -263,7 +263,7 @@ groups: requirement_level: required - ref: queue.type requirement_level: required - - id: mq.oldest.msg.age + - id: ibm.mq.oldest.msg.age type: metric metric_name: ibm.mq.oldest.msg.age stability: development @@ -277,7 +277,7 @@ groups: requirement_level: required - ref: queue.type requirement_level: required - - id: mq.current.max.queue.filesize + - id: ibm.mq.current.max.queue.filesize type: metric metric_name: ibm.mq.current.max.queue.filesize stability: development @@ -291,7 +291,7 @@ groups: requirement_level: required - ref: queue.type requirement_level: required - - id: mq.current.queue.filesize + - id: ibm.mq.current.queue.filesize type: metric metric_name: ibm.mq.current.queue.filesize stability: development @@ -305,7 +305,7 @@ groups: requirement_level: required - ref: queue.type requirement_level: required - - id: mq.instances.per.client + - id: ibm.mq.instances.per.client type: metric metric_name: ibm.mq.instances.per.client stability: development @@ -319,7 +319,7 @@ groups: requirement_level: required - ref: queue.type requirement_level: required - - id: mq.message.deq.count + - id: ibm.mq.message.deq.count type: metric metric_name: ibm.mq.message.deq.count stability: development @@ -333,7 +333,7 @@ groups: requirement_level: required - ref: queue.type requirement_level: required - - id: mq.message.enq.count + - id: ibm.mq.message.enq.count type: metric metric_name: ibm.mq.message.enq.count stability: development @@ -347,7 +347,7 @@ groups: requirement_level: required - ref: queue.type requirement_level: required - - id: mq.queue.depth + - id: ibm.mq.queue.depth type: metric metric_name: ibm.mq.queue.depth stability: development @@ -361,7 +361,7 @@ groups: requirement_level: required - ref: queue.type requirement_level: required - - id: mq.service.interval.event + - id: ibm.mq.service.interval.event type: metric metric_name: ibm.mq.service.interval.event stability: development @@ -375,7 +375,7 @@ groups: requirement_level: required - ref: queue.type requirement_level: required - - id: mq.reusable.log.size + - id: ibm.mq.reusable.log.size type: metric metric_name: ibm.mq.reusable.log.size stability: development @@ -385,7 +385,7 @@ groups: attributes: - ref: queue.manager requirement_level: required - - id: mq.manager.active.channels + - id: ibm.mq.manager.active.channels type: metric metric_name: ibm.mq.manager.active.channels stability: development @@ -395,7 +395,7 @@ groups: attributes: - ref: queue.manager requirement_level: required - - id: mq.restart.log.size + - id: ibm.mq.restart.log.size type: metric metric_name: ibm.mq.restart.log.size stability: development @@ -405,7 +405,7 @@ groups: attributes: - ref: queue.manager requirement_level: required - - id: mq.max.queue.depth + - id: ibm.mq.max.queue.depth type: metric metric_name: ibm.mq.max.queue.depth stability: development @@ -419,7 +419,7 @@ groups: requirement_level: required - ref: queue.type requirement_level: required - - id: mq.onqtime.1 + - id: ibm.mq.onqtime.1 type: metric metric_name: ibm.mq.onqtime.1 stability: development @@ -433,7 +433,7 @@ groups: requirement_level: required - ref: queue.type requirement_level: required - - id: mq.onqtime.2 + - id: ibm.mq.onqtime.2 type: metric metric_name: ibm.mq.onqtime.2 stability: development @@ -447,7 +447,7 @@ groups: requirement_level: required - ref: queue.type requirement_level: required - - id: mq.message.received.count + - id: ibm.mq.message.received.count type: metric metric_name: ibm.mq.message.received.count stability: development @@ -461,7 +461,7 @@ groups: requirement_level: required - ref: queue.manager requirement_level: required - - id: mq.message.sent.count + - id: ibm.mq.message.sent.count type: metric metric_name: ibm.mq.message.sent.count stability: development @@ -475,7 +475,7 @@ groups: requirement_level: required - ref: queue.manager requirement_level: required - - id: mq.max.instances + - id: ibm.mq.max.instances type: metric metric_name: ibm.mq.max.instances stability: development @@ -489,7 +489,7 @@ groups: requirement_level: required - ref: queue.manager requirement_level: required - - id: mq.connection.count + - id: ibm.mq.connection.count type: metric metric_name: ibm.mq.connection.count stability: development @@ -499,7 +499,7 @@ groups: attributes: - ref: queue.manager requirement_level: required - - id: mq.manager.status + - id: ibm.mq.manager.status type: metric metric_name: ibm.mq.manager.status stability: development @@ -509,7 +509,7 @@ groups: attributes: - ref: queue.manager requirement_level: required - - id: mq.heartbeat + - id: ibm.mq.heartbeat type: metric metric_name: ibm.mq.heartbeat stability: development @@ -519,7 +519,7 @@ groups: attributes: - ref: queue.manager requirement_level: required - - id: mq.archive.log.size + - id: ibm.mq.archive.log.size type: metric metric_name: ibm.mq.archive.log.size stability: development @@ -529,7 +529,7 @@ groups: attributes: - ref: queue.manager requirement_level: required - - id: mq.manager.max.active.channels + - id: ibm.mq.manager.max.active.channels type: metric metric_name: ibm.mq.manager.max.active.channels stability: development @@ -539,7 +539,7 @@ groups: attributes: - ref: queue.manager requirement_level: required - - id: mq.manager.statistics.interval + - id: ibm.mq.manager.statistics.interval type: metric metric_name: ibm.mq.manager.statistics.interval stability: development @@ -549,7 +549,7 @@ groups: attributes: - ref: queue.manager requirement_level: required - - id: mq.publish.count + - id: ibm.mq.publish.count type: metric metric_name: ibm.mq.publish.count stability: development @@ -561,7 +561,7 @@ groups: requirement_level: required - ref: topic.name requirement_level: required - - id: mq.subscription.count + - id: ibm.mq.subscription.count type: metric metric_name: ibm.mq.subscription.count stability: development @@ -573,7 +573,7 @@ groups: requirement_level: required - ref: topic.name requirement_level: required - - id: mq.listener.status + - id: ibm.mq.listener.status type: metric metric_name: ibm.mq.listener.status stability: development @@ -585,7 +585,7 @@ groups: requirement_level: required - ref: listener.name requirement_level: required - - id: mq.unauthorized.event + - id: ibm.mq.unauthorized.event type: metric metric_name: ibm.mq.unauthorized.event stability: development @@ -599,7 +599,7 @@ groups: requirement_level: required - ref: application.name requirement_level: required - - id: mq.manager.max.handles + - id: ibm.mq.manager.max.handles type: metric metric_name: ibm.mq.manager.max.handles stability: development From fd11244ed519e15dd3fdabe794a041f58877560c Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 16 Jul 2025 09:00:24 -0700 Subject: [PATCH 39/66] use consistent quoting --- ibm-mq-metrics/model/metrics.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ibm-mq-metrics/model/metrics.yaml b/ibm-mq-metrics/model/metrics.yaml index e2460367b..ba5e398df 100644 --- a/ibm-mq-metrics/model/metrics.yaml +++ b/ibm-mq-metrics/model/metrics.yaml @@ -213,9 +213,9 @@ groups: requirement_level: required - ref: queue.type requirement_level: required - - id: "mq.queue.depth.full.event" + - id: ibm.mq.queue.depth.full.event type: metric - metric_name: "mq.queue.depth.full.event" + metric_name: mq.queue.depth.full.event stability: development brief: "The number of full queue events" instrument: counter @@ -225,9 +225,9 @@ groups: requirement_level: required - ref: queue.name requirement_level: required - - id: "mq.queue.depth.high.event" + - id: mq.queue.depth.high.event type: metric - metric_name: "mq.queue.depth.high.event" + metric_name: mq.queue.depth.high.event stability: development brief: "The number of high queue events" instrument: counter @@ -237,9 +237,9 @@ groups: requirement_level: required - ref: queue.name requirement_level: required - - id: "mq.queue.depth.low.event" + - id: mq.queue.depth.low.event type: metric - metric_name: "mq.queue.depth.low.event" + metric_name: mq.queue.depth.low.event stability: development brief: "The number of low queue events" instrument: counter From 217d785dc672d5c8f25dd368a5e533380611bca8 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 16 Jul 2025 09:01:14 -0700 Subject: [PATCH 40/66] add ibm prefix --- ibm-mq-metrics/model/metrics.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ibm-mq-metrics/model/metrics.yaml b/ibm-mq-metrics/model/metrics.yaml index ba5e398df..d45957ad6 100644 --- a/ibm-mq-metrics/model/metrics.yaml +++ b/ibm-mq-metrics/model/metrics.yaml @@ -215,7 +215,7 @@ groups: requirement_level: required - id: ibm.mq.queue.depth.full.event type: metric - metric_name: mq.queue.depth.full.event + metric_name: ibm.mq.queue.depth.full.event stability: development brief: "The number of full queue events" instrument: counter @@ -225,9 +225,9 @@ groups: requirement_level: required - ref: queue.name requirement_level: required - - id: mq.queue.depth.high.event + - id: ibm.mq..queue.depth.high.event type: metric - metric_name: mq.queue.depth.high.event + metric_name: ibm.mq.queue.depth.high.event stability: development brief: "The number of high queue events" instrument: counter @@ -237,9 +237,9 @@ groups: requirement_level: required - ref: queue.name requirement_level: required - - id: mq.queue.depth.low.event + - id: ibm.mq..queue.depth.low.event type: metric - metric_name: mq.queue.depth.low.event + metric_name: ibm.mq.queue.depth.low.event stability: development brief: "The number of low queue events" instrument: counter From b7afbcbccf6f5fe94241c53969f5982869fcf9fe Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 16 Jul 2025 09:04:51 -0700 Subject: [PATCH 41/66] fix usages to new names --- ibm-mq-metrics/docs/metrics.md | 270 +++++++++--------- .../io/opentelemetry/ibm/mq/WmqMonitor.java | 2 +- .../opentelemetry/ibm/mq/metrics/Metrics.java | 180 ++++++------ .../ibm/mq/metrics/MetricsConfig.java | 180 ++++++------ .../ChannelMetricsCollector.java | 34 +-- .../InquireChannelCmdCollector.java | 20 +- .../InquireQueueManagerCmdCollector.java | 4 +- .../InquireTStatusCmdCollector.java | 8 +- .../ListenerMetricsCollector.java | 4 +- .../PerformanceEventQueueCollector.java | 12 +- .../QueueCollectionBuddy.java | 46 +-- .../QueueManagerEventCollector.java | 4 +- .../QueueManagerMetricsCollector.java | 24 +- .../ReadConfigurationEventQueueCollector.java | 4 +- 14 files changed, 398 insertions(+), 394 deletions(-) diff --git a/ibm-mq-metrics/docs/metrics.md b/ibm-mq-metrics/docs/metrics.md index fafe725ae..2ab49328f 100644 --- a/ibm-mq-metrics/docs/metrics.md +++ b/ibm-mq-metrics/docs/metrics.md @@ -1,14 +1,14 @@ # Produced Metrics -## Metric `mq.message.retry.count` +## Metric `ibm.mq.message.retry.count` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.message.retry.count` | Gauge | `{messages}` | Number of message retries | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.message.retry.count` | Gauge | `{messages}` | Number of message retries | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.message.retry.count` Attributes +### `ibm.mq.message.retry.count` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -18,14 +18,14 @@ -## Metric `mq.status` +## Metric `ibm.mq.status` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.status` | Gauge | `1` | Channel status | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.status` | Gauge | `1` | Channel status | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.status` Attributes +### `ibm.mq.status` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -37,14 +37,14 @@ -## Metric `mq.max.sharing.conversations` +## Metric `ibm.mq.max.sharing.conversations` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.max.sharing.conversations` | Gauge | `{conversations}` | Maximum number of conversations permitted on this channel instance. | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.max.sharing.conversations` | Gauge | `{conversations}` | Maximum number of conversations permitted on this channel instance. | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.max.sharing.conversations` Attributes +### `ibm.mq.max.sharing.conversations` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -56,14 +56,14 @@ -## Metric `mq.current.sharing.conversations` +## Metric `ibm.mq.current.sharing.conversations` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.current.sharing.conversations` | Gauge | `{conversations}` | Current number of conversations permitted on this channel instance. | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.current.sharing.conversations` | Gauge | `{conversations}` | Current number of conversations permitted on this channel instance. | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.current.sharing.conversations` Attributes +### `ibm.mq.current.sharing.conversations` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -75,14 +75,14 @@ -## Metric `mq.byte.received` +## Metric `ibm.mq.byte.received` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.byte.received` | Gauge | `{bytes}` | Number of bytes received | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.byte.received` | Gauge | `{bytes}` | Number of bytes received | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.byte.received` Attributes +### `ibm.mq.byte.received` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -94,14 +94,14 @@ -## Metric `mq.byte.sent` +## Metric `ibm.mq.byte.sent` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.byte.sent` | Gauge | `{bytes}` | Number of bytes sent | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.byte.sent` | Gauge | `{bytes}` | Number of bytes sent | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.byte.sent` Attributes +### `ibm.mq.byte.sent` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -113,14 +113,14 @@ -## Metric `mq.buffers.received` +## Metric `ibm.mq.buffers.received` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.buffers.received` | Gauge | `{buffers}` | Buffers received | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.buffers.received` | Gauge | `{buffers}` | Buffers received | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.buffers.received` Attributes +### `ibm.mq.buffers.received` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -132,14 +132,14 @@ -## Metric `mq.buffers.sent` +## Metric `ibm.mq.buffers.sent` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.buffers.sent` | Gauge | `{buffers}` | Buffers sent | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.buffers.sent` | Gauge | `{buffers}` | Buffers sent | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.buffers.sent` Attributes +### `ibm.mq.buffers.sent` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -151,14 +151,14 @@ -## Metric `mq.message.count` +## Metric `ibm.mq.message.count` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.message.count` | Gauge | `{messages}` | Message count | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.message.count` | Gauge | `{messages}` | Message count | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.message.count` Attributes +### `ibm.mq.message.count` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -170,14 +170,14 @@ -## Metric `mq.open.input.count` +## Metric `ibm.mq.open.input.count` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.open.input.count` | Gauge | `{applications}` | Count of applications sending messages to the queue | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.open.input.count` | Gauge | `{applications}` | Count of applications sending messages to the queue | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.open.input.count` Attributes +### `ibm.mq.open.input.count` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -187,14 +187,14 @@ -## Metric `mq.open.output.count` +## Metric `ibm.mq.open.output.count` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.open.output.count` | Gauge | `{applications}` | Count of applications consuming messages from the queue | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.open.output.count` | Gauge | `{applications}` | Count of applications consuming messages from the queue | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.open.output.count` Attributes +### `ibm.mq.open.output.count` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -204,14 +204,14 @@ -## Metric `mq.high.queue.depth` +## Metric `ibm.mq.high.queue.depth` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.high.queue.depth` | Gauge | `{percent}` | The current high queue depth | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.high.queue.depth` | Gauge | `{percent}` | The current high queue depth | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.high.queue.depth` Attributes +### `ibm.mq.high.queue.depth` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -221,14 +221,14 @@ -## Metric `mq.service.interval` +## Metric `ibm.mq.service.interval` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.service.interval` | Gauge | `{percent}` | The queue service interval | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.service.interval` | Gauge | `{percent}` | The queue service interval | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.service.interval` Attributes +### `ibm.mq.service.interval` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -238,14 +238,14 @@ -## Metric `mq.queue.depth.full.event` +## Metric `ibm.mq.queue.depth.full.event` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.queue.depth.full.event` | Counter | `{events}` | The number of full queue events | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.depth.full.event` | Counter | `{events}` | The number of full queue events | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.queue.depth.full.event` Attributes +### `ibm.mq.queue.depth.full.event` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -254,14 +254,14 @@ -## Metric `mq.queue.depth.high.event` +## Metric `ibm.mq.queue.depth.high.event` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.queue.depth.high.event` | Counter | `{events}` | The number of high queue events | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.depth.high.event` | Counter | `{events}` | The number of high queue events | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.queue.depth.high.event` Attributes +### `ibm.mq.queue.depth.high.event` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -270,14 +270,14 @@ -## Metric `mq.queue.depth.low.event` +## Metric `ibm.mq.queue.depth.low.event` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.queue.depth.low.event` | Counter | `{events}` | The number of low queue events | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.depth.low.event` | Counter | `{events}` | The number of low queue events | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.queue.depth.low.event` Attributes +### `ibm.mq.queue.depth.low.event` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -286,14 +286,14 @@ -## Metric `mq.uncommitted.messages` +## Metric `ibm.mq.uncommitted.messages` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.uncommitted.messages` | Gauge | `{messages}` | Number of uncommitted messages | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.uncommitted.messages` | Gauge | `{messages}` | Number of uncommitted messages | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.uncommitted.messages` Attributes +### `ibm.mq.uncommitted.messages` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -303,14 +303,14 @@ -## Metric `mq.oldest.msg.age` +## Metric `ibm.mq.oldest.msg.age` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.oldest.msg.age` | Gauge | `microseconds` | Queue message oldest age | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.oldest.msg.age` | Gauge | `microseconds` | Queue message oldest age | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.oldest.msg.age` Attributes +### `ibm.mq.oldest.msg.age` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -320,14 +320,14 @@ -## Metric `mq.current.max.queue.filesize` +## Metric `ibm.mq.current.max.queue.filesize` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.current.max.queue.filesize` | Gauge | `mib` | Current maximum queue file size | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.current.max.queue.filesize` | Gauge | `mib` | Current maximum queue file size | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.current.max.queue.filesize` Attributes +### `ibm.mq.current.max.queue.filesize` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -337,14 +337,14 @@ -## Metric `mq.current.queue.filesize` +## Metric `ibm.mq.current.queue.filesize` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.current.queue.filesize` | Gauge | `mib` | Current queue file size | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.current.queue.filesize` | Gauge | `mib` | Current queue file size | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.current.queue.filesize` Attributes +### `ibm.mq.current.queue.filesize` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -354,14 +354,14 @@ -## Metric `mq.instances.per.client` +## Metric `ibm.mq.instances.per.client` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.instances.per.client` | Gauge | `{instances}` | Instances per client | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.instances.per.client` | Gauge | `{instances}` | Instances per client | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.instances.per.client` Attributes +### `ibm.mq.instances.per.client` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -371,14 +371,14 @@ -## Metric `mq.message.deq.count` +## Metric `ibm.mq.message.deq.count` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.message.deq.count` | Gauge | `{messages}` | Message dequeue count | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.message.deq.count` | Gauge | `{messages}` | Message dequeue count | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.message.deq.count` Attributes +### `ibm.mq.message.deq.count` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -388,14 +388,14 @@ -## Metric `mq.message.enq.count` +## Metric `ibm.mq.message.enq.count` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.message.enq.count` | Gauge | `{messages}` | Message enqueue count | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.message.enq.count` | Gauge | `{messages}` | Message enqueue count | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.message.enq.count` Attributes +### `ibm.mq.message.enq.count` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -405,14 +405,14 @@ -## Metric `mq.queue.depth` +## Metric `ibm.mq.queue.depth` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.queue.depth` | Gauge | `{messages}` | Current queue depth | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.depth` | Gauge | `{messages}` | Current queue depth | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.queue.depth` Attributes +### `ibm.mq.queue.depth` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -422,14 +422,14 @@ -## Metric `mq.service.interval.event` +## Metric `ibm.mq.service.interval.event` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.service.interval.event` | Gauge | `1` | Queue service interval event | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.service.interval.event` | Gauge | `1` | Queue service interval event | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.service.interval.event` Attributes +### `ibm.mq.service.interval.event` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -439,14 +439,14 @@ -## Metric `mq.reusable.log.size` +## Metric `ibm.mq.reusable.log.size` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.reusable.log.size` | Gauge | `mib` | The amount of space occupied, in megabytes, by log extents available to be reused. | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.reusable.log.size` | Gauge | `mib` | The amount of space occupied, in megabytes, by log extents available to be reused. | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.reusable.log.size` Attributes +### `ibm.mq.reusable.log.size` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -454,14 +454,14 @@ -## Metric `mq.manager.active.channels` +## Metric `ibm.mq.manager.active.channels` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.manager.active.channels` | Gauge | `{channels}` | The queue manager active maximum channels limit | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.manager.active.channels` | Gauge | `{channels}` | The queue manager active maximum channels limit | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.manager.active.channels` Attributes +### `ibm.mq.manager.active.channels` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -469,14 +469,14 @@ -## Metric `mq.restart.log.size` +## Metric `ibm.mq.restart.log.size` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.restart.log.size` | Gauge | `mib` | Size of the log data required for restart recovery in megabytes. | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.restart.log.size` | Gauge | `mib` | Size of the log data required for restart recovery in megabytes. | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.restart.log.size` Attributes +### `ibm.mq.restart.log.size` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -484,14 +484,14 @@ -## Metric `mq.max.queue.depth` +## Metric `ibm.mq.max.queue.depth` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.max.queue.depth` | Gauge | `{messages}` | Maximum queue depth | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.max.queue.depth` | Gauge | `{messages}` | Maximum queue depth | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.max.queue.depth` Attributes +### `ibm.mq.max.queue.depth` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -501,14 +501,14 @@ -## Metric `mq.onqtime.1` +## Metric `ibm.mq.onqtime.1` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.onqtime.1` | Gauge | `microseconds` | Amount of time, in microseconds, that a message spent on the queue, over a short period | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.onqtime.1` | Gauge | `microseconds` | Amount of time, in microseconds, that a message spent on the queue, over a short period | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.onqtime.1` Attributes +### `ibm.mq.onqtime.1` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -518,14 +518,14 @@ -## Metric `mq.onqtime.2` +## Metric `ibm.mq.onqtime.2` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.onqtime.2` | Gauge | `microseconds` | Amount of time, in microseconds, that a message spent on the queue, over a longer period | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.onqtime.2` | Gauge | `microseconds` | Amount of time, in microseconds, that a message spent on the queue, over a longer period | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.onqtime.2` Attributes +### `ibm.mq.onqtime.2` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -535,14 +535,14 @@ -## Metric `mq.message.received.count` +## Metric `ibm.mq.message.received.count` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.message.received.count` | Gauge | `{messages}` | Number of messages received | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.message.received.count` | Gauge | `{messages}` | Number of messages received | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.message.received.count` Attributes +### `ibm.mq.message.received.count` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -552,14 +552,14 @@ -## Metric `mq.message.sent.count` +## Metric `ibm.mq.message.sent.count` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.message.sent.count` | Gauge | `{messages}` | Number of messages sent | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.message.sent.count` | Gauge | `{messages}` | Number of messages sent | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.message.sent.count` Attributes +### `ibm.mq.message.sent.count` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -569,14 +569,14 @@ -## Metric `mq.max.instances` +## Metric `ibm.mq.max.instances` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.max.instances` | Gauge | `{instances}` | Max channel instances | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.max.instances` | Gauge | `{instances}` | Max channel instances | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.max.instances` Attributes +### `ibm.mq.max.instances` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -586,14 +586,14 @@ -## Metric `mq.connection.count` +## Metric `ibm.mq.connection.count` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.connection.count` | Gauge | `{connections}` | Active connections count | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.connection.count` | Gauge | `{connections}` | Active connections count | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.connection.count` Attributes +### `ibm.mq.connection.count` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -601,14 +601,14 @@ -## Metric `mq.manager.status` +## Metric `ibm.mq.manager.status` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.manager.status` | Gauge | `1` | Queue manager status | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.manager.status` | Gauge | `1` | Queue manager status | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.manager.status` Attributes +### `ibm.mq.manager.status` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -616,14 +616,14 @@ -## Metric `mq.heartbeat` +## Metric `ibm.mq.heartbeat` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.heartbeat` | Gauge | `1` | Queue manager heartbeat | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.heartbeat` | Gauge | `1` | Queue manager heartbeat | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.heartbeat` Attributes +### `ibm.mq.heartbeat` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -631,14 +631,14 @@ -## Metric `mq.archive.log.size` +## Metric `ibm.mq.archive.log.size` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.archive.log.size` | Gauge | `mib` | Queue manager archive log size | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.archive.log.size` | Gauge | `mib` | Queue manager archive log size | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.archive.log.size` Attributes +### `ibm.mq.archive.log.size` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -646,14 +646,14 @@ -## Metric `mq.manager.max.active.channels` +## Metric `ibm.mq.manager.max.active.channels` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.manager.max.active.channels` | Gauge | `{channels}` | Queue manager max active channels | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.manager.max.active.channels` | Gauge | `{channels}` | Queue manager max active channels | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.manager.max.active.channels` Attributes +### `ibm.mq.manager.max.active.channels` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -661,14 +661,14 @@ -## Metric `mq.manager.statistics.interval` +## Metric `ibm.mq.manager.statistics.interval` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.manager.statistics.interval` | Gauge | `1` | Queue manager statistics interval | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.manager.statistics.interval` | Gauge | `1` | Queue manager statistics interval | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.manager.statistics.interval` Attributes +### `ibm.mq.manager.statistics.interval` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -676,14 +676,14 @@ -## Metric `mq.publish.count` +## Metric `ibm.mq.publish.count` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.publish.count` | Gauge | `{publications}` | Topic publication count | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.publish.count` | Gauge | `{publications}` | Topic publication count | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.publish.count` Attributes +### `ibm.mq.publish.count` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -692,14 +692,14 @@ -## Metric `mq.subscription.count` +## Metric `ibm.mq.subscription.count` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.subscription.count` | Gauge | `{subscriptions}` | Topic subscription count | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.subscription.count` | Gauge | `{subscriptions}` | Topic subscription count | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.subscription.count` Attributes +### `ibm.mq.subscription.count` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -708,14 +708,14 @@ -## Metric `mq.listener.status` +## Metric `ibm.mq.listener.status` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.listener.status` | Gauge | `1` | Listener status | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.listener.status` | Gauge | `1` | Listener status | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.listener.status` Attributes +### `ibm.mq.listener.status` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -724,14 +724,14 @@ -## Metric `mq.unauthorized.event` +## Metric `ibm.mq.unauthorized.event` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.unauthorized.event` | Counter | `{events}` | Number of authentication error events | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.unauthorized.event` | Counter | `{events}` | Number of authentication error events | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.unauthorized.event` Attributes +### `ibm.mq.unauthorized.event` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -741,14 +741,14 @@ -## Metric `mq.manager.max.handles` +## Metric `ibm.mq.manager.max.handles` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `mq.manager.max.handles` | Gauge | `{events}` | Max open handles | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.manager.max.handles` | Gauge | `{events}` | Max open handles | ![Development](https://img.shields.io/badge/-development-blue) | -### `mq.manager.max.handles` Attributes +### `ibm.mq.manager.max.handles` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqMonitor.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqMonitor.java index 496c7f95b..421db2d25 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqMonitor.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqMonitor.java @@ -106,7 +106,7 @@ public void run(QueueManager queueManager) { e.getMessage(), e); } finally { - if (this.metricsConfig.isMqHeartbeatEnabled()) { + if (this.metricsConfig.isIbmMqHeartbeatEnabled()) { heartbeatGauge.set( heartBeatMetricValue, Attributes.of(AttributeKey.stringKey("queue.manager"), queueManagerName)); 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 1878e9205..94fd4180b 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 @@ -15,231 +15,231 @@ public final class Metrics { private Metrics() {} - public static LongGauge createMqMessageRetryCount(Meter meter) { + public static LongGauge createIbmMqMessageRetryCount(Meter meter) { return meter - .gaugeBuilder("mq.message.retry.count") + .gaugeBuilder("ibm.mq.message.retry.count") .ofLongs() .setUnit("{messages}") .setDescription("Number of message retries") .build(); } - public static LongGauge createMqStatus(Meter meter) { + public static LongGauge createIbmMqStatus(Meter meter) { return meter - .gaugeBuilder("mq.status") + .gaugeBuilder("ibm.mq.status") .ofLongs() .setUnit("1") .setDescription("Channel status") .build(); } - public static LongGauge createMqMaxSharingConversations(Meter meter) { + public static LongGauge createIbmMqMaxSharingConversations(Meter meter) { return meter - .gaugeBuilder("mq.max.sharing.conversations") + .gaugeBuilder("ibm.mq.max.sharing.conversations") .ofLongs() .setUnit("{conversations}") .setDescription("Maximum number of conversations permitted on this channel instance.") .build(); } - public static LongGauge createMqCurrentSharingConversations(Meter meter) { + public static LongGauge createIbmMqCurrentSharingConversations(Meter meter) { return meter - .gaugeBuilder("mq.current.sharing.conversations") + .gaugeBuilder("ibm.mq.current.sharing.conversations") .ofLongs() .setUnit("{conversations}") .setDescription("Current number of conversations permitted on this channel instance.") .build(); } - public static LongGauge createMqByteReceived(Meter meter) { + public static LongGauge createIbmMqByteReceived(Meter meter) { return meter - .gaugeBuilder("mq.byte.received") + .gaugeBuilder("ibm.mq.byte.received") .ofLongs() .setUnit("{bytes}") .setDescription("Number of bytes received") .build(); } - public static LongGauge createMqByteSent(Meter meter) { + public static LongGauge createIbmMqByteSent(Meter meter) { return meter - .gaugeBuilder("mq.byte.sent") + .gaugeBuilder("ibm.mq.byte.sent") .ofLongs() .setUnit("{bytes}") .setDescription("Number of bytes sent") .build(); } - public static LongGauge createMqBuffersReceived(Meter meter) { + public static LongGauge createIbmMqBuffersReceived(Meter meter) { return meter - .gaugeBuilder("mq.buffers.received") + .gaugeBuilder("ibm.mq.buffers.received") .ofLongs() .setUnit("{buffers}") .setDescription("Buffers received") .build(); } - public static LongGauge createMqBuffersSent(Meter meter) { + public static LongGauge createIbmMqBuffersSent(Meter meter) { return meter - .gaugeBuilder("mq.buffers.sent") + .gaugeBuilder("ibm.mq.buffers.sent") .ofLongs() .setUnit("{buffers}") .setDescription("Buffers sent") .build(); } - public static LongGauge createMqMessageCount(Meter meter) { + public static LongGauge createIbmMqMessageCount(Meter meter) { return meter - .gaugeBuilder("mq.message.count") + .gaugeBuilder("ibm.mq.message.count") .ofLongs() .setUnit("{messages}") .setDescription("Message count") .build(); } - public static LongGauge createMqOpenInputCount(Meter meter) { + public static LongGauge createIbmMqOpenInputCount(Meter meter) { return meter - .gaugeBuilder("mq.open.input.count") + .gaugeBuilder("ibm.mq.open.input.count") .ofLongs() .setUnit("{applications}") .setDescription("Count of applications sending messages to the queue") .build(); } - public static LongGauge createMqOpenOutputCount(Meter meter) { + public static LongGauge createIbmMqOpenOutputCount(Meter meter) { return meter - .gaugeBuilder("mq.open.output.count") + .gaugeBuilder("ibm.mq.open.output.count") .ofLongs() .setUnit("{applications}") .setDescription("Count of applications consuming messages from the queue") .build(); } - public static LongGauge createMqHighQueueDepth(Meter meter) { + public static LongGauge createIbmMqHighQueueDepth(Meter meter) { return meter - .gaugeBuilder("mq.high.queue.depth") + .gaugeBuilder("ibm.mq.high.queue.depth") .ofLongs() .setUnit("{percent}") .setDescription("The current high queue depth") .build(); } - public static LongGauge createMqServiceInterval(Meter meter) { + public static LongGauge createIbmMqServiceInterval(Meter meter) { return meter - .gaugeBuilder("mq.service.interval") + .gaugeBuilder("ibm.mq.service.interval") .ofLongs() .setUnit("{percent}") .setDescription("The queue service interval") .build(); } - public static LongCounter createMqQueueDepthFullEvent(Meter meter) { + public static LongCounter createIbmMqQueueDepthFullEvent(Meter meter) { return meter - .counterBuilder("mq.queue.depth.full.event") + .counterBuilder("ibm.mq.queue.depth.full.event") .setUnit("{events}") .setDescription("The number of full queue events") .build(); } - public static LongCounter createMqQueueDepthHighEvent(Meter meter) { + public static LongCounter createIbmMqQueueDepthHighEvent(Meter meter) { return meter - .counterBuilder("mq.queue.depth.high.event") + .counterBuilder("ibm.mq.queue.depth.high.event") .setUnit("{events}") .setDescription("The number of high queue events") .build(); } - public static LongCounter createMqQueueDepthLowEvent(Meter meter) { + public static LongCounter createIbmMqQueueDepthLowEvent(Meter meter) { return meter - .counterBuilder("mq.queue.depth.low.event") + .counterBuilder("ibm.mq.queue.depth.low.event") .setUnit("{events}") .setDescription("The number of low queue events") .build(); } - public static LongGauge createMqUncommittedMessages(Meter meter) { + public static LongGauge createIbmMqUncommittedMessages(Meter meter) { return meter - .gaugeBuilder("mq.uncommitted.messages") + .gaugeBuilder("ibm.mq.uncommitted.messages") .ofLongs() .setUnit("{messages}") .setDescription("Number of uncommitted messages") .build(); } - public static LongGauge createMqOldestMsgAge(Meter meter) { + public static LongGauge createIbmMqOldestMsgAge(Meter meter) { return meter - .gaugeBuilder("mq.oldest.msg.age") + .gaugeBuilder("ibm.mq.oldest.msg.age") .ofLongs() .setUnit("microseconds") .setDescription("Queue message oldest age") .build(); } - public static LongGauge createMqCurrentMaxQueueFilesize(Meter meter) { + public static LongGauge createIbmMqCurrentMaxQueueFilesize(Meter meter) { return meter - .gaugeBuilder("mq.current.max.queue.filesize") + .gaugeBuilder("ibm.mq.current.max.queue.filesize") .ofLongs() .setUnit("mib") .setDescription("Current maximum queue file size") .build(); } - public static LongGauge createMqCurrentQueueFilesize(Meter meter) { + public static LongGauge createIbmMqCurrentQueueFilesize(Meter meter) { return meter - .gaugeBuilder("mq.current.queue.filesize") + .gaugeBuilder("ibm.mq.current.queue.filesize") .ofLongs() .setUnit("mib") .setDescription("Current queue file size") .build(); } - public static LongGauge createMqInstancesPerClient(Meter meter) { + public static LongGauge createIbmMqInstancesPerClient(Meter meter) { return meter - .gaugeBuilder("mq.instances.per.client") + .gaugeBuilder("ibm.mq.instances.per.client") .ofLongs() .setUnit("{instances}") .setDescription("Instances per client") .build(); } - public static LongGauge createMqMessageDeqCount(Meter meter) { + public static LongGauge createIbmMqMessageDeqCount(Meter meter) { return meter - .gaugeBuilder("mq.message.deq.count") + .gaugeBuilder("ibm.mq.message.deq.count") .ofLongs() .setUnit("{messages}") .setDescription("Message dequeue count") .build(); } - public static LongGauge createMqMessageEnqCount(Meter meter) { + public static LongGauge createIbmMqMessageEnqCount(Meter meter) { return meter - .gaugeBuilder("mq.message.enq.count") + .gaugeBuilder("ibm.mq.message.enq.count") .ofLongs() .setUnit("{messages}") .setDescription("Message enqueue count") .build(); } - public static LongGauge createMqQueueDepth(Meter meter) { + public static LongGauge createIbmMqQueueDepth(Meter meter) { return meter - .gaugeBuilder("mq.queue.depth") + .gaugeBuilder("ibm.mq.queue.depth") .ofLongs() .setUnit("{messages}") .setDescription("Current queue depth") .build(); } - public static LongGauge createMqServiceIntervalEvent(Meter meter) { + public static LongGauge createIbmMqServiceIntervalEvent(Meter meter) { return meter - .gaugeBuilder("mq.service.interval.event") + .gaugeBuilder("ibm.mq.service.interval.event") .ofLongs() .setUnit("1") .setDescription("Queue service interval event") .build(); } - public static LongGauge createMqReusableLogSize(Meter meter) { + public static LongGauge createIbmMqReusableLogSize(Meter meter) { return meter - .gaugeBuilder("mq.reusable.log.size") + .gaugeBuilder("ibm.mq.reusable.log.size") .ofLongs() .setUnit("mib") .setDescription( @@ -247,36 +247,36 @@ public static LongGauge createMqReusableLogSize(Meter meter) { .build(); } - public static LongGauge createMqManagerActiveChannels(Meter meter) { + public static LongGauge createIbmMqManagerActiveChannels(Meter meter) { return meter - .gaugeBuilder("mq.manager.active.channels") + .gaugeBuilder("ibm.mq.manager.active.channels") .ofLongs() .setUnit("{channels}") .setDescription("The queue manager active maximum channels limit") .build(); } - public static LongGauge createMqRestartLogSize(Meter meter) { + public static LongGauge createIbmMqRestartLogSize(Meter meter) { return meter - .gaugeBuilder("mq.restart.log.size") + .gaugeBuilder("ibm.mq.restart.log.size") .ofLongs() .setUnit("mib") .setDescription("Size of the log data required for restart recovery in megabytes.") .build(); } - public static LongGauge createMqMaxQueueDepth(Meter meter) { + public static LongGauge createIbmMqMaxQueueDepth(Meter meter) { return meter - .gaugeBuilder("mq.max.queue.depth") + .gaugeBuilder("ibm.mq.max.queue.depth") .ofLongs() .setUnit("{messages}") .setDescription("Maximum queue depth") .build(); } - public static LongGauge createMqOnqtime1(Meter meter) { + public static LongGauge createIbmMqOnqtime1(Meter meter) { return meter - .gaugeBuilder("mq.onqtime.1") + .gaugeBuilder("ibm.mq.onqtime.1") .ofLongs() .setUnit("microseconds") .setDescription( @@ -284,9 +284,9 @@ public static LongGauge createMqOnqtime1(Meter meter) { .build(); } - public static LongGauge createMqOnqtime2(Meter meter) { + public static LongGauge createIbmMqOnqtime2(Meter meter) { return meter - .gaugeBuilder("mq.onqtime.2") + .gaugeBuilder("ibm.mq.onqtime.2") .ofLongs() .setUnit("microseconds") .setDescription( @@ -294,125 +294,125 @@ public static LongGauge createMqOnqtime2(Meter meter) { .build(); } - public static LongGauge createMqMessageReceivedCount(Meter meter) { + public static LongGauge createIbmMqMessageReceivedCount(Meter meter) { return meter - .gaugeBuilder("mq.message.received.count") + .gaugeBuilder("ibm.mq.message.received.count") .ofLongs() .setUnit("{messages}") .setDescription("Number of messages received") .build(); } - public static LongGauge createMqMessageSentCount(Meter meter) { + public static LongGauge createIbmMqMessageSentCount(Meter meter) { return meter - .gaugeBuilder("mq.message.sent.count") + .gaugeBuilder("ibm.mq.message.sent.count") .ofLongs() .setUnit("{messages}") .setDescription("Number of messages sent") .build(); } - public static LongGauge createMqMaxInstances(Meter meter) { + public static LongGauge createIbmMqMaxInstances(Meter meter) { return meter - .gaugeBuilder("mq.max.instances") + .gaugeBuilder("ibm.mq.max.instances") .ofLongs() .setUnit("{instances}") .setDescription("Max channel instances") .build(); } - public static LongGauge createMqConnectionCount(Meter meter) { + public static LongGauge createIbmMqConnectionCount(Meter meter) { return meter - .gaugeBuilder("mq.connection.count") + .gaugeBuilder("ibm.mq.connection.count") .ofLongs() .setUnit("{connections}") .setDescription("Active connections count") .build(); } - public static LongGauge createMqManagerStatus(Meter meter) { + public static LongGauge createIbmMqManagerStatus(Meter meter) { return meter - .gaugeBuilder("mq.manager.status") + .gaugeBuilder("ibm.mq.manager.status") .ofLongs() .setUnit("1") .setDescription("Queue manager status") .build(); } - public static LongGauge createMqHeartbeat(Meter meter) { + public static LongGauge createIbmMqHeartbeat(Meter meter) { return meter - .gaugeBuilder("mq.heartbeat") + .gaugeBuilder("ibm.mq.heartbeat") .ofLongs() .setUnit("1") .setDescription("Queue manager heartbeat") .build(); } - public static LongGauge createMqArchiveLogSize(Meter meter) { + public static LongGauge createIbmMqArchiveLogSize(Meter meter) { return meter - .gaugeBuilder("mq.archive.log.size") + .gaugeBuilder("ibm.mq.archive.log.size") .ofLongs() .setUnit("mib") .setDescription("Queue manager archive log size") .build(); } - public static LongGauge createMqManagerMaxActiveChannels(Meter meter) { + public static LongGauge createIbmMqManagerMaxActiveChannels(Meter meter) { return meter - .gaugeBuilder("mq.manager.max.active.channels") + .gaugeBuilder("ibm.mq.manager.max.active.channels") .ofLongs() .setUnit("{channels}") .setDescription("Queue manager max active channels") .build(); } - public static LongGauge createMqManagerStatisticsInterval(Meter meter) { + public static LongGauge createIbmMqManagerStatisticsInterval(Meter meter) { return meter - .gaugeBuilder("mq.manager.statistics.interval") + .gaugeBuilder("ibm.mq.manager.statistics.interval") .ofLongs() .setUnit("1") .setDescription("Queue manager statistics interval") .build(); } - public static LongGauge createMqPublishCount(Meter meter) { + public static LongGauge createIbmMqPublishCount(Meter meter) { return meter - .gaugeBuilder("mq.publish.count") + .gaugeBuilder("ibm.mq.publish.count") .ofLongs() .setUnit("{publications}") .setDescription("Topic publication count") .build(); } - public static LongGauge createMqSubscriptionCount(Meter meter) { + public static LongGauge createIbmMqSubscriptionCount(Meter meter) { return meter - .gaugeBuilder("mq.subscription.count") + .gaugeBuilder("ibm.mq.subscription.count") .ofLongs() .setUnit("{subscriptions}") .setDescription("Topic subscription count") .build(); } - public static LongGauge createMqListenerStatus(Meter meter) { + public static LongGauge createIbmMqListenerStatus(Meter meter) { return meter - .gaugeBuilder("mq.listener.status") + .gaugeBuilder("ibm.mq.listener.status") .ofLongs() .setUnit("1") .setDescription("Listener status") .build(); } - public static LongCounter createMqUnauthorizedEvent(Meter meter) { + public static LongCounter createIbmMqUnauthorizedEvent(Meter meter) { return meter - .counterBuilder("mq.unauthorized.event") + .counterBuilder("ibm.mq.unauthorized.event") .setUnit("{events}") .setDescription("Number of authentication error events") .build(); } - public static LongGauge createMqManagerMaxHandles(Meter meter) { + public static LongGauge createIbmMqManagerMaxHandles(Meter meter) { return meter - .gaugeBuilder("mq.manager.max.handles") + .gaugeBuilder("ibm.mq.manager.max.handles") .ofLongs() .setUnit("{events}") .setDescription("Max open handles") 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 1fe9fb337..e52fc1f7b 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 @@ -19,184 +19,184 @@ public MetricsConfig(ConfigWrapper config) { this.config = config.getMetrics(); } - public boolean isMqMessageRetryCountEnabled() { - return isEnabled("mq.message.retry.count"); + public boolean isIbmMqMessageRetryCountEnabled() { + return isEnabled("ibm.mq.message.retry.count"); } - public boolean isMqStatusEnabled() { - return isEnabled("mq.status"); + public boolean isIbmMqStatusEnabled() { + return isEnabled("ibm.mq.status"); } - public boolean isMqMaxSharingConversationsEnabled() { - return isEnabled("mq.max.sharing.conversations"); + public boolean isIbmMqMaxSharingConversationsEnabled() { + return isEnabled("ibm.mq.max.sharing.conversations"); } - public boolean isMqCurrentSharingConversationsEnabled() { - return isEnabled("mq.current.sharing.conversations"); + public boolean isIbmMqCurrentSharingConversationsEnabled() { + return isEnabled("ibm.mq.current.sharing.conversations"); } - public boolean isMqByteReceivedEnabled() { - return isEnabled("mq.byte.received"); + public boolean isIbmMqByteReceivedEnabled() { + return isEnabled("ibm.mq.byte.received"); } - public boolean isMqByteSentEnabled() { - return isEnabled("mq.byte.sent"); + public boolean isIbmMqByteSentEnabled() { + return isEnabled("ibm.mq.byte.sent"); } - public boolean isMqBuffersReceivedEnabled() { - return isEnabled("mq.buffers.received"); + public boolean isIbmMqBuffersReceivedEnabled() { + return isEnabled("ibm.mq.buffers.received"); } - public boolean isMqBuffersSentEnabled() { - return isEnabled("mq.buffers.sent"); + public boolean isIbmMqBuffersSentEnabled() { + return isEnabled("ibm.mq.buffers.sent"); } - public boolean isMqMessageCountEnabled() { - return isEnabled("mq.message.count"); + public boolean isIbmMqMessageCountEnabled() { + return isEnabled("ibm.mq.message.count"); } - public boolean isMqOpenInputCountEnabled() { - return isEnabled("mq.open.input.count"); + public boolean isIbmMqOpenInputCountEnabled() { + return isEnabled("ibm.mq.open.input.count"); } - public boolean isMqOpenOutputCountEnabled() { - return isEnabled("mq.open.output.count"); + public boolean isIbmMqOpenOutputCountEnabled() { + return isEnabled("ibm.mq.open.output.count"); } - public boolean isMqHighQueueDepthEnabled() { - return isEnabled("mq.high.queue.depth"); + public boolean isIbmMqHighQueueDepthEnabled() { + return isEnabled("ibm.mq.high.queue.depth"); } - public boolean isMqServiceIntervalEnabled() { - return isEnabled("mq.service.interval"); + public boolean isIbmMqServiceIntervalEnabled() { + return isEnabled("ibm.mq.service.interval"); } - public boolean isMqQueueDepthFullEventEnabled() { - return isEnabled("mq.queue.depth.full.event"); + public boolean isIbmMqQueueDepthFullEventEnabled() { + return isEnabled("ibm.mq.queue.depth.full.event"); } - public boolean isMqQueueDepthHighEventEnabled() { - return isEnabled("mq.queue.depth.high.event"); + public boolean isIbmMqQueueDepthHighEventEnabled() { + return isEnabled("ibm.mq.queue.depth.high.event"); } - public boolean isMqQueueDepthLowEventEnabled() { - return isEnabled("mq.queue.depth.low.event"); + public boolean isIbmMqQueueDepthLowEventEnabled() { + return isEnabled("ibm.mq.queue.depth.low.event"); } - public boolean isMqUncommittedMessagesEnabled() { - return isEnabled("mq.uncommitted.messages"); + public boolean isIbmMqUncommittedMessagesEnabled() { + return isEnabled("ibm.mq.uncommitted.messages"); } - public boolean isMqOldestMsgAgeEnabled() { - return isEnabled("mq.oldest.msg.age"); + public boolean isIbmMqOldestMsgAgeEnabled() { + return isEnabled("ibm.mq.oldest.msg.age"); } - public boolean isMqCurrentMaxQueueFilesizeEnabled() { - return isEnabled("mq.current.max.queue.filesize"); + public boolean isIbmMqCurrentMaxQueueFilesizeEnabled() { + return isEnabled("ibm.mq.current.max.queue.filesize"); } - public boolean isMqCurrentQueueFilesizeEnabled() { - return isEnabled("mq.current.queue.filesize"); + public boolean isIbmMqCurrentQueueFilesizeEnabled() { + return isEnabled("ibm.mq.current.queue.filesize"); } - public boolean isMqInstancesPerClientEnabled() { - return isEnabled("mq.instances.per.client"); + public boolean isIbmMqInstancesPerClientEnabled() { + return isEnabled("ibm.mq.instances.per.client"); } - public boolean isMqMessageDeqCountEnabled() { - return isEnabled("mq.message.deq.count"); + public boolean isIbmMqMessageDeqCountEnabled() { + return isEnabled("ibm.mq.message.deq.count"); } - public boolean isMqMessageEnqCountEnabled() { - return isEnabled("mq.message.enq.count"); + public boolean isIbmMqMessageEnqCountEnabled() { + return isEnabled("ibm.mq.message.enq.count"); } - public boolean isMqQueueDepthEnabled() { - return isEnabled("mq.queue.depth"); + public boolean isIbmMqQueueDepthEnabled() { + return isEnabled("ibm.mq.queue.depth"); } - public boolean isMqServiceIntervalEventEnabled() { - return isEnabled("mq.service.interval.event"); + public boolean isIbmMqServiceIntervalEventEnabled() { + return isEnabled("ibm.mq.service.interval.event"); } - public boolean isMqReusableLogSizeEnabled() { - return isEnabled("mq.reusable.log.size"); + public boolean isIbmMqReusableLogSizeEnabled() { + return isEnabled("ibm.mq.reusable.log.size"); } - public boolean isMqManagerActiveChannelsEnabled() { - return isEnabled("mq.manager.active.channels"); + public boolean isIbmMqManagerActiveChannelsEnabled() { + return isEnabled("ibm.mq.manager.active.channels"); } - public boolean isMqRestartLogSizeEnabled() { - return isEnabled("mq.restart.log.size"); + public boolean isIbmMqRestartLogSizeEnabled() { + return isEnabled("ibm.mq.restart.log.size"); } - public boolean isMqMaxQueueDepthEnabled() { - return isEnabled("mq.max.queue.depth"); + public boolean isIbmMqMaxQueueDepthEnabled() { + return isEnabled("ibm.mq.max.queue.depth"); } - public boolean isMqOnqtime1Enabled() { - return isEnabled("mq.onqtime.1"); + public boolean isIbmMqOnqtime1Enabled() { + return isEnabled("ibm.mq.onqtime.1"); } - public boolean isMqOnqtime2Enabled() { - return isEnabled("mq.onqtime.2"); + public boolean isIbmMqOnqtime2Enabled() { + return isEnabled("ibm.mq.onqtime.2"); } - public boolean isMqMessageReceivedCountEnabled() { - return isEnabled("mq.message.received.count"); + public boolean isIbmMqMessageReceivedCountEnabled() { + return isEnabled("ibm.mq.message.received.count"); } - public boolean isMqMessageSentCountEnabled() { - return isEnabled("mq.message.sent.count"); + public boolean isIbmMqMessageSentCountEnabled() { + return isEnabled("ibm.mq.message.sent.count"); } - public boolean isMqMaxInstancesEnabled() { - return isEnabled("mq.max.instances"); + public boolean isIbmMqMaxInstancesEnabled() { + return isEnabled("ibm.mq.max.instances"); } - public boolean isMqConnectionCountEnabled() { - return isEnabled("mq.connection.count"); + public boolean isIbmMqConnectionCountEnabled() { + return isEnabled("ibm.mq.connection.count"); } - public boolean isMqManagerStatusEnabled() { - return isEnabled("mq.manager.status"); + public boolean isIbmMqManagerStatusEnabled() { + return isEnabled("ibm.mq.manager.status"); } - public boolean isMqHeartbeatEnabled() { - return isEnabled("mq.heartbeat"); + public boolean isIbmMqHeartbeatEnabled() { + return isEnabled("ibm.mq.heartbeat"); } - public boolean isMqArchiveLogSizeEnabled() { - return isEnabled("mq.archive.log.size"); + public boolean isIbmMqArchiveLogSizeEnabled() { + return isEnabled("ibm.mq.archive.log.size"); } - public boolean isMqManagerMaxActiveChannelsEnabled() { - return isEnabled("mq.manager.max.active.channels"); + public boolean isIbmMqManagerMaxActiveChannelsEnabled() { + return isEnabled("ibm.mq.manager.max.active.channels"); } - public boolean isMqManagerStatisticsIntervalEnabled() { - return isEnabled("mq.manager.statistics.interval"); + public boolean isIbmMqManagerStatisticsIntervalEnabled() { + return isEnabled("ibm.mq.manager.statistics.interval"); } - public boolean isMqPublishCountEnabled() { - return isEnabled("mq.publish.count"); + public boolean isIbmMqPublishCountEnabled() { + return isEnabled("ibm.mq.publish.count"); } - public boolean isMqSubscriptionCountEnabled() { - return isEnabled("mq.subscription.count"); + public boolean isIbmMqSubscriptionCountEnabled() { + return isEnabled("ibm.mq.subscription.count"); } - public boolean isMqListenerStatusEnabled() { - return isEnabled("mq.listener.status"); + public boolean isIbmMqListenerStatusEnabled() { + return isEnabled("ibm.mq.listener.status"); } - public boolean isMqUnauthorizedEventEnabled() { - return isEnabled("mq.unauthorized.event"); + public boolean isIbmMqUnauthorizedEventEnabled() { + return isEnabled("ibm.mq.unauthorized.event"); } - public boolean isMqManagerMaxHandlesEnabled() { - return isEnabled("mq.manager.max.handles"); + public boolean isIbmMqManagerMaxHandlesEnabled() { + return isEnabled("ibm.mq.manager.max.handles"); } private boolean isEnabled(String key) { diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollector.java index 7182e9daf..23d83c35b 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollector.java @@ -44,15 +44,15 @@ public final class ChannelMetricsCollector implements Consumer Date: Wed, 16 Jul 2025 09:21:48 -0700 Subject: [PATCH 42/66] fix tests --- .../ChannelMetricsCollectorTest.java | 26 +++--- .../InquireChannelCmdCollectorTest.java | 10 ++- .../ListenerMetricsCollectorTest.java | 2 +- .../QueueCollectionBuddyTest.java | 36 ++++---- .../QueueManagerMetricsCollectorTest.java | 2 +- .../TopicMetricsCollectorTest.java | 6 +- .../src/test/resources/conf/config.yml | 90 +++++++++---------- 7 files changed, 87 insertions(+), 85 deletions(-) diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollectorTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollectorTest.java index 8bf675827..b4ae65e88 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollectorTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollectorTest.java @@ -71,37 +71,37 @@ void testPublishMetrics() throws Exception { List metricsList = new ArrayList<>( Arrays.asList( - "mq.message.count", - "mq.status", - "mq.byte.sent", - "mq.byte.received", - "mq.buffers.sent", - "mq.buffers.received")); + "ibm.mq.message.count", + "ibm.mq.status", + "ibm.mq.byte.sent", + "ibm.mq.byte.received", + "ibm.mq.buffers.sent", + "ibm.mq.buffers.received")); for (MetricData metric : otelTesting.getMetrics()) { if (metricsList.remove(metric.getName())) { - if (metric.getName().equals("mq.message.count")) { + if (metric.getName().equals("ibm.mq.message.count")) { assertThat(metric.getLongGaugeData().getPoints().iterator().next().getValue()) .isEqualTo(17); } - if (metric.getName().equals("mq.status")) { + if (metric.getName().equals("ibm.mq.status")) { assertThat(metric.getLongGaugeData().getPoints().iterator().next().getValue()) .isEqualTo(3); } - if (metric.getName().equals("mq.byte.sent")) { + if (metric.getName().equals("ibm.mq.byte.sent")) { assertThat(metric.getLongGaugeData().getPoints().iterator().next().getValue()) .isEqualTo(6984); } - if (metric.getName().equals("mq.byte.received")) { + if (metric.getName().equals("ibm.mq.byte.received")) { assertThat(metric.getLongGaugeData().getPoints().iterator().next().getValue()) .isEqualTo(5772); } - if (metric.getName().equals("mq.buffers.sent")) { + if (metric.getName().equals("ibm.mq.buffers.sent")) { assertThat(metric.getLongGaugeData().getPoints().iterator().next().getValue()) .isEqualTo(19); } - if (metric.getName().equals("mq.buffers.received")) { + if (metric.getName().equals("ibm.mq.buffers.received")) { assertThat(metric.getLongGaugeData().getPoints().iterator().next().getValue()) .isEqualTo(20); } @@ -214,7 +214,7 @@ void testPublishMetrics_pfException(Exception exceptionToThrow) throws Exception List exported = otelTesting.getMetrics(); assertThat(exported.get(0).getLongGaugeData().getPoints()).hasSize(1); - assertThatMetric(exported.get(0), 0).hasName("mq.manager.active.channels").hasValue(0); + assertThatMetric(exported.get(0), 0).hasName("ibm.mq.manager.active.channels").hasValue(0); } static Stream exceptionsToThrow() { diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollectorTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollectorTest.java index 2dced05ea..a0e06e336 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollectorTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollectorTest.java @@ -62,18 +62,20 @@ public void testProcessPCFRequestAndPublishQMetricsForInquireQStatusCmd() throws List metricsList = new ArrayList<>( Arrays.asList( - "mq.message.retry.count", "mq.message.received.count", "mq.message.sent.count")); + "ibm.mq.message.retry.count", + "ibm.mq.message.received.count", + "ibm.mq.message.sent.count")); for (MetricData metric : otelTesting.getMetrics()) { if (metricsList.remove(metric.getName())) { - if (metric.getName().equals("mq.message.retry.count")) { + if (metric.getName().equals("ibm.mq.message.retry.count")) { assertThat(metric.getLongGaugeData().getPoints().iterator().next().getValue()) .isEqualTo(22); } - if (metric.getName().equals("mq.message.received.count")) { + if (metric.getName().equals("ibm.mq.message.received.count")) { assertThat(metric.getLongGaugeData().getPoints().iterator().next().getValue()) .isEqualTo(42); } - if (metric.getName().equals("mq.message.sent.count")) { + if (metric.getName().equals("ibm.mq.message.sent.count")) { assertThat(metric.getLongGaugeData().getPoints().iterator().next().getValue()) .isEqualTo(64); } diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollectorTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollectorTest.java index 8c8736ee7..6170e31f4 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollectorTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollectorTest.java @@ -59,7 +59,7 @@ public void testPublishMetrics() throws Exception { classUnderTest.accept(context); MetricData metric = otelTesting.getMetrics().get(0); - assertThat(metric.getName()).isEqualTo("mq.listener.status"); + assertThat(metric.getName()).isEqualTo("ibm.mq.listener.status"); Set values = new HashSet<>(); values.add(2L); values.add(3L); diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java index 8699534cb..082fc583a 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java @@ -72,19 +72,19 @@ void testProcessPcfRequestAndPublishQMetricsForInquireQStatusCmd() throws Except "DEV.DEAD.LETTER.QUEUE", new HashMap<>( ImmutableMap.of( - "mq.oldest.msg.age", -1L, - "mq.uncommitted.messages", 0L, - "mq.onqtime.1", -1L, - "mq.onqtime.2", -1L, - "mq.queue.depth", 0L)), + "ibm.mq.oldest.msg.age", -1L, + "ibm.mq.uncommitted.messages", 0L, + "ibm.mq.onqtime.1", -1L, + "ibm.mq.onqtime.2", -1L, + "ibm.mq.queue.depth", 0L)), "DEV.QUEUE.1", new HashMap( ImmutableMap.of( - "mq.oldest.msg.age", -1L, - "mq.uncommitted.messages", 10L, - "mq.onqtime.1", -1L, - "mq.onqtime.2", -1L, - "mq.queue.depth", 1L)))); + "ibm.mq.oldest.msg.age", -1L, + "ibm.mq.uncommitted.messages", 10L, + "ibm.mq.onqtime.1", -1L, + "ibm.mq.onqtime.2", -1L, + "ibm.mq.queue.depth", 1L)))); for (MetricData metric : otelTesting.getMetrics()) { for (LongPointData d : metric.getLongGaugeData().getPoints()) { @@ -113,17 +113,17 @@ void testProcessPcfRequestAndPublishQMetricsForInquireQCmd() throws Exception { "DEV.DEAD.LETTER.QUEUE", new HashMap<>( ImmutableMap.of( - "mq.queue.depth", 2L, - "mq.max.queue.depth", 5000L, - "mq.open.input.count", 2L, - "mq.open.output.count", 2L)), + "ibm.mq.queue.depth", 2L, + "ibm.mq.max.queue.depth", 5000L, + "ibm.mq.open.input.count", 2L, + "ibm.mq.open.output.count", 2L)), "DEV.QUEUE.1", new HashMap<>( ImmutableMap.of( - "mq.queue.depth", 3L, - "mq.max.queue.depth", 5000L, - "mq.open.input.count", 3L, - "mq.open.output.count", 3L)))); + "ibm.mq.queue.depth", 3L, + "ibm.mq.max.queue.depth", 5000L, + "ibm.mq.open.input.count", 3L, + "ibm.mq.open.output.count", 3L)))); for (MetricData metric : otelTesting.getMetrics()) { for (LongPointData d : metric.getLongGaugeData().getPoints()) { diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerMetricsCollectorTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerMetricsCollectorTest.java index 52578e4e3..dde400b02 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerMetricsCollectorTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerMetricsCollectorTest.java @@ -58,7 +58,7 @@ public void testProcessPCFRequestAndPublishQMetricsForInquireQStatusCmd() throws new QueueManagerMetricsCollector( otelTesting.getOpenTelemetry().getMeter("opentelemetry.io/mq")); classUnderTest.accept(context); - List metricsList = new ArrayList<>(singletonList("mq.manager.status")); + List metricsList = new ArrayList<>(singletonList("ibm.mq.manager.status")); for (MetricData metric : otelTesting.getMetrics()) { if (metricsList.remove(metric.getName())) { diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/TopicMetricsCollectorTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/TopicMetricsCollectorTest.java index 562adcc74..865501573 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/TopicMetricsCollectorTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/TopicMetricsCollectorTest.java @@ -63,11 +63,11 @@ void testPublishMetrics() throws Exception { classUnderTest.accept(context); List metricsList = - new ArrayList<>(Arrays.asList("mq.publish.count", "mq.subscription.count")); + new ArrayList<>(Arrays.asList("ibm.mq.publish.count", "ibm.mq.subscription.count")); for (MetricData metric : otelTesting.getMetrics()) { if (metricsList.remove(metric.getName())) { - if (metric.getName().equals("mq.publish.count")) { + if (metric.getName().equals("ibm.mq.publish.count")) { Set values = new HashSet<>(); values.add(2L); values.add(3L); @@ -77,7 +77,7 @@ void testPublishMetrics() throws Exception { .collect(Collectors.toSet())) .isEqualTo(values); } - if (metric.getName().equals("mq.subscription.count")) { + if (metric.getName().equals("ibm.mq.subscription.count")) { Set values = new HashSet<>(); values.add(3L); values.add(4L); diff --git a/ibm-mq-metrics/src/test/resources/conf/config.yml b/ibm-mq-metrics/src/test/resources/conf/config.yml index c53550cb8..e49bd9978 100644 --- a/ibm-mq-metrics/src/test/resources/conf/config.yml +++ b/ibm-mq-metrics/src/test/resources/conf/config.yml @@ -102,95 +102,95 @@ queueManagers: values: ["system","$SYS"] metrics: - "mq.message.retry.count": # Number of message retries + "ibm.mq.message.retry.count": # Number of message retries enabled: true - "mq.status": # Channel status + "ibm.mq.status": # Channel status enabled: true - "mq.max.sharing.conversations": # Maximum number of conversations permitted on this channel instance. + "ibm.mq.max.sharing.conversations": # Maximum number of conversations permitted on this channel instance. enabled: true - "mq.current.sharing.conversations": # Current number of conversations permitted on this channel instance. + "ibm.mq.current.sharing.conversations": # Current number of conversations permitted on this channel instance. enabled: true - "mq.byte.received": # Number of bytes received + "ibm.mq.byte.received": # Number of bytes received enabled: true - "mq.byte.sent": # Number of bytes sent + "ibm.mq.byte.sent": # Number of bytes sent enabled: true - "mq.buffers.received": # Buffers received + "ibm.mq.buffers.received": # Buffers received enabled: true - "mq.buffers.sent": # Buffers sent + "ibm.mq.buffers.sent": # Buffers sent enabled: true - "mq.message.count": # Message count + "ibm.mq.message.count": # Message count enabled: true - "mq.open.input.count": # Count of applications sending messages to the queue + "ibm.mq.open.input.count": # Count of applications sending messages to the queue enabled: true - "mq.open.output.count": # Count of applications consuming messages from the queue + "ibm.mq.open.output.count": # Count of applications consuming messages from the queue enabled: true - "mq.high.queue.depth": # The current high queue depth + "ibm.mq.high.queue.depth": # The current high queue depth enabled: true - "mq.service.interval": # The queue service interval + "ibm.mq.service.interval": # The queue service interval enabled: true - "mq.queue.depth.full.event": # The number of full queue events + "ibm.mq.queue.depth.full.event": # The number of full queue events enabled: true - "mq.queue.depth.high.event": # The number of high queue events + "ibm.mq.queue.depth.high.event": # The number of high queue events enabled: true - "mq.queue.depth.low.event": # The number of low queue events + "ibm.mq.queue.depth.low.event": # The number of low queue events enabled: true - "mq.uncommitted.messages": # Number of uncommitted messages + "ibm.mq.uncommitted.messages": # Number of uncommitted messages enabled: true - "mq.oldest.msg.age": # Queue message oldest age + "ibm.mq.oldest.msg.age": # Queue message oldest age enabled: true - "mq.current.max.queue.filesize": # Current maximum queue file size + "ibm.mq.current.max.queue.filesize": # Current maximum queue file size enabled: true - "mq.current.queue.filesize": # Current queue file size + "ibm.mq.current.queue.filesize": # Current queue file size enabled: true - "mq.instances.per.client": # Instances per client + "ibm.mq.instances.per.client": # Instances per client enabled: true - "mq.message.deq.count": # Message dequeue count + "ibm.mq.message.deq.count": # Message dequeue count enabled: true - "mq.message.enq.count": # Message enqueue count + "ibm.mq.message.enq.count": # Message enqueue count enabled: true - "mq.queue.depth": # Current queue depth + "ibm.mq.queue.depth": # Current queue depth enabled: true - "mq.service.interval.event": # Queue service interval event + "ibm.mq.service.interval.event": # Queue service interval event enabled: true - "mq.reusable.log.size": # The amount of space occupied, in megabytes, by log extents available to be reused. + "ibm.mq.reusable.log.size": # The amount of space occupied, in megabytes, by log extents available to be reused. enabled: true - "mq.manager.active.channels": # The queue manager active maximum channels limit + "ibm.mq.manager.active.channels": # The queue manager active maximum channels limit enabled: true - "mq.restart.log.size": # Size of the log data required for restart recovery in megabytes. + "ibm.mq.restart.log.size": # Size of the log data required for restart recovery in megabytes. enabled: true - "mq.max.queue.depth": # Maximum queue depth + "ibm.mq.max.queue.depth": # Maximum queue depth enabled: true - "mq.onqtime.1": # Amount of time, in microseconds, that a message spent on the queue, over a short period + "ibm.mq.onqtime.1": # Amount of time, in microseconds, that a message spent on the queue, over a short period enabled: true - "mq.onqtime.2": # Amount of time, in microseconds, that a message spent on the queue, over a longer period + "ibm.mq.onqtime.2": # Amount of time, in microseconds, that a message spent on the queue, over a longer period enabled: true - "mq.message.received.count": # Number of messages received + "ibm.mq.message.received.count": # Number of messages received enabled: true - "mq.message.sent.count": # Number of messages sent + "ibm.mq.message.sent.count": # Number of messages sent enabled: true - "mq.max.instances": # Max channel instances + "ibm.mq.max.instances": # Max channel instances enabled: true - "mq.connection.count": # Active connections count + "ibm.mq.connection.count": # Active connections count enabled: true - "mq.manager.status": # Queue manager status + "ibm.mq.manager.status": # Queue manager status enabled: true - "mq.heartbeat": # Queue manager heartbeat + "ibm.mq.heartbeat": # Queue manager heartbeat enabled: true - "mq.archive.log.size": # Queue manager archive log size + "ibm.mq.archive.log.size": # Queue manager archive log size enabled: true - "mq.manager.max.active.channels": # Queue manager max active channels + "ibm.mq.manager.max.active.channels": # Queue manager max active channels enabled: true - "mq.manager.statistics.interval": # Queue manager statistics interval + "ibm.mq.manager.statistics.interval": # Queue manager statistics interval enabled: true - "mq.publish.count": # Topic publication count + "ibm.mq.publish.count": # Topic publication count enabled: true - "mq.subscription.count": # Topic subscription count + "ibm.mq.subscription.count": # Topic subscription count enabled: true - "mq.listener.status": # Listener status + "ibm.mq.listener.status": # Listener status enabled: true - "mq.unauthorized.event": # Number of authentication error events + "ibm.mq.unauthorized.event": # Number of authentication error events enabled: true - "mq.manager.max.handles": # Max open handles + "ibm.mq.manager.max.handles": # Max open handles enabled: true #Run it as a scheduled task instead of running every minute. From 751c32b6c480a1e0abb8371a9135151ac32f3829 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 16 Jul 2025 13:37:29 -0700 Subject: [PATCH 43/66] begin fixing up attributes and generate weaver template for constants (instead of duplicating these strings everywhere!) --- ibm-mq-metrics/docs/metrics.md | 296 ++++++++++-------- ibm-mq-metrics/model/attributes.yaml | 44 +-- ibm-mq-metrics/model/metrics.yaml | 248 +++++++-------- .../ibm/mq/metrics/IbmMqAttributes.java | 51 +++ .../InquireTStatusCmdCollector.java | 4 +- .../QueueManagerEventCollector.java | 2 +- .../registry/java/IbmMqAttributes.java.j2 | 27 ++ .../templates/registry/java/weaver.yaml | 9 +- 8 files changed, 406 insertions(+), 275 deletions(-) create mode 100644 ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metrics/IbmMqAttributes.java create mode 100644 ibm-mq-metrics/templates/registry/java/IbmMqAttributes.java.j2 diff --git a/ibm-mq-metrics/docs/metrics.md b/ibm-mq-metrics/docs/metrics.md index 2ab49328f..2f48b7868 100644 --- a/ibm-mq-metrics/docs/metrics.md +++ b/ibm-mq-metrics/docs/metrics.md @@ -12,9 +12,9 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | @@ -29,11 +29,11 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `channel.start.time` | int | The start time of the channel as seconds since Epoch. | `1748462702` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `job.name` | string | The job name | `0000074900000003` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.start.time` | int | The start time of the channel as seconds since Epoch. | `1748462702` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.job.name` | string | The job name | `0000074900000003` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | @@ -48,11 +48,11 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `channel.start.time` | int | The start time of the channel as seconds since Epoch. | `1748462702` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `job.name` | string | The job name | `0000074900000003` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.start.time` | int | The start time of the channel as seconds since Epoch. | `1748462702` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.job.name` | string | The job name | `0000074900000003` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | @@ -67,11 +67,11 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `channel.start.time` | int | The start time of the channel as seconds since Epoch. | `1748462702` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `job.name` | string | The job name | `0000074900000003` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.start.time` | int | The start time of the channel as seconds since Epoch. | `1748462702` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.job.name` | string | The job name | `0000074900000003` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | @@ -86,11 +86,11 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `channel.start.time` | int | The start time of the channel as seconds since Epoch. | `1748462702` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `job.name` | string | The job name | `0000074900000003` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.start.time` | int | The start time of the channel as seconds since Epoch. | `1748462702` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.job.name` | string | The job name | `0000074900000003` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | @@ -105,11 +105,11 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `channel.start.time` | int | The start time of the channel as seconds since Epoch. | `1748462702` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `job.name` | string | The job name | `0000074900000003` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.start.time` | int | The start time of the channel as seconds since Epoch. | `1748462702` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.job.name` | string | The job name | `0000074900000003` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | @@ -124,11 +124,11 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `channel.start.time` | int | The start time of the channel as seconds since Epoch. | `1748462702` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `job.name` | string | The job name | `0000074900000003` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.start.time` | int | The start time of the channel as seconds since Epoch. | `1748462702` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.job.name` | string | The job name | `0000074900000003` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | @@ -143,11 +143,11 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `channel.start.time` | int | The start time of the channel as seconds since Epoch. | `1748462702` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `job.name` | string | The job name | `0000074900000003` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.start.time` | int | The start time of the channel as seconds since Epoch. | `1748462702` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.job.name` | string | The job name | `0000074900000003` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | @@ -162,11 +162,11 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `channel.start.time` | int | The start time of the channel as seconds since Epoch. | `1748462702` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `job.name` | string | The job name | `0000074900000003` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.start.time` | int | The start time of the channel as seconds since Epoch. | `1748462702` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.job.name` | string | The job name | `0000074900000003` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | @@ -181,9 +181,11 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `messaging.destination.name` | string | The system-specific name of the messaging operation. [1] | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + +**[1] `messaging.destination.name`:** This is duplicated from otel semantic-conventions. @@ -198,9 +200,11 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `messaging.destination.name` | string | The system-specific name of the messaging operation. [2] | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + +**[2] `messaging.destination.name`:** This is duplicated from otel semantic-conventions. @@ -215,9 +219,11 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `messaging.destination.name` | string | The system-specific name of the messaging operation. [3] | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + +**[3] `messaging.destination.name`:** This is duplicated from otel semantic-conventions. @@ -232,9 +238,11 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `messaging.destination.name` | string | The system-specific name of the messaging operation. [4] | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + +**[4] `messaging.destination.name`:** This is duplicated from otel semantic-conventions. @@ -249,8 +257,10 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `messaging.destination.name` | string | The system-specific name of the messaging operation. [5] | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + +**[5] `messaging.destination.name`:** This is duplicated from otel semantic-conventions. @@ -265,8 +275,10 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `messaging.destination.name` | string | The system-specific name of the messaging operation. [6] | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + +**[6] `messaging.destination.name`:** This is duplicated from otel semantic-conventions. @@ -281,8 +293,10 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `messaging.destination.name` | string | The system-specific name of the messaging operation. [7] | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + +**[7] `messaging.destination.name`:** This is duplicated from otel semantic-conventions. @@ -297,9 +311,11 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `messaging.destination.name` | string | The system-specific name of the messaging operation. [8] | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + +**[8] `messaging.destination.name`:** This is duplicated from otel semantic-conventions. @@ -314,9 +330,11 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `messaging.destination.name` | string | The system-specific name of the messaging operation. [9] | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + +**[9] `messaging.destination.name`:** This is duplicated from otel semantic-conventions. @@ -331,9 +349,11 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `messaging.destination.name` | string | The system-specific name of the messaging operation. [10] | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + +**[10] `messaging.destination.name`:** This is duplicated from otel semantic-conventions. @@ -348,9 +368,11 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `messaging.destination.name` | string | The system-specific name of the messaging operation. [11] | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + +**[11] `messaging.destination.name`:** This is duplicated from otel semantic-conventions. @@ -365,9 +387,11 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `messaging.destination.name` | string | The system-specific name of the messaging operation. [12] | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + +**[12] `messaging.destination.name`:** This is duplicated from otel semantic-conventions. @@ -382,9 +406,11 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `messaging.destination.name` | string | The system-specific name of the messaging operation. [13] | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + +**[13] `messaging.destination.name`:** This is duplicated from otel semantic-conventions. @@ -399,9 +425,11 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `messaging.destination.name` | string | The system-specific name of the messaging operation. [14] | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + +**[14] `messaging.destination.name`:** This is duplicated from otel semantic-conventions. @@ -416,9 +444,11 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `messaging.destination.name` | string | The system-specific name of the messaging operation. [15] | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + +**[15] `messaging.destination.name`:** This is duplicated from otel semantic-conventions. @@ -433,9 +463,11 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `messaging.destination.name` | string | The system-specific name of the messaging operation. [16] | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + +**[16] `messaging.destination.name`:** This is duplicated from otel semantic-conventions. @@ -450,7 +482,7 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | @@ -465,7 +497,7 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | @@ -480,7 +512,7 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | @@ -495,9 +527,11 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `messaging.destination.name` | string | The system-specific name of the messaging operation. [17] | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + +**[17] `messaging.destination.name`:** This is duplicated from otel semantic-conventions. @@ -512,9 +546,11 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `messaging.destination.name` | string | The system-specific name of the messaging operation. [18] | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + +**[18] `messaging.destination.name`:** This is duplicated from otel semantic-conventions. @@ -529,9 +565,11 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.name` | string | The queue name | `DEV.DEAD.LETTER.QUEUE` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.type` | string | The queue type | `local-normal` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `messaging.destination.name` | string | The system-specific name of the messaging operation. [19] | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + +**[19] `messaging.destination.name`:** This is duplicated from otel semantic-conventions. @@ -546,9 +584,9 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | @@ -563,9 +601,9 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | @@ -580,9 +618,9 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.name` | string | The name of the channel | `DEV.ADMIN.SVRCONN` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.channel.type` | string | The type of the channel | `server-connection`; `cluster-receiver`; `amqp` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | @@ -597,7 +635,7 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | @@ -612,7 +650,7 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | @@ -627,7 +665,7 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | @@ -642,7 +680,7 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | @@ -657,7 +695,7 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | @@ -672,7 +710,7 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | @@ -687,8 +725,10 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `topic.name` | string | The name of the topic | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `messaging.destination.name` | string | The system-specific name of the messaging operation. [20] | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + +**[20] `messaging.destination.name`:** This is duplicated from otel semantic-conventions. @@ -703,8 +743,10 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `topic.name` | string | The name of the topic | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `messaging.destination.name` | string | The system-specific name of the messaging operation. [21] | `dev/` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + +**[21] `messaging.destination.name`:** This is duplicated from otel semantic-conventions. @@ -719,8 +761,8 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `listener.name` | string | The listener name | `listener` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.listener.name` | string | The listener name | `listener` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | @@ -735,9 +777,13 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `application.name` | string | The application name | `Wordle`; `JMSService` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | -| `user.name` | string | The user name | `foo`; `root` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `service.name` | string | Logical name of the service. [22] | `Wordle`; `JMSService` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `user.name` | string | Short name or login/username of the user. [23] | `foo`; `root` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + +**[22] `service.name`:** This is duplicated from otel semantic-conventions. + +**[23] `user.name`:** This is duplicated from otel semantic-conventions. @@ -752,4 +798,4 @@ | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| `queue.manager` | string | The name of the queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.manager` | string | The name of the IBM queue manager | `MQ1` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | diff --git a/ibm-mq-metrics/model/attributes.yaml b/ibm-mq-metrics/model/attributes.yaml index 5d337099a..ef7ffdafd 100644 --- a/ibm-mq-metrics/model/attributes.yaml +++ b/ibm-mq-metrics/model/attributes.yaml @@ -3,55 +3,57 @@ groups: type: attribute_group brief: Attributes of metrics. attributes: - - id: queue.manager + - id: ibm.mq.queue.manager type: string brief: > - The name of the queue manager + The name of the IBM queue manager stability: development examples: ["MQ1"] - - id: topic.name + - id: messaging.destination.name type: string brief: > - The name of the topic + The system-specific name of the messaging operation. + note: This is duplicated from otel semantic-conventions. stability: development examples: [ "dev/" ] - - id: channel.name + - id: ibm.mq.channel.name type: string brief: > The name of the channel stability: development examples: [ "DEV.ADMIN.SVRCONN" ] - - id: channel.type + - id: ibm.mq.channel.type type: string brief: > The type of the channel stability: development examples: [ "server-connection", "cluster-receiver", "amqp" ] - - id: job.name + - id: ibm.mq.job.name type: string brief: > The job name stability: development examples: [ "0000074900000003" ] - - id: channel.start.time + - id: ibm.mq.channel.start.time type: int brief: > The start time of the channel as seconds since Epoch. stability: development examples: [ 1748462702 ] - - id: queue.name - type: string - brief: > - The queue name - stability: development - examples: [ "DEV.DEAD.LETTER.QUEUE" ] - - id: queue.type + # Use the messaging.destination.name attribute instead? +# - id: queue.name +# type: string +# brief: > +# The queue name +# stability: development +# examples: [ "DEV.DEAD.LETTER.QUEUE" ] + - id: ibm.mq.queue.type type: string brief: > The queue type stability: development examples: [ "local-normal" ] - - id: listener.name + - id: ibm.mq.listener.name type: string brief: > The listener name @@ -60,12 +62,14 @@ groups: - id: user.name type: string brief: > - The user name + Short name or login/username of the user. + note: This is duplicated from otel semantic-conventions. stability: development examples: [ "foo", "root" ] - - id: application.name + - id: service.name type: string brief: > - The application name + Logical name of the service. + note: This is duplicated from otel semantic-conventions. stability: development - examples: [ "Wordle", "JMSService" ] \ No newline at end of file + examples: [ "Wordle", "JMSService" ] diff --git a/ibm-mq-metrics/model/metrics.yaml b/ibm-mq-metrics/model/metrics.yaml index d45957ad6..ad1710875 100644 --- a/ibm-mq-metrics/model/metrics.yaml +++ b/ibm-mq-metrics/model/metrics.yaml @@ -7,11 +7,11 @@ groups: instrument: gauge unit: "{messages}" attributes: - - ref: channel.name + - ref: ibm.mq.channel.name requirement_level: required - - ref: channel.type + - ref: ibm.mq.channel.type requirement_level: required - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - id: ibm.mq.status type: metric @@ -21,15 +21,15 @@ groups: instrument: gauge unit: "1" attributes: - - ref: channel.name + - ref: ibm.mq.channel.name requirement_level: required - - ref: channel.type + - ref: ibm.mq.channel.type requirement_level: required - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: job.name + - ref: ibm.mq.job.name requirement_level: required - - ref: channel.start.time + - ref: ibm.mq.channel.start.time requirement_level: required - id: ibm.mq.max.sharing.conversations type: metric @@ -39,15 +39,15 @@ groups: instrument: gauge unit: "{conversations}" attributes: - - ref: channel.name + - ref: ibm.mq.channel.name requirement_level: required - - ref: channel.type + - ref: ibm.mq.channel.type requirement_level: required - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: job.name + - ref: ibm.mq.job.name requirement_level: required - - ref: channel.start.time + - ref: ibm.mq.channel.start.time requirement_level: required - id: ibm.mq.current.sharing.conversations type: metric @@ -57,15 +57,15 @@ groups: brief: "Current number of conversations permitted on this channel instance." instrument: gauge attributes: - - ref: channel.name + - ref: ibm.mq.channel.name requirement_level: required - - ref: channel.type + - ref: ibm.mq.channel.type requirement_level: required - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: job.name + - ref: ibm.mq.job.name requirement_level: required - - ref: channel.start.time + - ref: ibm.mq.channel.start.time requirement_level: required - id: ibm.mq.byte.received type: metric @@ -75,15 +75,15 @@ groups: instrument: gauge unit: "{bytes}" attributes: - - ref: channel.name + - ref: ibm.mq.channel.name requirement_level: required - - ref: channel.type + - ref: ibm.mq.channel.type requirement_level: required - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: job.name + - ref: ibm.mq.job.name requirement_level: required - - ref: channel.start.time + - ref: ibm.mq.channel.start.time requirement_level: required - id: ibm.mq.byte.sent type: metric @@ -93,15 +93,15 @@ groups: instrument: gauge unit: "{bytes}" attributes: - - ref: channel.name + - ref: ibm.mq.channel.name requirement_level: required - - ref: channel.type + - ref: ibm.mq.channel.type requirement_level: required - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: job.name + - ref: ibm.mq.job.name requirement_level: required - - ref: channel.start.time + - ref: ibm.mq.channel.start.time requirement_level: required - id: ibm.mq.buffers.received type: metric @@ -111,15 +111,15 @@ groups: instrument: gauge unit: "{buffers}" attributes: - - ref: channel.name + - ref: ibm.mq.channel.name requirement_level: required - - ref: channel.type + - ref: ibm.mq.channel.type requirement_level: required - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: job.name + - ref: ibm.mq.job.name requirement_level: required - - ref: channel.start.time + - ref: ibm.mq.channel.start.time requirement_level: required - id: ibm.mq.buffers.sent type: metric @@ -129,15 +129,15 @@ groups: unit: "{buffers}" instrument: gauge attributes: - - ref: channel.name + - ref: ibm.mq.channel.name requirement_level: required - - ref: channel.type + - ref: ibm.mq.channel.type requirement_level: required - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: job.name + - ref: ibm.mq.job.name requirement_level: required - - ref: channel.start.time + - ref: ibm.mq.channel.start.time requirement_level: required - id: ibm.mq.message.count type: metric @@ -147,15 +147,15 @@ groups: unit: "{messages}" instrument: gauge attributes: - - ref: channel.name + - ref: ibm.mq.channel.name requirement_level: required - - ref: channel.type + - ref: ibm.mq.channel.type requirement_level: required - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: job.name + - ref: ibm.mq.job.name requirement_level: required - - ref: channel.start.time + - ref: ibm.mq.channel.start.time requirement_level: required - id: ibm.mq.open.input.count type: metric @@ -165,11 +165,11 @@ groups: instrument: gauge unit: "{applications}" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: queue.name + - ref: messaging.destination.name requirement_level: required - - ref: queue.type + - ref: ibm.mq.queue.type requirement_level: required - id: ibm.mq.open.output.count type: metric @@ -179,11 +179,11 @@ groups: instrument: gauge unit: "{applications}" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: queue.name + - ref: messaging.destination.name requirement_level: required - - ref: queue.type + - ref: ibm.mq.queue.type requirement_level: required - id: ibm.mq.high.queue.depth type: metric @@ -193,11 +193,11 @@ groups: instrument: gauge unit: "{percent}" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: queue.name + - ref: messaging.destination.name requirement_level: required - - ref: queue.type + - ref: ibm.mq.queue.type requirement_level: required - id: ibm.mq.service.interval type: metric @@ -207,11 +207,11 @@ groups: instrument: gauge unit: "{percent}" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: queue.name + - ref: messaging.destination.name requirement_level: required - - ref: queue.type + - ref: ibm.mq.queue.type requirement_level: required - id: ibm.mq.queue.depth.full.event type: metric @@ -221,9 +221,9 @@ groups: instrument: counter unit: "{events}" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: queue.name + - ref: messaging.destination.name requirement_level: required - id: ibm.mq..queue.depth.high.event type: metric @@ -233,9 +233,9 @@ groups: instrument: counter unit: "{events}" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: queue.name + - ref: messaging.destination.name requirement_level: required - id: ibm.mq..queue.depth.low.event type: metric @@ -245,9 +245,9 @@ groups: instrument: counter unit: "{events}" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: queue.name + - ref: messaging.destination.name requirement_level: required - id: ibm.mq.uncommitted.messages type: metric @@ -257,11 +257,11 @@ groups: instrument: gauge unit: "{messages}" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: queue.name + - ref: messaging.destination.name requirement_level: required - - ref: queue.type + - ref: ibm.mq.queue.type requirement_level: required - id: ibm.mq.oldest.msg.age type: metric @@ -271,11 +271,11 @@ groups: instrument: gauge unit: "microseconds" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: queue.name + - ref: messaging.destination.name requirement_level: required - - ref: queue.type + - ref: ibm.mq.queue.type requirement_level: required - id: ibm.mq.current.max.queue.filesize type: metric @@ -285,11 +285,11 @@ groups: instrument: gauge unit: "mib" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: queue.name + - ref: messaging.destination.name requirement_level: required - - ref: queue.type + - ref: ibm.mq.queue.type requirement_level: required - id: ibm.mq.current.queue.filesize type: metric @@ -299,11 +299,11 @@ groups: instrument: gauge unit: "mib" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: queue.name + - ref: messaging.destination.name requirement_level: required - - ref: queue.type + - ref: ibm.mq.queue.type requirement_level: required - id: ibm.mq.instances.per.client type: metric @@ -313,11 +313,11 @@ groups: instrument: gauge unit: "{instances}" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: queue.name + - ref: messaging.destination.name requirement_level: required - - ref: queue.type + - ref: ibm.mq.queue.type requirement_level: required - id: ibm.mq.message.deq.count type: metric @@ -327,11 +327,11 @@ groups: instrument: gauge unit: "{messages}" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: queue.name + - ref: messaging.destination.name requirement_level: required - - ref: queue.type + - ref: ibm.mq.queue.type requirement_level: required - id: ibm.mq.message.enq.count type: metric @@ -341,11 +341,11 @@ groups: instrument: gauge unit: "{messages}" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: queue.name + - ref: messaging.destination.name requirement_level: required - - ref: queue.type + - ref: ibm.mq.queue.type requirement_level: required - id: ibm.mq.queue.depth type: metric @@ -355,11 +355,11 @@ groups: instrument: gauge unit: "{messages}" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: queue.name + - ref: messaging.destination.name requirement_level: required - - ref: queue.type + - ref: ibm.mq.queue.type requirement_level: required - id: ibm.mq.service.interval.event type: metric @@ -369,11 +369,11 @@ groups: instrument: gauge unit: "1" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: queue.name + - ref: messaging.destination.name requirement_level: required - - ref: queue.type + - ref: ibm.mq.queue.type requirement_level: required - id: ibm.mq.reusable.log.size type: metric @@ -383,7 +383,7 @@ groups: instrument: gauge unit: "mib" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - id: ibm.mq.manager.active.channels type: metric @@ -393,7 +393,7 @@ groups: instrument: gauge unit: "{channels}" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - id: ibm.mq.restart.log.size type: metric @@ -403,7 +403,7 @@ groups: instrument: gauge unit: "mib" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - id: ibm.mq.max.queue.depth type: metric @@ -413,11 +413,11 @@ groups: instrument: gauge unit: "{messages}" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: queue.name + - ref: messaging.destination.name requirement_level: required - - ref: queue.type + - ref: ibm.mq.queue.type requirement_level: required - id: ibm.mq.onqtime.1 type: metric @@ -427,11 +427,11 @@ groups: instrument: gauge unit: "microseconds" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: queue.name + - ref: messaging.destination.name requirement_level: required - - ref: queue.type + - ref: ibm.mq.queue.type requirement_level: required - id: ibm.mq.onqtime.2 type: metric @@ -441,11 +441,11 @@ groups: instrument: gauge unit: "microseconds" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: queue.name + - ref: messaging.destination.name requirement_level: required - - ref: queue.type + - ref: ibm.mq.queue.type requirement_level: required - id: ibm.mq.message.received.count type: metric @@ -455,11 +455,11 @@ groups: instrument: gauge unit: "{messages}" attributes: - - ref: channel.name + - ref: ibm.mq.channel.name requirement_level: required - - ref: channel.type + - ref: ibm.mq.channel.type requirement_level: required - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - id: ibm.mq.message.sent.count type: metric @@ -469,11 +469,11 @@ groups: instrument: gauge unit: "{messages}" attributes: - - ref: channel.name + - ref: ibm.mq.channel.name requirement_level: required - - ref: channel.type + - ref: ibm.mq.channel.type requirement_level: required - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - id: ibm.mq.max.instances type: metric @@ -483,11 +483,11 @@ groups: instrument: gauge unit: "{instances}" attributes: - - ref: channel.name + - ref: ibm.mq.channel.name requirement_level: required - - ref: channel.type + - ref: ibm.mq.channel.type requirement_level: required - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - id: ibm.mq.connection.count type: metric @@ -497,7 +497,7 @@ groups: instrument: gauge unit: "{connections}" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - id: ibm.mq.manager.status type: metric @@ -507,7 +507,7 @@ groups: instrument: gauge unit: "1" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - id: ibm.mq.heartbeat type: metric @@ -517,7 +517,7 @@ groups: instrument: gauge unit: "1" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - id: ibm.mq.archive.log.size type: metric @@ -527,7 +527,7 @@ groups: instrument: gauge unit: "mib" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - id: ibm.mq.manager.max.active.channels type: metric @@ -537,7 +537,7 @@ groups: instrument: gauge unit: "{channels}" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - id: ibm.mq.manager.statistics.interval type: metric @@ -547,7 +547,7 @@ groups: instrument: gauge unit: "1" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - id: ibm.mq.publish.count type: metric @@ -557,9 +557,9 @@ groups: instrument: gauge unit: "{publications}" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: topic.name + - ref: messaging.destination.name requirement_level: required - id: ibm.mq.subscription.count type: metric @@ -569,9 +569,9 @@ groups: instrument: gauge unit: "{subscriptions}" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: topic.name + - ref: messaging.destination.name requirement_level: required - id: ibm.mq.listener.status type: metric @@ -581,9 +581,9 @@ groups: instrument: gauge unit: "1" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - - ref: listener.name + - ref: ibm.mq.listener.name requirement_level: required - id: ibm.mq.unauthorized.event type: metric @@ -593,11 +593,11 @@ groups: instrument: counter unit: "{events}" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required - ref: user.name requirement_level: required - - ref: application.name + - ref: service.name requirement_level: required - id: ibm.mq.manager.max.handles type: metric @@ -607,5 +607,5 @@ groups: instrument: gauge unit: "{events}" attributes: - - ref: queue.manager + - ref: ibm.mq.queue.manager requirement_level: required diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metrics/IbmMqAttributes.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metrics/IbmMqAttributes.java new file mode 100644 index 000000000..6caf87c48 --- /dev/null +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metrics/IbmMqAttributes.java @@ -0,0 +1,51 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.ibm.mq.metrics; + +import static io.opentelemetry.api.common.AttributeKey.longKey; +import static io.opentelemetry.api.common.AttributeKey.stringKey; + +import io.opentelemetry.api.common.AttributeKey; + +// This file is generated using weaver. Do not edit manually. + +/** Attribute definitions generated from a Weaver model. Do not edit manually. */ +public final class IbmMqAttributes { + + /** The name of the IBM queue manager */ + public static final AttributeKey IBM_MQ_QUEUE_MANAGER = stringKey("ibm.mq.queue.manager"); + + /** The system-specific name of the messaging operation. */ + public static final AttributeKey MESSAGING_DESTINATION_NAME = + stringKey("messaging.destination.name"); + + /** The name of the channel */ + public static final AttributeKey IBM_MQ_CHANNEL_NAME = stringKey("ibm.mq.channel.name"); + + /** The type of the channel */ + public static final AttributeKey IBM_MQ_CHANNEL_TYPE = stringKey("ibm.mq.channel.type"); + + /** The job name */ + public static final AttributeKey IBM_MQ_JOB_NAME = stringKey("ibm.mq.job.name"); + + /** The start time of the channel as seconds since Epoch. */ + public static final AttributeKey IBM_MQ_CHANNEL_START_TIME = + longKey("ibm.mq.channel.start.time"); + + /** The queue type */ + public static final AttributeKey IBM_MQ_QUEUE_TYPE = stringKey("ibm.mq.queue.type"); + + /** The listener name */ + public static final AttributeKey IBM_MQ_LISTENER_NAME = stringKey("ibm.mq.listener.name"); + + /** Short name or login/username of the user. */ + public static final AttributeKey USER_NAME = stringKey("user.name"); + + /** Logical name of the service. */ + public static final AttributeKey SERVICE_NAME = stringKey("service.name"); + + private IbmMqAttributes() {} +} diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireTStatusCmdCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireTStatusCmdCollector.java index 824abcbc5..74b13ffa5 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireTStatusCmdCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireTStatusCmdCollector.java @@ -112,9 +112,9 @@ private void extractMetrics( throws PCFException { Attributes attributes = Attributes.of( - AttributeKey.stringKey("topic.name"), + AttributeKey.stringKey("messaging.destination.name"), topicString, - AttributeKey.stringKey("queue.manager"), + AttributeKey.stringKey("ibm.mq.queue.manager"), context.getQueueManagerName()); if (context.getMetricsConfig().isIbmMqPublishCountEnabled()) { int publisherCount = 0; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerEventCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerEventCollector.java index 53a5afe89..2d81de65b 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerEventCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerEventCollector.java @@ -62,7 +62,7 @@ private void readEvents(MetricsCollectorContext context, String queueManagerEven context.getQueueManagerName(), AttributeKey.stringKey("user.name"), username, - AttributeKey.stringKey("application.name"), + AttributeKey.stringKey("service.name"), applicationName)); } } else { diff --git a/ibm-mq-metrics/templates/registry/java/IbmMqAttributes.java.j2 b/ibm-mq-metrics/templates/registry/java/IbmMqAttributes.java.j2 new file mode 100644 index 000000000..2fcbdd64b --- /dev/null +++ b/ibm-mq-metrics/templates/registry/java/IbmMqAttributes.java.j2 @@ -0,0 +1,27 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ +package io.opentelemetry.ibm.mq.metrics; + +import static io.opentelemetry.api.common.AttributeKey.stringKey; +import static io.opentelemetry.api.common.AttributeKey.longKey; +import io.opentelemetry.api.common.AttributeKey; + +// This file is generated using weaver. Do not edit manually. + +/** Attribute definitions generated from a Weaver model. Do not edit manually. */ +public final class IbmMqAttributes { +{% for attr in ctx %} + /** + {{ attr.brief }} */{% if attr.type == 'string' %} + public final static AttributeKey {{ attr.name.upper().split('.')|join('_') }} = stringKey("{{attr.name}}"); + {% elif attr.type == 'int' %} + public final static AttributeKey {{ attr.name.upper().split('.')|join('_') }} = longKey("{{attr.name}}"); + {% else %} + // UNHANDLED TYPE PLEASE FIXME + public final static AttributeKey {{ attr.name.upper().split('.')|join('_') }} = ??key("{{attr.name}}"); + {% endif %} +{% endfor %} + private IbmMqAttributes(){} +} diff --git a/ibm-mq-metrics/templates/registry/java/weaver.yaml b/ibm-mq-metrics/templates/registry/java/weaver.yaml index 8e4ea48e1..ece71c233 100644 --- a/ibm-mq-metrics/templates/registry/java/weaver.yaml +++ b/ibm-mq-metrics/templates/registry/java/weaver.yaml @@ -1,7 +1,10 @@ templates: - - pattern: Metrics.java.j2 + - template: Metrics.java.j2 filter: '.groups | map(select(.type == "metric"))' application_mode: single - - pattern: MetricsConfig.java.j2 + - template: MetricsConfig.java.j2 filter: '.groups | map(select(.type == "metric"))' - application_mode: single \ No newline at end of file + application_mode: single + - template: IbmMqAttributes.java.j2 + filter: '.groups | map(select(.type == "attribute_group")) | map(.attributes[])' + application_mode: single From 23395710b2811d20b038408cdd2c1c5be78eba19 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 16 Jul 2025 13:58:57 -0700 Subject: [PATCH 44/66] wire up attribute key constants --- .../tests/WMQMonitorIntegrationTest.java | 59 ++++++++++--------- .../io/opentelemetry/ibm/mq/WmqMonitor.java | 8 +-- .../ChannelMetricsCollector.java | 5 +- .../InquireQueueManagerCmdCollector.java | 6 +- .../InquireTStatusCmdCollector.java | 8 ++- .../ListenerMetricsCollector.java | 8 ++- .../PerformanceEventQueueCollector.java | 8 ++- .../QueueCollectionBuddy.java | 10 ++-- .../QueueManagerEventCollector.java | 11 ++-- .../QueueManagerMetricsCollector.java | 28 +++------ .../ReadConfigurationEventQueueCollector.java | 7 +-- .../QueueCollectionBuddyTest.java | 12 ++-- 12 files changed, 85 insertions(+), 85 deletions(-) diff --git a/ibm-mq-metrics/src/integrationTest/java/io/opentelemetry/ibm/mq/integration/tests/WMQMonitorIntegrationTest.java b/ibm-mq-metrics/src/integrationTest/java/io/opentelemetry/ibm/mq/integration/tests/WMQMonitorIntegrationTest.java index d37a85386..9f0a64f21 100644 --- a/ibm-mq-metrics/src/integrationTest/java/io/opentelemetry/ibm/mq/integration/tests/WMQMonitorIntegrationTest.java +++ b/ibm-mq-metrics/src/integrationTest/java/io/opentelemetry/ibm/mq/integration/tests/WMQMonitorIntegrationTest.java @@ -5,6 +5,8 @@ package io.opentelemetry.ibm.mq.integration.tests; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.IBM_MQ_QUEUE_MANAGER; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.MESSAGING_DESTINATION_NAME; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -16,7 +18,6 @@ import com.ibm.mq.headers.pcf.PCFException; import com.ibm.mq.headers.pcf.PCFMessage; import com.ibm.mq.headers.pcf.PCFMessageAgent; -import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.ibm.mq.config.QueueManager; import io.opentelemetry.ibm.mq.opentelemetry.ConfigWrapper; @@ -191,46 +192,46 @@ void test_monitor_with_full_config() throws Exception { } Set metricNames = metrics.keySet(); // this value is read from the active channels count: - assertThat(metricNames).contains("mq.manager.active.channels"); + assertThat(metricNames).contains("ibm.mq.manager.active.channels"); // this value is read from the configuration queue. - assertThat(metricNames).contains("mq.manager.max.handles"); + assertThat(metricNames).contains("ibm.mq.manager.max.handles"); // this value is read from the queue manager events, for unauthorized events. - assertThat(metricNames).contains("mq.unauthorized.event"); + assertThat(metricNames).contains("ibm.mq.unauthorized.event"); // this value is read from the performance event queue. - assertThat(metricNames).contains("mq.queue.depth.full.event"); + assertThat(metricNames).contains("ibm.mq.queue.depth.full.event"); // this value is read from the performance event queue. - assertThat(metricNames).contains("mq.queue.depth.high.event"); - assertThat(metricNames).contains("mq.queue.depth.low.event"); + assertThat(metricNames).contains("ibm.mq.queue.depth.high.event"); + assertThat(metricNames).contains("ibm.mq.queue.depth.low.event"); // reads a value from the heartbeat gauge - assertThat(metricNames).contains("mq.heartbeat"); - assertThat(metricNames).contains("mq.oldest.msg.age"); - if (metrics.get("mq.oldest.msg.age") != null) { + assertThat(metricNames).contains("ibm.mq.heartbeat"); + assertThat(metricNames).contains("ibm.mq.oldest.msg.age"); + if (metrics.get("ibm.mq.oldest.msg.age") != null) { Set queueNames = - metrics.get("mq.oldest.msg.age").getLongGaugeData().getPoints().stream() - .map(pt -> pt.getAttributes().get(AttributeKey.stringKey("queue.name"))) + metrics.get("ibm.mq.oldest.msg.age").getLongGaugeData().getPoints().stream() + .map(pt -> pt.getAttributes().get(MESSAGING_DESTINATION_NAME)) .collect(Collectors.toSet()); assertThat(queueNames).contains("smallqueue"); } // make sure we get MQ manager status - assertThat(metricNames).contains("mq.manager.status"); - if (metrics.get("mq.manager.status") != null) { + assertThat(metricNames).contains("ibm.mq.manager.status"); + if (metrics.get("ibm.mq.manager.status") != null) { Set queueManagers = - metrics.get("mq.manager.status").getLongGaugeData().getPoints().stream() - .map(pt -> pt.getAttributes().get(AttributeKey.stringKey("queue.manager"))) + metrics.get("ibm.mq.manager.status").getLongGaugeData().getPoints().stream() + .map(pt -> pt.getAttributes().get(IBM_MQ_QUEUE_MANAGER)) .collect(Collectors.toSet()); assertThat(queueManagers).contains("QM1"); } - assertThat(metricNames).contains("mq.onqtime.2"); - if (metrics.get("mq.onqtime.2") != null) { + assertThat(metricNames).contains("ibm.mq.onqtime.2"); + if (metrics.get("ibm.mq.onqtime.2") != null) { Set queueNames = - metrics.get("mq.onqtime.2").getLongGaugeData().getPoints().stream() - .map(pt -> pt.getAttributes().get(AttributeKey.stringKey("queue.name"))) + metrics.get("ibm.mq.onqtime.2").getLongGaugeData().getPoints().stream() + .map(pt -> pt.getAttributes().get(MESSAGING_DESTINATION_NAME)) .collect(Collectors.toSet()); assertThat(queueNames).contains("smallqueue"); Set queueManagers = - metrics.get("mq.manager.status").getLongGaugeData().getPoints().stream() - .map(pt -> pt.getAttributes().get(AttributeKey.stringKey("queue.manager"))) + metrics.get("ibm.mq.manager.status").getLongGaugeData().getPoints().stream() + .map(pt -> pt.getAttributes().get(IBM_MQ_QUEUE_MANAGER)) .collect(Collectors.toSet()); assertThat(queueManagers).contains("QM1"); // TODO: Add more asserts about data values, units, attributes, etc, not just names @@ -267,17 +268,17 @@ void test_otlphttp() throws Exception { metricNames.add(metricData.getName()); } // this value is read from the active channels count: - assertThat(metricNames).contains("mq.manager.active.channels"); + assertThat(metricNames).contains("ibm.mq.manager.active.channels"); // this value is read from the configuration queue. - assertThat(metricNames).contains("mq.manager.max.handles"); + assertThat(metricNames).contains("ibm.mq.manager.max.handles"); // this value is read from the queue manager events, for unauthorized events. - assertThat(metricNames).contains("mq.unauthorized.event"); + assertThat(metricNames).contains("ibm.mq.unauthorized.event"); // this value is read from the performance event queue. - assertThat(metricNames).contains("mq.queue.depth.full.event"); + assertThat(metricNames).contains("ibm.mq.queue.depth.full.event"); // this value is read from the performance event queue. - assertThat(metricNames).contains("mq.queue.depth.high.event"); - assertThat(metricNames).contains("mq.queue.depth.low.event"); + assertThat(metricNames).contains("ibm.mq.queue.depth.high.event"); + assertThat(metricNames).contains("ibm.mq.queue.depth.low.event"); // reads a value from the heartbeat gauge - assertThat(metricNames).contains("mq.heartbeat"); + assertThat(metricNames).contains("ibm.mq.heartbeat"); } } diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqMonitor.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqMonitor.java index 421db2d25..3db13d63c 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqMonitor.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqMonitor.java @@ -5,10 +5,11 @@ package io.opentelemetry.ibm.mq; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.IBM_MQ_QUEUE_MANAGER; + import com.fasterxml.jackson.databind.ObjectMapper; import com.ibm.mq.MQQueueManager; import com.ibm.mq.headers.pcf.PCFMessageAgent; -import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.LongGauge; import io.opentelemetry.api.metrics.Meter; @@ -65,7 +66,7 @@ public WmqMonitor(ConfigWrapper config, ExecutorService threadPool, Meter meter) this.metricsConfig = new MetricsConfig(config); - this.heartbeatGauge = meter.gaugeBuilder("mq.heartbeat").setUnit("1").ofLongs().build(); + this.heartbeatGauge = meter.gaugeBuilder("ibm.mq.heartbeat").setUnit("1").ofLongs().build(); this.threadPool = threadPool; jobs.add(new QueueManagerMetricsCollector(meter)); @@ -108,8 +109,7 @@ public void run(QueueManager queueManager) { } finally { if (this.metricsConfig.isIbmMqHeartbeatEnabled()) { heartbeatGauge.set( - heartBeatMetricValue, - Attributes.of(AttributeKey.stringKey("queue.manager"), queueManagerName)); + heartBeatMetricValue, Attributes.of(IBM_MQ_QUEUE_MANAGER, queueManagerName)); } cleanUp(ibmQueueManager, agent); long endTime = System.currentTimeMillis() - startTime; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollector.java index 23d83c35b..ec7ffb866 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollector.java @@ -7,12 +7,12 @@ import static com.ibm.mq.constants.CMQC.MQRC_SELECTOR_ERROR; import static com.ibm.mq.constants.CMQCFC.MQRCCF_CHL_STATUS_NOT_FOUND; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.IBM_MQ_QUEUE_MANAGER; import com.ibm.mq.constants.CMQC; import com.ibm.mq.constants.CMQCFC; import com.ibm.mq.headers.pcf.PCFException; import com.ibm.mq.headers.pcf.PCFMessage; -import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.LongGauge; import io.opentelemetry.api.metrics.Meter; @@ -158,8 +158,7 @@ public void accept(MetricsCollectorContext context) { logger.info( "Active Channels in queueManager {} are {}", context.getQueueManagerName(), activeChannels); activeChannelsGauge.set( - activeChannels.size(), - Attributes.of(AttributeKey.stringKey("queue.manager"), context.getQueueManagerName())); + activeChannels.size(), Attributes.of(IBM_MQ_QUEUE_MANAGER, context.getQueueManagerName())); long exitTime = System.currentTimeMillis() - entryTime; logger.debug("Time taken to publish metrics for all channels is {} milliseconds", exitTime); diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQueueManagerCmdCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQueueManagerCmdCollector.java index 484071d0b..5cdf0c52f 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQueueManagerCmdCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireQueueManagerCmdCollector.java @@ -5,12 +5,13 @@ package io.opentelemetry.ibm.mq.metricscollector; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.IBM_MQ_QUEUE_MANAGER; + import com.ibm.mq.constants.CMQC; import com.ibm.mq.constants.CMQCFC; import com.ibm.mq.constants.MQConstants; import com.ibm.mq.headers.pcf.MQCFIL; import com.ibm.mq.headers.pcf.PCFMessage; -import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.LongGauge; import io.opentelemetry.api.metrics.Meter; @@ -62,8 +63,7 @@ public void accept(MetricsCollectorContext context) { if (context.getMetricsConfig().isIbmMqManagerStatisticsIntervalEnabled()) { int interval = responses.get(0).getIntParameterValue(CMQC.MQIA_STATISTICS_INTERVAL); statisticsIntervalGauge.set( - interval, - Attributes.of(AttributeKey.stringKey("queue.manager"), context.getQueueManagerName())); + interval, Attributes.of(IBM_MQ_QUEUE_MANAGER, context.getQueueManagerName())); } } catch (Exception e) { logger.error("Error collecting QueueManagerCmd metrics", e); diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireTStatusCmdCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireTStatusCmdCollector.java index 74b13ffa5..bb3812565 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireTStatusCmdCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireTStatusCmdCollector.java @@ -5,12 +5,14 @@ package io.opentelemetry.ibm.mq.metricscollector; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.IBM_MQ_QUEUE_MANAGER; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.MESSAGING_DESTINATION_NAME; + import com.ibm.mq.constants.CMQC; import com.ibm.mq.constants.CMQCFC; import com.ibm.mq.headers.MQDataException; import com.ibm.mq.headers.pcf.PCFException; import com.ibm.mq.headers.pcf.PCFMessage; -import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.LongGauge; import io.opentelemetry.api.metrics.Meter; @@ -112,9 +114,9 @@ private void extractMetrics( throws PCFException { Attributes attributes = Attributes.of( - AttributeKey.stringKey("messaging.destination.name"), + MESSAGING_DESTINATION_NAME, topicString, - AttributeKey.stringKey("ibm.mq.queue.manager"), + IBM_MQ_QUEUE_MANAGER, context.getQueueManagerName()); if (context.getMetricsConfig().isIbmMqPublishCountEnabled()) { int publisherCount = 0; diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollector.java index 138e1b106..a7bf3d48d 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ListenerMetricsCollector.java @@ -5,10 +5,12 @@ package io.opentelemetry.ibm.mq.metricscollector; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.IBM_MQ_LISTENER_NAME; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.IBM_MQ_QUEUE_MANAGER; + import com.ibm.mq.constants.CMQCFC; import com.ibm.mq.headers.pcf.PCFException; import com.ibm.mq.headers.pcf.PCFMessage; -import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.LongGauge; import io.opentelemetry.api.metrics.Meter; @@ -102,9 +104,9 @@ private void updateMetrics( listenerStatusGauge.set( status, Attributes.of( - AttributeKey.stringKey("listener.name"), + IBM_MQ_LISTENER_NAME, listenerName, - AttributeKey.stringKey("queue.manager"), + IBM_MQ_QUEUE_MANAGER, context.getQueueManagerName())); } } diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/PerformanceEventQueueCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/PerformanceEventQueueCollector.java index 39db0324a..db1d4a254 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/PerformanceEventQueueCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/PerformanceEventQueueCollector.java @@ -5,6 +5,9 @@ package io.opentelemetry.ibm.mq.metricscollector; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.IBM_MQ_QUEUE_MANAGER; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.MESSAGING_DESTINATION_NAME; + import com.ibm.mq.MQException; import com.ibm.mq.MQGetMessageOptions; import com.ibm.mq.MQMessage; @@ -13,7 +16,6 @@ import com.ibm.mq.constants.MQConstants; import com.ibm.mq.headers.pcf.PCFException; import com.ibm.mq.headers.pcf.PCFMessage; -import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.LongCounter; import io.opentelemetry.api.metrics.Meter; @@ -82,9 +84,9 @@ private void incrementCounterByEventType(MetricsCollectorContext context, PCFMes String queueName = receivedMsg.getStringParameterValue(CMQC.MQCA_BASE_OBJECT_NAME).trim(); Attributes attributes = Attributes.of( - AttributeKey.stringKey("queue.manager"), + IBM_MQ_QUEUE_MANAGER, context.getQueueManagerName(), - AttributeKey.stringKey("queue.name"), + MESSAGING_DESTINATION_NAME, queueName); switch (receivedMsg.getReason()) { case CMQC.MQRC_Q_FULL: diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java index b150b6bf6..9bfc96e2c 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java @@ -10,6 +10,9 @@ import static com.ibm.mq.constants.CMQC.MQQT_LOCAL; import static com.ibm.mq.constants.CMQC.MQQT_MODEL; import static com.ibm.mq.constants.CMQC.MQQT_REMOTE; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.IBM_MQ_QUEUE_MANAGER; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.IBM_MQ_QUEUE_TYPE; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.MESSAGING_DESTINATION_NAME; import com.ibm.mq.constants.CMQC; import com.ibm.mq.constants.CMQCFC; @@ -19,7 +22,6 @@ import com.ibm.mq.headers.pcf.PCFException; import com.ibm.mq.headers.pcf.PCFMessage; import com.ibm.mq.headers.pcf.PCFParameter; -import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.LongGauge; import io.opentelemetry.api.metrics.Meter; @@ -271,11 +273,11 @@ private void updateMetrics( PCFParameter pcfParam = pcfMessage.getParameter(constantValue); Attributes attributes = Attributes.of( - AttributeKey.stringKey("queue.name"), + MESSAGING_DESTINATION_NAME, queueName, - AttributeKey.stringKey("queue.type"), + IBM_MQ_QUEUE_TYPE, queueType, - AttributeKey.stringKey("queue.manager"), + IBM_MQ_QUEUE_MANAGER, context.getQueueManagerName()); if (pcfParam instanceof MQCFIN) { diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerEventCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerEventCollector.java index 2d81de65b..723e433cf 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerEventCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueManagerEventCollector.java @@ -5,6 +5,10 @@ package io.opentelemetry.ibm.mq.metricscollector; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.IBM_MQ_QUEUE_MANAGER; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.SERVICE_NAME; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.USER_NAME; + import com.ibm.mq.MQException; import com.ibm.mq.MQGetMessageOptions; import com.ibm.mq.MQMessage; @@ -13,7 +17,6 @@ import com.ibm.mq.constants.CMQCFC; import com.ibm.mq.constants.MQConstants; import com.ibm.mq.headers.pcf.PCFMessage; -import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.LongCounter; import io.opentelemetry.api.metrics.Meter; @@ -58,11 +61,11 @@ private void readEvents(MetricsCollectorContext context, String queueManagerEven authorityEventCounter.add( 1, Attributes.of( - AttributeKey.stringKey("queue.manager"), + IBM_MQ_QUEUE_MANAGER, context.getQueueManagerName(), - AttributeKey.stringKey("user.name"), + USER_NAME, username, - AttributeKey.stringKey("service.name"), + SERVICE_NAME, applicationName)); } } else { 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 0c8d925f1..4dbd73878 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 @@ -5,9 +5,10 @@ package io.opentelemetry.ibm.mq.metricscollector; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.IBM_MQ_QUEUE_MANAGER; + import com.ibm.mq.constants.CMQCFC; import com.ibm.mq.headers.pcf.PCFMessage; -import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.LongGauge; import io.opentelemetry.api.metrics.Meter; @@ -64,41 +65,30 @@ public void accept(MetricsCollectorContext context) { logger.debug("Unexpected error while PCFMessage.send(), response is empty"); return; } + Attributes attributes = Attributes.of(IBM_MQ_QUEUE_MANAGER, context.getQueueManagerName()); if (context.getMetricsConfig().isIbmMqManagerStatusEnabled()) { int status = responses.get(0).getIntParameterValue(CMQCFC.MQIACF_Q_MGR_STATUS); - statusGauge.set( - status, - Attributes.of(AttributeKey.stringKey("queue.manager"), context.getQueueManagerName())); + statusGauge.set(status, attributes); } if (context.getMetricsConfig().isIbmMqConnectionCountEnabled()) { int count = responses.get(0).getIntParameterValue(CMQCFC.MQIACF_CONNECTION_COUNT); - connectionCountGauge.set( - count, - Attributes.of(AttributeKey.stringKey("queue.manager"), context.getQueueManagerName())); + connectionCountGauge.set(count, attributes); } if (context.getMetricsConfig().isIbmMqRestartLogSizeEnabled()) { int logSize = responses.get(0).getIntParameterValue(CMQCFC.MQIACF_RESTART_LOG_SIZE); - restartLogSizeGauge.set( - logSize, - Attributes.of(AttributeKey.stringKey("queue.manager"), context.getQueueManagerName())); + restartLogSizeGauge.set(logSize, attributes); } if (context.getMetricsConfig().isIbmMqReusableLogSizeEnabled()) { int logSize = responses.get(0).getIntParameterValue(CMQCFC.MQIACF_REUSABLE_LOG_SIZE); - reuseLogSizeGauge.set( - logSize, - Attributes.of(AttributeKey.stringKey("queue.manager"), context.getQueueManagerName())); + reuseLogSizeGauge.set(logSize, attributes); } if (context.getMetricsConfig().isIbmMqArchiveLogSizeEnabled()) { int logSize = responses.get(0).getIntParameterValue(CMQCFC.MQIACF_ARCHIVE_LOG_SIZE); - archiveLogSizeGauge.set( - logSize, - Attributes.of(AttributeKey.stringKey("queue.manager"), context.getQueueManagerName())); + archiveLogSizeGauge.set(logSize, attributes); } if (context.getMetricsConfig().isIbmMqManagerMaxActiveChannelsEnabled()) { int maxActiveChannels = context.getQueueManager().getMaxActiveChannels(); - maxActiveChannelsGauge.set( - maxActiveChannels, - Attributes.of(AttributeKey.stringKey("queue.manager"), context.getQueueManagerName())); + maxActiveChannelsGauge.set(maxActiveChannels, attributes); } } catch (Exception e) { logger.error(e.getMessage()); diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ReadConfigurationEventQueueCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ReadConfigurationEventQueueCollector.java index 576e42614..f7e56134d 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ReadConfigurationEventQueueCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ReadConfigurationEventQueueCollector.java @@ -5,6 +5,8 @@ package io.opentelemetry.ibm.mq.metricscollector; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.IBM_MQ_QUEUE_MANAGER; + import com.ibm.mq.MQException; import com.ibm.mq.MQGetMessageOptions; import com.ibm.mq.MQMessage; @@ -13,7 +15,6 @@ import com.ibm.mq.constants.CMQCFC; import com.ibm.mq.constants.MQConstants; import com.ibm.mq.headers.pcf.PCFMessage; -import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.LongGauge; import io.opentelemetry.api.metrics.Meter; @@ -124,9 +125,7 @@ public void accept(MetricsCollectorContext context) { if (context.getMetricsConfig().isIbmMqManagerMaxHandlesEnabled()) { int maxHandles = candidate.getIntParameterValue(CMQC.MQIA_MAX_HANDLES); maxHandlesGauge.set( - maxHandles, - Attributes.of( - AttributeKey.stringKey("queue.manager"), context.getQueueManager().getName())); + maxHandles, Attributes.of(IBM_MQ_QUEUE_MANAGER, context.getQueueManager().getName())); } } diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java index 082fc583a..e1c64bc50 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java @@ -5,6 +5,7 @@ package io.opentelemetry.ibm.mq.metricscollector; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.MESSAGING_DESTINATION_NAME; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.when; @@ -14,7 +15,6 @@ import com.ibm.mq.constants.CMQCFC; import com.ibm.mq.headers.pcf.PCFMessage; import com.ibm.mq.headers.pcf.PCFMessageAgent; -import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.ibm.mq.config.QueueManager; import io.opentelemetry.ibm.mq.metrics.MetricsConfig; @@ -88,7 +88,7 @@ void testProcessPcfRequestAndPublishQMetricsForInquireQStatusCmd() throws Except for (MetricData metric : otelTesting.getMetrics()) { for (LongPointData d : metric.getLongGaugeData().getPoints()) { - String queueName = d.getAttributes().get(AttributeKey.stringKey("queue.name")); + String queueName = d.getAttributes().get(MESSAGING_DESTINATION_NAME); Long expectedValue = expectedValues.get(queueName).remove(metric.getName()); assertThat(d.getValue()).isEqualTo(expectedValue); } @@ -127,7 +127,7 @@ void testProcessPcfRequestAndPublishQMetricsForInquireQCmd() throws Exception { for (MetricData metric : otelTesting.getMetrics()) { for (LongPointData d : metric.getLongGaugeData().getPoints()) { - String queueName = d.getAttributes().get(AttributeKey.stringKey("queue.name")); + String queueName = d.getAttributes().get(MESSAGING_DESTINATION_NAME); Long expectedValue = expectedValues.get(queueName).remove(metric.getName()); assertThat(d.getValue()).isEqualTo(expectedValue); } @@ -152,11 +152,11 @@ void testProcessPcfRequestAndPublishQMetricsForResetQStatsCmd() throws Exception for (MetricData metric : otelTesting.getMetrics()) { Iterator iterator = metric.getLongGaugeData().getPoints().iterator(); - if (metric.getName().equals("mq.high.queue.depth")) { + if (metric.getName().equals("ibm.mq.high.queue.depth")) { assertThat(iterator.next().getValue()).isEqualTo(10); - } else if (metric.getName().equals("mq.message.deq.count")) { + } else if (metric.getName().equals("ibm.mq.message.deq.count")) { assertThat(iterator.next().getValue()).isEqualTo(0); - } else if (metric.getName().equals("mq.message.enq.count")) { + } else if (metric.getName().equals("ibm.mq.message.enq.count")) { assertThat(iterator.next().getValue()).isEqualTo(3); } } From edf5e8b76ead9119f8629f99c5ee4b4927ccc946 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 16 Jul 2025 13:59:06 -0700 Subject: [PATCH 45/66] fix metric names --- .../resources/conf/test-config.yml | 92 +++++++++---------- .../resources/conf/test-queuemgr-config.yml | 92 +++++++++---------- 2 files changed, 92 insertions(+), 92 deletions(-) diff --git a/ibm-mq-metrics/src/integrationTest/resources/conf/test-config.yml b/ibm-mq-metrics/src/integrationTest/resources/conf/test-config.yml index 964ef590d..68e4030d2 100644 --- a/ibm-mq-metrics/src/integrationTest/resources/conf/test-config.yml +++ b/ibm-mq-metrics/src/integrationTest/resources/conf/test-config.yml @@ -90,95 +90,95 @@ queueManagers: values: ["SYSTEM","$SYS"] metrics: - "mq.message.retry.count": # Number of message retries + "ibm.mq.message.retry.count": # Number of message retries enabled: true - "mq.status": # Channel status + "ibm.mq.status": # Channel status enabled: true - "mq.max.sharing.conversations": # Maximum number of conversations permitted on this channel instance. + "ibm.mq.max.sharing.conversations": # Maximum number of conversations permitted on this channel instance. enabled: true - "mq.current.sharing.conversations": # Current number of conversations permitted on this channel instance. + "ibm.mq.current.sharing.conversations": # Current number of conversations permitted on this channel instance. enabled: true - "mq.byte.received": # Number of bytes received + "ibm.mq.byte.received": # Number of bytes received enabled: true - "mq.byte.sent": # Number of bytes sent + "ibm.mq.byte.sent": # Number of bytes sent enabled: true - "mq.buffers.received": # Buffers received + "ibm.mq.buffers.received": # Buffers received enabled: true - "mq.buffers.sent": # Buffers sent + "ibm.mq.buffers.sent": # Buffers sent enabled: true - "mq.message.count": # Message count + "ibm.mq.message.count": # Message count enabled: true - "mq.open.input.count": # Count of applications sending messages to the queue + "ibm.mq.open.input.count": # Count of applications sending messages to the queue enabled: true - "mq.open.output.count": # Count of applications consuming messages from the queue + "ibm.mq.open.output.count": # Count of applications consuming messages from the queue enabled: true - "mq.high.queue.depth": # The current high queue depth + "ibm.mq.high.queue.depth": # The current high queue depth enabled: true - "mq.service.interval": # The queue service interval + "ibm.mq.service.interval": # The queue service interval enabled: true - "mq.queue.depth.full.event": # The number of full queue events + "ibm.mq.queue.depth.full.event": # The number of full queue events enabled: true - "mq.queue.depth.high.event": # The number of high queue events + "ibm.mq.queue.depth.high.event": # The number of high queue events enabled: true - "mq.queue.depth.low.event": # The number of low queue events + "ibm.mq.queue.depth.low.event": # The number of low queue events enabled: true - "mq.uncommitted.messages": # Number of uncommitted messages + "ibm.mq.uncommitted.messages": # Number of uncommitted messages enabled: true - "mq.oldest.msg.age": # Queue message oldest age + "ibm.mq.oldest.msg.age": # Queue message oldest age enabled: true - "mq.current.max.queue.filesize": # Current maximum queue file size + "ibm.mq.current.max.queue.filesize": # Current maximum queue file size enabled: true - "mq.current.queue.filesize": # Current queue file size + "ibm.mq.current.queue.filesize": # Current queue file size enabled: true - "mq.instances.per.client": # Instances per client + "ibm.mq.instances.per.client": # Instances per client enabled: true - "mq.message.deq.count": # Message dequeue count + "ibm.mq.message.deq.count": # Message dequeue count enabled: true - "mq.message.enq.count": # Message enqueue count + "ibm.mq.message.enq.count": # Message enqueue count enabled: true - "mq.queue.depth": # Current queue depth + "ibm.mq.queue.depth": # Current queue depth enabled: true - "mq.service.interval.event": # Queue service interval event + "ibm.mq.service.interval.event": # Queue service interval event enabled: true - "mq.reusable.log.size": # The amount of space occupied, in megabytes, by log extents available to be reused. + "ibm.mq.reusable.log.size": # The amount of space occupied, in megabytes, by log extents available to be reused. enabled: true - "mq.manager.active.channels": # The queue manager active maximum channels limit + "ibm.mq.manager.active.channels": # The queue manager active maximum channels limit enabled: true - "mq.restart.log.size": # Size of the log data required for restart recovery in megabytes. + "ibm.mq.restart.log.size": # Size of the log data required for restart recovery in megabytes. enabled: true - "mq.max.queue.depth": # Maximum queue depth + "ibm.mq.max.queue.depth": # Maximum queue depth enabled: true - "mq.onqtime.1": # Amount of time, in microseconds, that a message spent on the queue, over a short period + "ibm.mq.onqtime.1": # Amount of time, in microseconds, that a message spent on the queue, over a short period enabled: true - "mq.onqtime.2": # Amount of time, in microseconds, that a message spent on the queue, over a longer period + "ibm.mq.onqtime.2": # Amount of time, in microseconds, that a message spent on the queue, over a longer period enabled: true - "mq.message.received.count": # Number of messages received + "ibm.mq.message.received.count": # Number of messages received enabled: true - "mq.message.sent.count": # Number of messages sent + "ibm.mq.message.sent.count": # Number of messages sent enabled: true - "mq.max.instances": # Max channel instances + "ibm.mq.max.instances": # Max channel instances enabled: true - "mq.connection.count": # Active connections count + "ibm.mq.connection.count": # Active connections count enabled: true - "mq.manager.status": # Queue manager status + "ibm.mq.manager.status": # Queue manager status enabled: true - "mq.heartbeat": # Queue manager heartbeat + "ibm.mq.heartbeat": # Queue manager heartbeat enabled: true - "mq.archive.log.size": # Queue manager archive log size + "ibm.mq.archive.log.size": # Queue manager archive log size enabled: true - "mq.manager.max.active.channels": # Queue manager max active channels + "ibm.mq.manager.max.active.channels": # Queue manager max active channels enabled: true - "mq.manager.statistics.interval": # Queue manager statistics interval + "ibm.mq.manager.statistics.interval": # Queue manager statistics interval enabled: true - "mq.publish.count": # Topic publication count + "ibm.mq.publish.count": # Topic publication count enabled: true - "mq.subscription.count": # Topic subscription count + "ibm.mq.subscription.count": # Topic subscription count enabled: true - "mq.listener.status": # Listener status + "ibm.mq.listener.status": # Listener status enabled: true - "mq.unauthorized.event": # Number of authentication error events + "ibm.mq.unauthorized.event": # Number of authentication error events enabled: true - "mq.manager.max.handles": # Max open handles + "ibm.mq.manager.max.handles": # Max open handles enabled: true sslConnection: @@ -194,4 +194,4 @@ otlpExporter: otel.exporter.otlp.protocol: http/protobuf otel.metric.export.interval: 5s otel.logs.exporter: none - otel.traces.exporter: none \ No newline at end of file + otel.traces.exporter: none diff --git a/ibm-mq-metrics/src/integrationTest/resources/conf/test-queuemgr-config.yml b/ibm-mq-metrics/src/integrationTest/resources/conf/test-queuemgr-config.yml index 840dd3f1d..500694df1 100644 --- a/ibm-mq-metrics/src/integrationTest/resources/conf/test-queuemgr-config.yml +++ b/ibm-mq-metrics/src/integrationTest/resources/conf/test-queuemgr-config.yml @@ -62,95 +62,95 @@ queueManagers: values: ["SYSTEM","$SYS"] metrics: - "mq.message.retry.count": # Number of message retries + "ibm.mq.message.retry.count": # Number of message retries enabled: true - "mq.status": # Channel status + "ibm.mq.status": # Channel status enabled: true - "mq.max.sharing.conversations": # Maximum number of conversations permitted on this channel instance. + "ibm.mq.max.sharing.conversations": # Maximum number of conversations permitted on this channel instance. enabled: true - "mq.current.sharing.conversations": # Current number of conversations permitted on this channel instance. + "ibm.mq.current.sharing.conversations": # Current number of conversations permitted on this channel instance. enabled: true - "mq.byte.received": # Number of bytes received + "ibm.mq.byte.received": # Number of bytes received enabled: true - "mq.byte.sent": # Number of bytes sent + "ibm.mq.byte.sent": # Number of bytes sent enabled: true - "mq.buffers.received": # Buffers received + "ibm.mq.buffers.received": # Buffers received enabled: true - "mq.buffers.sent": # Buffers sent + "ibm.mq.buffers.sent": # Buffers sent enabled: true - "mq.message.count": # Message count + "ibm.mq.message.count": # Message count enabled: true - "mq.open.input.count": # Count of applications sending messages to the queue + "ibm.mq.open.input.count": # Count of applications sending messages to the queue enabled: true - "mq.open.output.count": # Count of applications consuming messages from the queue + "ibm.mq.open.output.count": # Count of applications consuming messages from the queue enabled: true - "mq.high.queue.depth": # The current high queue depth + "ibm.mq.high.queue.depth": # The current high queue depth enabled: true - "mq.service.interval": # The queue service interval + "ibm.mq.service.interval": # The queue service interval enabled: true - "mq.queue.depth.full.event": # The number of full queue events + "ibm.mq.queue.depth.full.event": # The number of full queue events enabled: true - "mq.queue.depth.high.event": # The number of high queue events + "ibm.mq.queue.depth.high.event": # The number of high queue events enabled: true - "mq.queue.depth.low.event": # The number of low queue events + "ibm.mq.queue.depth.low.event": # The number of low queue events enabled: true - "mq.uncommitted.messages": # Number of uncommitted messages + "ibm.mq.uncommitted.messages": # Number of uncommitted messages enabled: true - "mq.oldest.msg.age": # Queue message oldest age + "ibm.mq.oldest.msg.age": # Queue message oldest age enabled: true - "mq.current.max.queue.filesize": # Current maximum queue file size + "ibm.mq.current.max.queue.filesize": # Current maximum queue file size enabled: true - "mq.current.queue.filesize": # Current queue file size + "ibm.mq.current.queue.filesize": # Current queue file size enabled: true - "mq.instances.per.client": # Instances per client + "ibm.mq.instances.per.client": # Instances per client enabled: true - "mq.message.deq.count": # Message dequeue count + "ibm.mq.message.deq.count": # Message dequeue count enabled: true - "mq.message.enq.count": # Message enqueue count + "ibm.mq.message.enq.count": # Message enqueue count enabled: true - "mq.queue.depth": # Current queue depth + "ibm.mq.queue.depth": # Current queue depth enabled: true - "mq.service.interval.event": # Queue service interval event + "ibm.mq.service.interval.event": # Queue service interval event enabled: true - "mq.reusable.log.size": # The amount of space occupied, in megabytes, by log extents available to be reused. + "ibm.mq.reusable.log.size": # The amount of space occupied, in megabytes, by log extents available to be reused. enabled: true - "mq.manager.active.channels": # The queue manager active maximum channels limit + "ibm.mq.manager.active.channels": # The queue manager active maximum channels limit enabled: true - "mq.restart.log.size": # Size of the log data required for restart recovery in megabytes. + "ibm.mq.restart.log.size": # Size of the log data required for restart recovery in megabytes. enabled: true - "mq.max.queue.depth": # Maximum queue depth + "ibm.mq.max.queue.depth": # Maximum queue depth enabled: true - "mq.onqtime.1": # Amount of time, in microseconds, that a message spent on the queue, over a short period + "ibm.mq.onqtime.1": # Amount of time, in microseconds, that a message spent on the queue, over a short period enabled: true - "mq.onqtime.2": # Amount of time, in microseconds, that a message spent on the queue, over a longer period + "ibm.mq.onqtime.2": # Amount of time, in microseconds, that a message spent on the queue, over a longer period enabled: true - "mq.message.received.count": # Number of messages received + "ibm.mq.message.received.count": # Number of messages received enabled: true - "mq.message.sent.count": # Number of messages sent + "ibm.mq.message.sent.count": # Number of messages sent enabled: true - "mq.max.instances": # Max channel instances + "ibm.mq.max.instances": # Max channel instances enabled: true - "mq.connection.count": # Active connections count + "ibm.mq.connection.count": # Active connections count enabled: true - "mq.manager.status": # Queue manager status + "ibm.mq.manager.status": # Queue manager status enabled: true - "mq.heartbeat": # Queue manager heartbeat + "ibm.mq.heartbeat": # Queue manager heartbeat enabled: true - "mq.archive.log.size": # Queue manager archive log size + "ibm.mq.archive.log.size": # Queue manager archive log size enabled: true - "mq.manager.max.active.channels": # Queue manager max active channels + "ibm.mq.manager.max.active.channels": # Queue manager max active channels enabled: true - "mq.manager.statistics.interval": # Queue manager statistics interval + "ibm.mq.manager.statistics.interval": # Queue manager statistics interval enabled: true - "mq.publish.count": # Topic publication count + "ibm.mq.publish.count": # Topic publication count enabled: true - "mq.subscription.count": # Topic subscription count + "ibm.mq.subscription.count": # Topic subscription count enabled: true - "mq.listener.status": # Listener status + "ibm.mq.listener.status": # Listener status enabled: true - "mq.unauthorized.event": # Number of authentication error events + "ibm.mq.unauthorized.event": # Number of authentication error events enabled: true - "mq.manager.max.handles": # Max open handles + "ibm.mq.manager.max.handles": # Max open handles enabled: true @@ -167,4 +167,4 @@ sslConnection: otlpExporter: otel.metric.export.interval: 5s otel.logs.exporter: none - otel.traces.exporter: none \ No newline at end of file + otel.traces.exporter: none From 6a6de13ee464a0642ff5ed4e3f98c6bbbe62b625 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 16 Jul 2025 14:13:21 -0700 Subject: [PATCH 46/66] additional attribute constants --- .../metricscollector/ChannelMetricsCollector.java | 14 +++++++++----- .../InquireChannelCmdCollector.java | 10 +++++++--- .../metricscollector/QueueCollectionBuddyTest.java | 4 ++-- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollector.java index ec7ffb866..44afdb28a 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/ChannelMetricsCollector.java @@ -7,6 +7,10 @@ import static com.ibm.mq.constants.CMQC.MQRC_SELECTOR_ERROR; import static com.ibm.mq.constants.CMQCFC.MQRCCF_CHL_STATUS_NOT_FOUND; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.IBM_MQ_CHANNEL_NAME; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.IBM_MQ_CHANNEL_START_TIME; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.IBM_MQ_CHANNEL_TYPE; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.IBM_MQ_JOB_NAME; import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.IBM_MQ_QUEUE_MANAGER; import com.ibm.mq.constants.CMQC; @@ -175,11 +179,11 @@ private void updateMetrics( throws PCFException { Attributes attributes = Attributes.builder() - .put("channel.name", channelName) - .put("channel.type", channelType) - .put("queue.manager", context.getQueueManagerName()) - .put("channel.start.time", channelStartTime) - .put("job.name", jobName) + .put(IBM_MQ_CHANNEL_NAME, channelName) + .put(IBM_MQ_CHANNEL_TYPE, channelType) + .put(IBM_MQ_QUEUE_MANAGER, context.getQueueManagerName()) + .put(IBM_MQ_CHANNEL_START_TIME, channelStartTime) + .put(IBM_MQ_JOB_NAME, jobName) .build(); if (context.getMetricsConfig().isIbmMqMessageCountEnabled()) { int received = message.getIntParameterValue(CMQCFC.MQIACH_MSGS); diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollector.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollector.java index a510fcce7..b0dc7286c 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollector.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/InquireChannelCmdCollector.java @@ -5,6 +5,10 @@ package io.opentelemetry.ibm.mq.metricscollector; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.IBM_MQ_CHANNEL_NAME; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.IBM_MQ_CHANNEL_TYPE; +import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.IBM_MQ_QUEUE_MANAGER; + import com.ibm.mq.constants.CMQCFC; import com.ibm.mq.constants.MQConstants; import com.ibm.mq.headers.pcf.MQCFIL; @@ -106,9 +110,9 @@ private void updateMetrics( throws PCFException { Attributes attributes = Attributes.builder() - .put("channel.name", channelName) - .put("channel.type", channelType) - .put("queue.manager", context.getQueueManagerName()) + .put(IBM_MQ_CHANNEL_NAME, channelName) + .put(IBM_MQ_CHANNEL_TYPE, channelType) + .put(IBM_MQ_QUEUE_MANAGER, context.getQueueManagerName()) .build(); if (context.getMetricsConfig().isIbmMqMaxInstancesEnabled() && message.getParameter(CMQCFC.MQIACH_MAX_INSTANCES) != null) { diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java index e1c64bc50..f32192502 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java @@ -67,7 +67,7 @@ void testProcessPcfRequestAndPublishQMetricsForInquireQStatusCmd() throws Except collectorContext, request, "*", InquireQStatusCmdCollector.ATTRIBUTES); Map> expectedValues = - new HashMap>( + new HashMap<>( ImmutableMap.of( "DEV.DEAD.LETTER.QUEUE", new HashMap<>( @@ -78,7 +78,7 @@ void testProcessPcfRequestAndPublishQMetricsForInquireQStatusCmd() throws Except "ibm.mq.onqtime.2", -1L, "ibm.mq.queue.depth", 0L)), "DEV.QUEUE.1", - new HashMap( + new HashMap<>( ImmutableMap.of( "ibm.mq.oldest.msg.age", -1L, "ibm.mq.uncommitted.messages", 10L, From 47ed258964e1c363f6874e38df3078d63f5673cc Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 24 Jul 2025 13:24:52 -0700 Subject: [PATCH 47/66] make build command more specific --- ibm-mq-metrics/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ibm-mq-metrics/README.md b/ibm-mq-metrics/README.md index a22345577..fc3ca9fce 100644 --- a/ibm-mq-metrics/README.md +++ b/ibm-mq-metrics/README.md @@ -61,7 +61,8 @@ Please turn on those events to take advantage of this monitoring. Build the package with: ```shell -./gradlew shadowJar +cd ibm-mq-metrics +../gradlew shadowJar ``` Note: Due to restrictive licensing, this uber-jar (fat-jar) does not include the IBM client jar f From 8442cc32eb57a3fa64f131e295b8f2baaf5118a8 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 24 Jul 2025 13:25:14 -0700 Subject: [PATCH 48/66] remove typo --- ibm-mq-metrics/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ibm-mq-metrics/README.md b/ibm-mq-metrics/README.md index fc3ca9fce..64c70e925 100644 --- a/ibm-mq-metrics/README.md +++ b/ibm-mq-metrics/README.md @@ -65,7 +65,7 @@ cd ibm-mq-metrics ../gradlew shadowJar ``` -Note: Due to restrictive licensing, this uber-jar (fat-jar) does not include the IBM client jar f +Note: Due to restrictive licensing, this uber-jar (fat-jar) does not include the IBM client jar. ## Run From 2563d04310dccb6ab1ba08047ecfdfdafc0f3faf Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 24 Jul 2025 13:26:32 -0700 Subject: [PATCH 49/66] fix path to jar --- ibm-mq-metrics/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ibm-mq-metrics/README.md b/ibm-mq-metrics/README.md index 64c70e925..1af0f127a 100644 --- a/ibm-mq-metrics/README.md +++ b/ibm-mq-metrics/README.md @@ -72,12 +72,13 @@ Note: Due to restrictive licensing, this uber-jar (fat-jar) does not include the Run the standalone jar alongside the IBM jar: ```shell +cd ibm-mq-metrics java \ -Djavax.net.ssl.keyStore=key.jks \ -Djavax.net.ssl.keyStorePassword= \ -Djavax.net.ssl.trustStore=key.jks \ -Djavax.net.ssl.trustStorePassword= \ - -cp target/ibm-mq-monitoring--all.jar:lib/com.ibm.mq.allclient.jar \ + -cp build/libs/ibm-mq-monitoring--all.jar:lib/com.ibm.mq.allclient.jar \ io.opentelemetry.ibm.mq.opentelemetry.Main \ ./my-config.yml ``` From 687dc12a989a1134d4e88ee4d68d558f9786569c Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 24 Jul 2025 13:33:39 -0700 Subject: [PATCH 50/66] note about java versions. remove appd extension troubleshooting tips --- ibm-mq-metrics/README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/ibm-mq-metrics/README.md b/ibm-mq-metrics/README.md index 1af0f127a..1f7f7e5d4 100644 --- a/ibm-mq-metrics/README.md +++ b/ibm-mq-metrics/README.md @@ -109,11 +109,13 @@ command, chg permission is needed. ### SSL Support +_Note: The following is only needed for versions of Java 8 before 8u161._ + 1. Configure the IBM SSL Cipher Suite in the config.yml. Note that, to use some CipherSuites the unrestricted policy needs to be configured in JRE. Please visit [this link](http://www.ibm.com/support/knowledgecenter/SSYKE2_8.0.0/com.ibm.java.security.component.80.doc/security-component/sdkpolicyfiles.html) for more details. For Oracle JRE, please update with [JCE Unlimited Strength Jurisdiction Policy](http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html). - The download includes a readme file with instructions on how to apply these files to JRE + The download includes a readme file with instructions on how to apply these files to JRE. 2. Please add the following JVM arguments to the MA start up command or script. @@ -172,8 +174,7 @@ See [docs/metrics.md](docs/metrics.md). ## Troubleshooting -1. Please follow the steps listed in this [troubleshooting-document](https://community.appdynamics.com/t5/Knowledge-Base/How-to-troubleshoot-missing-custom-metrics-or-extensions-metrics/ta-p/28695) in order to troubleshoot your issue. These are a set of common issues that customers might have faced during the installation of the extension. -2. Error `Completion Code '2', Reason '2495'` +1. Error `Completion Code '2', Reason '2495'` Normally this error occurs if the environment variables are not set up correctly for this extension to work MQ in Bindings Mode. If you are seeing `Failed to load the WebSphere MQ native JNI library: 'mqjbnd'`, please add the following jvm argument when starting the MA. @@ -194,20 +195,20 @@ See [docs/metrics.md](docs/metrics.md). Another way to get around this issue is to avoid using the Bindings mode. Connect using CLIENT transport type from a remote box. -3. Error `Completion Code '2', Reason '2035'` +2. Error `Completion Code '2', Reason '2035'` This could happen for various reasons but for most of the cases, for **Client** mode the user specified in config.yml is not authorized to access the queue manager. Also sometimes even if userid and password are correct, channel auth (CHLAUTH) for that queue manager blocks traffics from other ips, you need to contact admin to provide you access to the queue manager. For Bindings mode, please make sure that the MA is owned by a mqm user. -4. `MQJE001: Completion Code '2', Reason '2195'` +3. `MQJE001: Completion Code '2', Reason '2195'` This could happen in **Client** mode. Please make sure that the IBM MQ dependency jars are correctly referenced in classpath of monitor.xml -5. `MQJE001: Completion Code '2', Reason '2400'` +4. `MQJE001: Completion Code '2', Reason '2400'` This could happen if unsupported cipherSuite is provided or JRE not having/enabled unlimited jurisdiction policy files. Please check SSL Support section. -6. If you are seeing "NoClassDefFoundError" or "ClassNotFound" error for any of the MQ dependency even after providing correct path in monitor.xml, then you can also try copying all the required jars in WMQMonitor (MAHome/monitors/WMQMonitor) folder and provide classpath in monitor.xml like below +5. If you are seeing "NoClassDefFoundError" or "ClassNotFound" error for any of the MQ dependency even after providing correct path in monitor.xml, then you can also try copying all the required jars in WMQMonitor (MAHome/monitors/WMQMonitor) folder and provide classpath in monitor.xml like below ``` ibm-mq-monitoring--all.jar;com.ibm.mq.allclient.jar From 9459d288597085959dbe41dfeb161d9628e7641a Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 24 Jul 2025 13:39:52 -0700 Subject: [PATCH 51/66] fix jar filename --- ibm-mq-metrics/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ibm-mq-metrics/README.md b/ibm-mq-metrics/README.md index 1f7f7e5d4..ba39d6376 100644 --- a/ibm-mq-metrics/README.md +++ b/ibm-mq-metrics/README.md @@ -78,7 +78,7 @@ java \ -Djavax.net.ssl.keyStorePassword= \ -Djavax.net.ssl.trustStore=key.jks \ -Djavax.net.ssl.trustStorePassword= \ - -cp build/libs/ibm-mq-monitoring--all.jar:lib/com.ibm.mq.allclient.jar \ + -cp build/libs/opentelemetry-ibm-mq-monitoring--all.jar:lib/com.ibm.mq.allclient.jar \ io.opentelemetry.ibm.mq.opentelemetry.Main \ ./my-config.yml ``` @@ -211,13 +211,13 @@ See [docs/metrics.md](docs/metrics.md). 5. If you are seeing "NoClassDefFoundError" or "ClassNotFound" error for any of the MQ dependency even after providing correct path in monitor.xml, then you can also try copying all the required jars in WMQMonitor (MAHome/monitors/WMQMonitor) folder and provide classpath in monitor.xml like below ``` - ibm-mq-monitoring--all.jar;com.ibm.mq.allclient.jar + opentelemetry-ibm-mq-monitoring--all.jar;com.ibm.mq.allclient.jar ``` OR ``` - ibm-mq-monitoring--all.jar;com.ibm.mq.jar;com.ibm.mq.jmqi.jar;com.ibm.mq.commonservices.jar;com.ibm.mq.headers.jar;com.ibm.mq.pcf.jar;connector.jar;dhbcore.jar + opentelemetry-ibm-mq-monitoring--all.jar;com.ibm.mq.jar;com.ibm.mq.jmqi.jar;com.ibm.mq.commonservices.jar;com.ibm.mq.headers.jar;com.ibm.mq.pcf.jar;connector.jar;dhbcore.jar ``` ## Component Owners From 9743ad2cc44770ecc2cd2748cb93d59fa0949c17 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 24 Jul 2025 13:40:39 -0700 Subject: [PATCH 52/66] fix exception name --- ibm-mq-metrics/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ibm-mq-metrics/README.md b/ibm-mq-metrics/README.md index ba39d6376..bae902298 100644 --- a/ibm-mq-metrics/README.md +++ b/ibm-mq-metrics/README.md @@ -208,7 +208,7 @@ See [docs/metrics.md](docs/metrics.md). 4. `MQJE001: Completion Code '2', Reason '2400'` This could happen if unsupported cipherSuite is provided or JRE not having/enabled unlimited jurisdiction policy files. Please check SSL Support section. -5. If you are seeing "NoClassDefFoundError" or "ClassNotFound" error for any of the MQ dependency even after providing correct path in monitor.xml, then you can also try copying all the required jars in WMQMonitor (MAHome/monitors/WMQMonitor) folder and provide classpath in monitor.xml like below +5. If you are seeing `NoClassDefFoundError` or `ClassNotFoundException` error for any of the MQ dependency even after providing correct path in monitor.xml, then you can also try copying all the required jars in WMQMonitor (MAHome/monitors/WMQMonitor) folder and provide classpath in monitor.xml like below ``` opentelemetry-ibm-mq-monitoring--all.jar;com.ibm.mq.allclient.jar From c8052e4b8ba21a6bf5e986807e4614771d635df4 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 24 Jul 2025 13:42:37 -0700 Subject: [PATCH 53/66] fix copypasta --- ibm-mq-metrics/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ibm-mq-metrics/build.gradle.kts b/ibm-mq-metrics/build.gradle.kts index fcf53407e..41ea1fa01 100644 --- a/ibm-mq-metrics/build.gradle.kts +++ b/ibm-mq-metrics/build.gradle.kts @@ -6,8 +6,8 @@ plugins { } description = "IBM-MQ metrics" -otelJava.moduleName.set("io.opentelemetry.contrib.jmxscraper") -application.mainClass.set("io.opentelemetry.contrib.jmxscraper.JmxScraper") +otelJava.moduleName.set("io.opentelemetry.contrib.ibm-mq-metrics") +application.mainClass.set("io.opentelemetry.ibm.mq.opentelemetry.Main") sourceSets { create("integrationTest") { From 58654f7e0750ba4f8f6d35d01c6860c06dbfe334 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 24 Jul 2025 14:11:55 -0700 Subject: [PATCH 54/66] java version comment --- ibm-mq-metrics/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ibm-mq-metrics/README.md b/ibm-mq-metrics/README.md index bae902298..5c75acd32 100644 --- a/ibm-mq-metrics/README.md +++ b/ibm-mq-metrics/README.md @@ -109,7 +109,7 @@ command, chg permission is needed. ### SSL Support -_Note: The following is only needed for versions of Java 8 before 8u161._ +_Note: The following is only needed for versions of Java 8 before 8u161._ 1. Configure the IBM SSL Cipher Suite in the config.yml. Note that, to use some CipherSuites the unrestricted policy needs to be configured in JRE. From 3bf27daa72a2a453a41fb009eb5945787e97a8d3 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 24 Jul 2025 14:12:06 -0700 Subject: [PATCH 55/66] fix units to singular --- ibm-mq-metrics/docs/metrics.md | 58 +++++++++---------- ibm-mq-metrics/model/metrics.yaml | 58 +++++++++---------- .../opentelemetry/ibm/mq/metrics/Metrics.java | 58 +++++++++---------- 3 files changed, 87 insertions(+), 87 deletions(-) diff --git a/ibm-mq-metrics/docs/metrics.md b/ibm-mq-metrics/docs/metrics.md index 2f48b7868..373701ada 100644 --- a/ibm-mq-metrics/docs/metrics.md +++ b/ibm-mq-metrics/docs/metrics.md @@ -5,7 +5,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.message.retry.count` | Gauge | `{messages}` | Number of message retries | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.message.retry.count` | Gauge | `{message}` | Number of message retries | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.message.retry.count` Attributes @@ -41,7 +41,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.max.sharing.conversations` | Gauge | `{conversations}` | Maximum number of conversations permitted on this channel instance. | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.max.sharing.conversations` | Gauge | `{conversation}` | Maximum number of conversations permitted on this channel instance. | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.max.sharing.conversations` Attributes @@ -60,7 +60,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.current.sharing.conversations` | Gauge | `{conversations}` | Current number of conversations permitted on this channel instance. | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.current.sharing.conversations` | Gauge | `{conversation}` | Current number of conversations permitted on this channel instance. | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.current.sharing.conversations` Attributes @@ -79,7 +79,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.byte.received` | Gauge | `{bytes}` | Number of bytes received | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.byte.received` | Gauge | `By` | Number of bytes received | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.byte.received` Attributes @@ -98,7 +98,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.byte.sent` | Gauge | `{bytes}` | Number of bytes sent | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.byte.sent` | Gauge | `By` | Number of bytes sent | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.byte.sent` Attributes @@ -117,7 +117,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.buffers.received` | Gauge | `{buffers}` | Buffers received | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.buffers.received` | Gauge | `{buffer}` | Buffers received | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.buffers.received` Attributes @@ -136,7 +136,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.buffers.sent` | Gauge | `{buffers}` | Buffers sent | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.buffers.sent` | Gauge | `{buffer}` | Buffers sent | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.buffers.sent` Attributes @@ -155,7 +155,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.message.count` | Gauge | `{messages}` | Message count | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.message.count` | Gauge | `{message}` | Message count | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.message.count` Attributes @@ -174,7 +174,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.open.input.count` | Gauge | `{applications}` | Count of applications sending messages to the queue | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.open.input.count` | Gauge | `{application}` | Count of applications sending messages to the queue | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.open.input.count` Attributes @@ -193,7 +193,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.open.output.count` | Gauge | `{applications}` | Count of applications consuming messages from the queue | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.open.output.count` | Gauge | `{application}` | Count of applications consuming messages from the queue | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.open.output.count` Attributes @@ -250,7 +250,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.queue.depth.full.event` | Counter | `{events}` | The number of full queue events | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.depth.full.event` | Counter | `{event}` | The number of full queue events | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.queue.depth.full.event` Attributes @@ -268,7 +268,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.queue.depth.high.event` | Counter | `{events}` | The number of high queue events | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.depth.high.event` | Counter | `{event}` | The number of high queue events | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.queue.depth.high.event` Attributes @@ -286,7 +286,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.queue.depth.low.event` | Counter | `{events}` | The number of low queue events | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.depth.low.event` | Counter | `{event}` | The number of low queue events | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.queue.depth.low.event` Attributes @@ -304,7 +304,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.uncommitted.messages` | Gauge | `{messages}` | Number of uncommitted messages | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.uncommitted.messages` | Gauge | `{message}` | Number of uncommitted messages | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.uncommitted.messages` Attributes @@ -380,7 +380,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.instances.per.client` | Gauge | `{instances}` | Instances per client | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.instances.per.client` | Gauge | `{instance}` | Instances per client | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.instances.per.client` Attributes @@ -399,7 +399,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.message.deq.count` | Gauge | `{messages}` | Message dequeue count | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.message.deq.count` | Gauge | `{message}` | Message dequeue count | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.message.deq.count` Attributes @@ -418,7 +418,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.message.enq.count` | Gauge | `{messages}` | Message enqueue count | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.message.enq.count` | Gauge | `{message}` | Message enqueue count | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.message.enq.count` Attributes @@ -437,7 +437,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.queue.depth` | Gauge | `{messages}` | Current queue depth | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.queue.depth` | Gauge | `{message}` | Current queue depth | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.queue.depth` Attributes @@ -490,7 +490,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.manager.active.channels` | Gauge | `{channels}` | The queue manager active maximum channels limit | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.manager.active.channels` | Gauge | `{channel}` | The queue manager active maximum channels limit | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.manager.active.channels` Attributes @@ -520,7 +520,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.max.queue.depth` | Gauge | `{messages}` | Maximum queue depth | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.max.queue.depth` | Gauge | `{message}` | Maximum queue depth | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.max.queue.depth` Attributes @@ -577,7 +577,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.message.received.count` | Gauge | `{messages}` | Number of messages received | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.message.received.count` | Gauge | `{message}` | Number of messages received | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.message.received.count` Attributes @@ -594,7 +594,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.message.sent.count` | Gauge | `{messages}` | Number of messages sent | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.message.sent.count` | Gauge | `{message}` | Number of messages sent | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.message.sent.count` Attributes @@ -611,7 +611,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.max.instances` | Gauge | `{instances}` | Max channel instances | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.max.instances` | Gauge | `{instance}` | Max channel instances | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.max.instances` Attributes @@ -628,7 +628,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.connection.count` | Gauge | `{connections}` | Active connections count | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.connection.count` | Gauge | `{connection}` | Active connections count | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.connection.count` Attributes @@ -688,7 +688,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.manager.max.active.channels` | Gauge | `{channels}` | Queue manager max active channels | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.manager.max.active.channels` | Gauge | `{channel}` | Queue manager max active channels | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.manager.max.active.channels` Attributes @@ -718,7 +718,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.publish.count` | Gauge | `{publications}` | Topic publication count | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.publish.count` | Gauge | `{publication}` | Topic publication count | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.publish.count` Attributes @@ -736,7 +736,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.subscription.count` | Gauge | `{subscriptions}` | Topic subscription count | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.subscription.count` | Gauge | `{subscription}` | Topic subscription count | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.subscription.count` Attributes @@ -770,7 +770,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.unauthorized.event` | Counter | `{events}` | Number of authentication error events | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.unauthorized.event` | Counter | `{event}` | Number of authentication error events | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.unauthorized.event` Attributes @@ -791,7 +791,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.manager.max.handles` | Gauge | `{events}` | Max open handles | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.manager.max.handles` | Gauge | `{event}` | Max open handles | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.manager.max.handles` Attributes diff --git a/ibm-mq-metrics/model/metrics.yaml b/ibm-mq-metrics/model/metrics.yaml index ad1710875..439b75e10 100644 --- a/ibm-mq-metrics/model/metrics.yaml +++ b/ibm-mq-metrics/model/metrics.yaml @@ -5,7 +5,7 @@ groups: stability: development brief: "Number of message retries" instrument: gauge - unit: "{messages}" + unit: "{message}" attributes: - ref: ibm.mq.channel.name requirement_level: required @@ -37,7 +37,7 @@ groups: stability: development brief: "Maximum number of conversations permitted on this channel instance." instrument: gauge - unit: "{conversations}" + unit: "{conversation}" attributes: - ref: ibm.mq.channel.name requirement_level: required @@ -53,7 +53,7 @@ groups: type: metric metric_name: ibm.mq.current.sharing.conversations stability: development - unit: "{conversations}" + unit: "{conversation}" brief: "Current number of conversations permitted on this channel instance." instrument: gauge attributes: @@ -73,7 +73,7 @@ groups: stability: development brief: "Number of bytes received" instrument: gauge - unit: "{bytes}" + unit: "By" attributes: - ref: ibm.mq.channel.name requirement_level: required @@ -91,7 +91,7 @@ groups: stability: development brief: "Number of bytes sent" instrument: gauge - unit: "{bytes}" + unit: "By" attributes: - ref: ibm.mq.channel.name requirement_level: required @@ -109,7 +109,7 @@ groups: stability: development brief: "Buffers received" instrument: gauge - unit: "{buffers}" + unit: "{buffer}" attributes: - ref: ibm.mq.channel.name requirement_level: required @@ -126,7 +126,7 @@ groups: metric_name: ibm.mq.buffers.sent stability: development brief: "Buffers sent" - unit: "{buffers}" + unit: "{buffer}" instrument: gauge attributes: - ref: ibm.mq.channel.name @@ -144,7 +144,7 @@ groups: metric_name: ibm.mq.message.count stability: development brief: "Message count" - unit: "{messages}" + unit: "{message}" instrument: gauge attributes: - ref: ibm.mq.channel.name @@ -163,7 +163,7 @@ groups: stability: development brief: "Count of applications sending messages to the queue" instrument: gauge - unit: "{applications}" + unit: "{application}" attributes: - ref: ibm.mq.queue.manager requirement_level: required @@ -177,7 +177,7 @@ groups: stability: development brief: "Count of applications consuming messages from the queue" instrument: gauge - unit: "{applications}" + unit: "{application}" attributes: - ref: ibm.mq.queue.manager requirement_level: required @@ -219,7 +219,7 @@ groups: stability: development brief: "The number of full queue events" instrument: counter - unit: "{events}" + unit: "{event}" attributes: - ref: ibm.mq.queue.manager requirement_level: required @@ -231,7 +231,7 @@ groups: stability: development brief: "The number of high queue events" instrument: counter - unit: "{events}" + unit: "{event}" attributes: - ref: ibm.mq.queue.manager requirement_level: required @@ -243,7 +243,7 @@ groups: stability: development brief: "The number of low queue events" instrument: counter - unit: "{events}" + unit: "{event}" attributes: - ref: ibm.mq.queue.manager requirement_level: required @@ -255,7 +255,7 @@ groups: stability: development brief: "Number of uncommitted messages" instrument: gauge - unit: "{messages}" + unit: "{message}" attributes: - ref: ibm.mq.queue.manager requirement_level: required @@ -311,7 +311,7 @@ groups: stability: development brief: "Instances per client" instrument: gauge - unit: "{instances}" + unit: "{instance}" attributes: - ref: ibm.mq.queue.manager requirement_level: required @@ -325,7 +325,7 @@ groups: stability: development brief: "Message dequeue count" instrument: gauge - unit: "{messages}" + unit: "{message}" attributes: - ref: ibm.mq.queue.manager requirement_level: required @@ -339,7 +339,7 @@ groups: stability: development brief: "Message enqueue count" instrument: gauge - unit: "{messages}" + unit: "{message}" attributes: - ref: ibm.mq.queue.manager requirement_level: required @@ -353,7 +353,7 @@ groups: stability: development brief: "Current queue depth" instrument: gauge - unit: "{messages}" + unit: "{message}" attributes: - ref: ibm.mq.queue.manager requirement_level: required @@ -391,7 +391,7 @@ groups: stability: development brief: "The queue manager active maximum channels limit" instrument: gauge - unit: "{channels}" + unit: "{channel}" attributes: - ref: ibm.mq.queue.manager requirement_level: required @@ -411,7 +411,7 @@ groups: stability: development brief: "Maximum queue depth" instrument: gauge - unit: "{messages}" + unit: "{message}" attributes: - ref: ibm.mq.queue.manager requirement_level: required @@ -453,7 +453,7 @@ groups: stability: development brief: "Number of messages received" instrument: gauge - unit: "{messages}" + unit: "{message}" attributes: - ref: ibm.mq.channel.name requirement_level: required @@ -467,7 +467,7 @@ groups: stability: development brief: "Number of messages sent" instrument: gauge - unit: "{messages}" + unit: "{message}" attributes: - ref: ibm.mq.channel.name requirement_level: required @@ -481,7 +481,7 @@ groups: stability: development brief: "Max channel instances" instrument: gauge - unit: "{instances}" + unit: "{instance}" attributes: - ref: ibm.mq.channel.name requirement_level: required @@ -495,7 +495,7 @@ groups: stability: development brief: "Active connections count" instrument: gauge - unit: "{connections}" + unit: "{connection}" attributes: - ref: ibm.mq.queue.manager requirement_level: required @@ -535,7 +535,7 @@ groups: stability: development brief: "Queue manager max active channels" instrument: gauge - unit: "{channels}" + unit: "{channel}" attributes: - ref: ibm.mq.queue.manager requirement_level: required @@ -555,7 +555,7 @@ groups: stability: development brief: "Topic publication count" instrument: gauge - unit: "{publications}" + unit: "{publication}" attributes: - ref: ibm.mq.queue.manager requirement_level: required @@ -567,7 +567,7 @@ groups: stability: development brief: "Topic subscription count" instrument: gauge - unit: "{subscriptions}" + unit: "{subscription}" attributes: - ref: ibm.mq.queue.manager requirement_level: required @@ -591,7 +591,7 @@ groups: stability: development brief: "Number of authentication error events" instrument: counter - unit: "{events}" + unit: "{event}" attributes: - ref: ibm.mq.queue.manager requirement_level: required @@ -605,7 +605,7 @@ groups: stability: development brief: "Max open handles" instrument: gauge - unit: "{events}" + unit: "{event}" attributes: - ref: ibm.mq.queue.manager requirement_level: required 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 94fd4180b..838d1d3ad 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 @@ -19,7 +19,7 @@ public static LongGauge createIbmMqMessageRetryCount(Meter meter) { return meter .gaugeBuilder("ibm.mq.message.retry.count") .ofLongs() - .setUnit("{messages}") + .setUnit("{message}") .setDescription("Number of message retries") .build(); } @@ -37,7 +37,7 @@ public static LongGauge createIbmMqMaxSharingConversations(Meter meter) { return meter .gaugeBuilder("ibm.mq.max.sharing.conversations") .ofLongs() - .setUnit("{conversations}") + .setUnit("{conversation}") .setDescription("Maximum number of conversations permitted on this channel instance.") .build(); } @@ -46,7 +46,7 @@ public static LongGauge createIbmMqCurrentSharingConversations(Meter meter) { return meter .gaugeBuilder("ibm.mq.current.sharing.conversations") .ofLongs() - .setUnit("{conversations}") + .setUnit("{conversation}") .setDescription("Current number of conversations permitted on this channel instance.") .build(); } @@ -55,7 +55,7 @@ public static LongGauge createIbmMqByteReceived(Meter meter) { return meter .gaugeBuilder("ibm.mq.byte.received") .ofLongs() - .setUnit("{bytes}") + .setUnit("By") .setDescription("Number of bytes received") .build(); } @@ -64,7 +64,7 @@ public static LongGauge createIbmMqByteSent(Meter meter) { return meter .gaugeBuilder("ibm.mq.byte.sent") .ofLongs() - .setUnit("{bytes}") + .setUnit("By") .setDescription("Number of bytes sent") .build(); } @@ -73,7 +73,7 @@ public static LongGauge createIbmMqBuffersReceived(Meter meter) { return meter .gaugeBuilder("ibm.mq.buffers.received") .ofLongs() - .setUnit("{buffers}") + .setUnit("{buffer}") .setDescription("Buffers received") .build(); } @@ -82,7 +82,7 @@ public static LongGauge createIbmMqBuffersSent(Meter meter) { return meter .gaugeBuilder("ibm.mq.buffers.sent") .ofLongs() - .setUnit("{buffers}") + .setUnit("{buffer}") .setDescription("Buffers sent") .build(); } @@ -91,7 +91,7 @@ public static LongGauge createIbmMqMessageCount(Meter meter) { return meter .gaugeBuilder("ibm.mq.message.count") .ofLongs() - .setUnit("{messages}") + .setUnit("{message}") .setDescription("Message count") .build(); } @@ -100,7 +100,7 @@ public static LongGauge createIbmMqOpenInputCount(Meter meter) { return meter .gaugeBuilder("ibm.mq.open.input.count") .ofLongs() - .setUnit("{applications}") + .setUnit("{application}") .setDescription("Count of applications sending messages to the queue") .build(); } @@ -109,7 +109,7 @@ public static LongGauge createIbmMqOpenOutputCount(Meter meter) { return meter .gaugeBuilder("ibm.mq.open.output.count") .ofLongs() - .setUnit("{applications}") + .setUnit("{application}") .setDescription("Count of applications consuming messages from the queue") .build(); } @@ -135,7 +135,7 @@ public static LongGauge createIbmMqServiceInterval(Meter meter) { public static LongCounter createIbmMqQueueDepthFullEvent(Meter meter) { return meter .counterBuilder("ibm.mq.queue.depth.full.event") - .setUnit("{events}") + .setUnit("{event}") .setDescription("The number of full queue events") .build(); } @@ -143,7 +143,7 @@ public static LongCounter createIbmMqQueueDepthFullEvent(Meter meter) { public static LongCounter createIbmMqQueueDepthHighEvent(Meter meter) { return meter .counterBuilder("ibm.mq.queue.depth.high.event") - .setUnit("{events}") + .setUnit("{event}") .setDescription("The number of high queue events") .build(); } @@ -151,7 +151,7 @@ public static LongCounter createIbmMqQueueDepthHighEvent(Meter meter) { public static LongCounter createIbmMqQueueDepthLowEvent(Meter meter) { return meter .counterBuilder("ibm.mq.queue.depth.low.event") - .setUnit("{events}") + .setUnit("{event}") .setDescription("The number of low queue events") .build(); } @@ -160,7 +160,7 @@ public static LongGauge createIbmMqUncommittedMessages(Meter meter) { return meter .gaugeBuilder("ibm.mq.uncommitted.messages") .ofLongs() - .setUnit("{messages}") + .setUnit("{message}") .setDescription("Number of uncommitted messages") .build(); } @@ -196,7 +196,7 @@ public static LongGauge createIbmMqInstancesPerClient(Meter meter) { return meter .gaugeBuilder("ibm.mq.instances.per.client") .ofLongs() - .setUnit("{instances}") + .setUnit("{instance}") .setDescription("Instances per client") .build(); } @@ -205,7 +205,7 @@ public static LongGauge createIbmMqMessageDeqCount(Meter meter) { return meter .gaugeBuilder("ibm.mq.message.deq.count") .ofLongs() - .setUnit("{messages}") + .setUnit("{message}") .setDescription("Message dequeue count") .build(); } @@ -214,7 +214,7 @@ public static LongGauge createIbmMqMessageEnqCount(Meter meter) { return meter .gaugeBuilder("ibm.mq.message.enq.count") .ofLongs() - .setUnit("{messages}") + .setUnit("{message}") .setDescription("Message enqueue count") .build(); } @@ -223,7 +223,7 @@ public static LongGauge createIbmMqQueueDepth(Meter meter) { return meter .gaugeBuilder("ibm.mq.queue.depth") .ofLongs() - .setUnit("{messages}") + .setUnit("{message}") .setDescription("Current queue depth") .build(); } @@ -251,7 +251,7 @@ public static LongGauge createIbmMqManagerActiveChannels(Meter meter) { return meter .gaugeBuilder("ibm.mq.manager.active.channels") .ofLongs() - .setUnit("{channels}") + .setUnit("{channel}") .setDescription("The queue manager active maximum channels limit") .build(); } @@ -269,7 +269,7 @@ public static LongGauge createIbmMqMaxQueueDepth(Meter meter) { return meter .gaugeBuilder("ibm.mq.max.queue.depth") .ofLongs() - .setUnit("{messages}") + .setUnit("{message}") .setDescription("Maximum queue depth") .build(); } @@ -298,7 +298,7 @@ public static LongGauge createIbmMqMessageReceivedCount(Meter meter) { return meter .gaugeBuilder("ibm.mq.message.received.count") .ofLongs() - .setUnit("{messages}") + .setUnit("{message}") .setDescription("Number of messages received") .build(); } @@ -307,7 +307,7 @@ public static LongGauge createIbmMqMessageSentCount(Meter meter) { return meter .gaugeBuilder("ibm.mq.message.sent.count") .ofLongs() - .setUnit("{messages}") + .setUnit("{message}") .setDescription("Number of messages sent") .build(); } @@ -316,7 +316,7 @@ public static LongGauge createIbmMqMaxInstances(Meter meter) { return meter .gaugeBuilder("ibm.mq.max.instances") .ofLongs() - .setUnit("{instances}") + .setUnit("{instance}") .setDescription("Max channel instances") .build(); } @@ -325,7 +325,7 @@ public static LongGauge createIbmMqConnectionCount(Meter meter) { return meter .gaugeBuilder("ibm.mq.connection.count") .ofLongs() - .setUnit("{connections}") + .setUnit("{connection}") .setDescription("Active connections count") .build(); } @@ -361,7 +361,7 @@ public static LongGauge createIbmMqManagerMaxActiveChannels(Meter meter) { return meter .gaugeBuilder("ibm.mq.manager.max.active.channels") .ofLongs() - .setUnit("{channels}") + .setUnit("{channel}") .setDescription("Queue manager max active channels") .build(); } @@ -379,7 +379,7 @@ public static LongGauge createIbmMqPublishCount(Meter meter) { return meter .gaugeBuilder("ibm.mq.publish.count") .ofLongs() - .setUnit("{publications}") + .setUnit("{publication}") .setDescription("Topic publication count") .build(); } @@ -388,7 +388,7 @@ public static LongGauge createIbmMqSubscriptionCount(Meter meter) { return meter .gaugeBuilder("ibm.mq.subscription.count") .ofLongs() - .setUnit("{subscriptions}") + .setUnit("{subscription}") .setDescription("Topic subscription count") .build(); } @@ -405,7 +405,7 @@ public static LongGauge createIbmMqListenerStatus(Meter meter) { public static LongCounter createIbmMqUnauthorizedEvent(Meter meter) { return meter .counterBuilder("ibm.mq.unauthorized.event") - .setUnit("{events}") + .setUnit("{event}") .setDescription("Number of authentication error events") .build(); } @@ -414,7 +414,7 @@ public static LongGauge createIbmMqManagerMaxHandles(Meter meter) { return meter .gaugeBuilder("ibm.mq.manager.max.handles") .ofLongs() - .setUnit("{events}") + .setUnit("{event}") .setDescription("Max open handles") .build(); } From d39dcb8c75c53c256a10d2a3569f9048af3dd987 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 24 Jul 2025 14:38:38 -0700 Subject: [PATCH 56/66] fix units to bytes instead of mib --- ibm-mq-metrics/docs/metrics.md | 10 +++++----- ibm-mq-metrics/model/metrics.yaml | 10 +++++----- .../io/opentelemetry/ibm/mq/metrics/Metrics.java | 13 ++++++++----- .../metricscollector/QueueCollectionBuddy.java | 16 +++++++++++++--- .../QueueManagerMetricsCollector.java | 7 ++++--- .../templates/registry/java/Metrics.java.j2 | 2 ++ 6 files changed, 37 insertions(+), 21 deletions(-) diff --git a/ibm-mq-metrics/docs/metrics.md b/ibm-mq-metrics/docs/metrics.md index 373701ada..52b9165be 100644 --- a/ibm-mq-metrics/docs/metrics.md +++ b/ibm-mq-metrics/docs/metrics.md @@ -342,7 +342,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.current.max.queue.filesize` | Gauge | `mib` | Current maximum queue file size | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.current.max.queue.filesize` | Gauge | `By` | Current maximum queue file size | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.current.max.queue.filesize` Attributes @@ -361,7 +361,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.current.queue.filesize` | Gauge | `mib` | Current queue file size | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.current.queue.filesize` | Gauge | `By` | Current queue file size | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.current.queue.filesize` Attributes @@ -475,7 +475,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.reusable.log.size` | Gauge | `mib` | The amount of space occupied, in megabytes, by log extents available to be reused. | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.reusable.log.size` | Gauge | `By` | The amount of space occupied, in megabytes, by log extents available to be reused. | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.reusable.log.size` Attributes @@ -505,7 +505,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.restart.log.size` | Gauge | `mib` | Size of the log data required for restart recovery in megabytes. | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.restart.log.size` | Gauge | `By` | Size of the log data required for restart recovery in megabytes. | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.restart.log.size` Attributes @@ -673,7 +673,7 @@ | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.archive.log.size` | Gauge | `mib` | Queue manager archive log size | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.archive.log.size` | Gauge | `By` | Queue manager archive log size | ![Development](https://img.shields.io/badge/-development-blue) | ### `ibm.mq.archive.log.size` Attributes diff --git a/ibm-mq-metrics/model/metrics.yaml b/ibm-mq-metrics/model/metrics.yaml index 439b75e10..057d72015 100644 --- a/ibm-mq-metrics/model/metrics.yaml +++ b/ibm-mq-metrics/model/metrics.yaml @@ -283,7 +283,7 @@ groups: stability: development brief: "Current maximum queue file size" instrument: gauge - unit: "mib" + unit: "By" attributes: - ref: ibm.mq.queue.manager requirement_level: required @@ -297,7 +297,7 @@ groups: stability: development brief: "Current queue file size" instrument: gauge - unit: "mib" + unit: "By" attributes: - ref: ibm.mq.queue.manager requirement_level: required @@ -381,7 +381,7 @@ groups: stability: development brief: "The amount of space occupied, in megabytes, by log extents available to be reused." instrument: gauge - unit: "mib" + unit: "By" attributes: - ref: ibm.mq.queue.manager requirement_level: required @@ -401,7 +401,7 @@ groups: stability: development brief: "Size of the log data required for restart recovery in megabytes." instrument: gauge - unit: "mib" + unit: "By" attributes: - ref: ibm.mq.queue.manager requirement_level: required @@ -525,7 +525,7 @@ groups: stability: development brief: "Queue manager archive log size" instrument: gauge - unit: "mib" + unit: "By" attributes: - ref: ibm.mq.queue.manager requirement_level: required 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 838d1d3ad..f6e65ae9c 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 @@ -8,11 +8,14 @@ import io.opentelemetry.api.metrics.LongCounter; import io.opentelemetry.api.metrics.LongGauge; import io.opentelemetry.api.metrics.Meter; +import java.util.function.Function; // This file is generated using weaver. Do not edit manually. /** Metric definitions generated from a Weaver model. Do not edit manually. */ public final class Metrics { + public static final Function MIBY_TO_BYTES = x -> x * 1024L * 1024L; + private Metrics() {} public static LongGauge createIbmMqMessageRetryCount(Meter meter) { @@ -178,7 +181,7 @@ public static LongGauge createIbmMqCurrentMaxQueueFilesize(Meter meter) { return meter .gaugeBuilder("ibm.mq.current.max.queue.filesize") .ofLongs() - .setUnit("mib") + .setUnit("By") .setDescription("Current maximum queue file size") .build(); } @@ -187,7 +190,7 @@ public static LongGauge createIbmMqCurrentQueueFilesize(Meter meter) { return meter .gaugeBuilder("ibm.mq.current.queue.filesize") .ofLongs() - .setUnit("mib") + .setUnit("By") .setDescription("Current queue file size") .build(); } @@ -241,7 +244,7 @@ public static LongGauge createIbmMqReusableLogSize(Meter meter) { return meter .gaugeBuilder("ibm.mq.reusable.log.size") .ofLongs() - .setUnit("mib") + .setUnit("By") .setDescription( "The amount of space occupied, in megabytes, by log extents available to be reused.") .build(); @@ -260,7 +263,7 @@ public static LongGauge createIbmMqRestartLogSize(Meter meter) { return meter .gaugeBuilder("ibm.mq.restart.log.size") .ofLongs() - .setUnit("mib") + .setUnit("By") .setDescription("Size of the log data required for restart recovery in megabytes.") .build(); } @@ -352,7 +355,7 @@ public static LongGauge createIbmMqArchiveLogSize(Meter meter) { return meter .gaugeBuilder("ibm.mq.archive.log.size") .ofLongs() - .setUnit("mib") + .setUnit("By") .setDescription("Queue manager archive log size") .build(); } diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java index 9bfc96e2c..1bb7da515 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java @@ -13,6 +13,7 @@ import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.IBM_MQ_QUEUE_MANAGER; import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.IBM_MQ_QUEUE_TYPE; import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.MESSAGING_DESTINATION_NAME; +import static io.opentelemetry.ibm.mq.metrics.Metrics.MIBY_TO_BYTES; import com.ibm.mq.constants.CMQC; import com.ibm.mq.constants.CMQCFC; @@ -55,9 +56,16 @@ private interface AllowedGauge { private static AllowedGauge createAllowedGauge( LongGauge gauge, Function allowed) { + return createAllowedGauge(gauge, allowed, Integer::longValue /*identity*/); + } + + private static AllowedGauge createAllowedGauge( + LongGauge gauge, + Function allowed, + Function unitMangler) { return (context, val, attributes) -> { if (allowed.apply(context.getMetricsConfig())) { - gauge.set(val, attributes); + gauge.set(unitMangler.apply(val), attributes); } }; } @@ -118,12 +126,14 @@ private static AllowedGauge createAllowedGauge( CMQCFC.MQIACF_CUR_Q_FILE_SIZE, createAllowedGauge( Metrics.createIbmMqCurrentQueueFilesize(meter), - MetricsConfig::isIbmMqCurrentQueueFilesizeEnabled)); + MetricsConfig::isIbmMqCurrentQueueFilesizeEnabled, + MIBY_TO_BYTES)); gauges.put( CMQCFC.MQIACF_CUR_MAX_FILE_SIZE, createAllowedGauge( Metrics.createIbmMqCurrentMaxQueueFilesize(meter), - MetricsConfig::isIbmMqCurrentMaxQueueFilesizeEnabled)); + MetricsConfig::isIbmMqCurrentMaxQueueFilesizeEnabled, + MIBY_TO_BYTES)); this.onqtimeShort = Metrics.createIbmMqOnqtime1(meter); this.onqtimeLong = Metrics.createIbmMqOnqtime2(meter); 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 4dbd73878..2b3d57086 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 @@ -6,6 +6,7 @@ package io.opentelemetry.ibm.mq.metricscollector; import static io.opentelemetry.ibm.mq.metrics.IbmMqAttributes.IBM_MQ_QUEUE_MANAGER; +import static io.opentelemetry.ibm.mq.metrics.Metrics.MIBY_TO_BYTES; import com.ibm.mq.constants.CMQCFC; import com.ibm.mq.headers.pcf.PCFMessage; @@ -76,15 +77,15 @@ public void accept(MetricsCollectorContext context) { } if (context.getMetricsConfig().isIbmMqRestartLogSizeEnabled()) { int logSize = responses.get(0).getIntParameterValue(CMQCFC.MQIACF_RESTART_LOG_SIZE); - restartLogSizeGauge.set(logSize, attributes); + restartLogSizeGauge.set(MIBY_TO_BYTES.apply(logSize), attributes); } if (context.getMetricsConfig().isIbmMqReusableLogSizeEnabled()) { int logSize = responses.get(0).getIntParameterValue(CMQCFC.MQIACF_REUSABLE_LOG_SIZE); - reuseLogSizeGauge.set(logSize, attributes); + reuseLogSizeGauge.set(MIBY_TO_BYTES.apply(logSize), attributes); } if (context.getMetricsConfig().isIbmMqArchiveLogSizeEnabled()) { int logSize = responses.get(0).getIntParameterValue(CMQCFC.MQIACF_ARCHIVE_LOG_SIZE); - archiveLogSizeGauge.set(logSize, attributes); + archiveLogSizeGauge.set(MIBY_TO_BYTES.apply(logSize), attributes); } if (context.getMetricsConfig().isIbmMqManagerMaxActiveChannelsEnabled()) { int maxActiveChannels = context.getQueueManager().getMaxActiveChannels(); diff --git a/ibm-mq-metrics/templates/registry/java/Metrics.java.j2 b/ibm-mq-metrics/templates/registry/java/Metrics.java.j2 index c342859b2..e47cfab8e 100644 --- a/ibm-mq-metrics/templates/registry/java/Metrics.java.j2 +++ b/ibm-mq-metrics/templates/registry/java/Metrics.java.j2 @@ -7,11 +7,13 @@ package io.opentelemetry.ibm.mq.metrics; import io.opentelemetry.api.metrics.LongCounter; import io.opentelemetry.api.metrics.LongGauge; import io.opentelemetry.api.metrics.Meter; +import java.util.function.Function; // This file is generated using weaver. Do not edit manually. /** Metric definitions generated from a Weaver model. Do not edit manually. */ public final class Metrics { +public final static Function MIBY_TO_BYTES = x -> x * 1024L * 1024L; private Metrics(){ } {% for metric in ctx %} From 82311279105db14938d3bee99b89928b22eedf5f Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 24 Jul 2025 14:40:01 -0700 Subject: [PATCH 57/66] remove word maven --- ibm-mq-metrics/src/integrationTest/resources/log4j2.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ibm-mq-metrics/src/integrationTest/resources/log4j2.xml b/ibm-mq-metrics/src/integrationTest/resources/log4j2.xml index 57fb99df6..f1508b386 100644 --- a/ibm-mq-metrics/src/integrationTest/resources/log4j2.xml +++ b/ibm-mq-metrics/src/integrationTest/resources/log4j2.xml @@ -2,7 +2,7 @@ - + From fb8a19b3464bf84bdde65533075062289fb757b6 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 24 Jul 2025 14:40:55 -0700 Subject: [PATCH 58/66] output logs to build dir --- ibm-mq-metrics/src/integrationTest/resources/log4j2.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ibm-mq-metrics/src/integrationTest/resources/log4j2.xml b/ibm-mq-metrics/src/integrationTest/resources/log4j2.xml index f1508b386..502eb571b 100644 --- a/ibm-mq-metrics/src/integrationTest/resources/log4j2.xml +++ b/ibm-mq-metrics/src/integrationTest/resources/log4j2.xml @@ -8,7 +8,7 @@ - + From 987cabc9fe53c18d32588104f0956e408c06ab79 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 24 Jul 2025 14:41:29 -0700 Subject: [PATCH 59/66] remove commented code --- .../src/main/java/io/opentelemetry/ibm/mq/WmqMonitor.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqMonitor.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqMonitor.java index 3db13d63c..7eaa2d8c0 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqMonitor.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/WmqMonitor.java @@ -197,8 +197,6 @@ private static void cleanUp( try { name = ibmQueueManager.getName(); ibmQueueManager.disconnect(); - // logger.debug("Connection disconnected for queue manager {} in thread {}", - // ibmQueueManager.getName(), Thread.currentThread().getName()); } catch (Exception e) { logger.error( "Error occurred while disconnecting queueManager {} in thread {}", From 675aa23550fcaea885d0b895c7d07878bc56ae52 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 24 Jul 2025 14:44:55 -0700 Subject: [PATCH 60/66] use Class.forName() --- .../main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java index d0963b091..633697f2e 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java @@ -33,7 +33,7 @@ public static void main(String[] args) throws Exception { } try { - Main.class.getClassLoader().loadClass("com.ibm.mq.headers.MQDataException"); + Class.forName("com.ibm.mq.headers.MQDataException"); } catch (ClassNotFoundException e) { System.err.println("IBM MQ jar is missing from classpath."); System.exit(1); From 9b26d3d6e697ec3d453c7d2953fcc88bedc7f088 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 25 Jul 2025 09:15:45 -0700 Subject: [PATCH 61/66] log4j is not used, remove configs. --- ibm-mq-metrics/src/main/resources/log4j2.xml | 59 -------------------- ibm-mq-metrics/src/test/resources/log4j.xml | 20 ------- 2 files changed, 79 deletions(-) delete mode 100644 ibm-mq-metrics/src/main/resources/log4j2.xml delete mode 100644 ibm-mq-metrics/src/test/resources/log4j.xml diff --git a/ibm-mq-metrics/src/main/resources/log4j2.xml b/ibm-mq-metrics/src/main/resources/log4j2.xml deleted file mode 100644 index 049d2af6b..000000000 --- a/ibm-mq-metrics/src/main/resources/log4j2.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n - logs - otel_ibm_mq - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ibm-mq-metrics/src/test/resources/log4j.xml b/ibm-mq-metrics/src/test/resources/log4j.xml deleted file mode 100644 index 233ddcbe9..000000000 --- a/ibm-mq-metrics/src/test/resources/log4j.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - From df72aa4b2334e9f5305c0ce9481a9a35ff34c978 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 25 Jul 2025 09:17:12 -0700 Subject: [PATCH 62/66] log4j is not used, remove configs. --- .../src/integrationTest/resources/log4j2.xml | 29 ------------------- 1 file changed, 29 deletions(-) delete mode 100644 ibm-mq-metrics/src/integrationTest/resources/log4j2.xml diff --git a/ibm-mq-metrics/src/integrationTest/resources/log4j2.xml b/ibm-mq-metrics/src/integrationTest/resources/log4j2.xml deleted file mode 100644 index 502eb571b..000000000 --- a/ibm-mq-metrics/src/integrationTest/resources/log4j2.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 496d650a2c3660c17b8e0400082a5605886fb906 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 25 Jul 2025 09:50:09 -0700 Subject: [PATCH 63/66] remove shutdown hook and simplify meter --- .../java/io/opentelemetry/ibm/mq/opentelemetry/Main.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java index 633697f2e..abd7e69fb 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/opentelemetry/Main.java @@ -6,7 +6,6 @@ package io.opentelemetry.ibm.mq.opentelemetry; import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.api.metrics.MeterProvider; import io.opentelemetry.ibm.mq.WmqMonitor; import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; @@ -77,10 +76,7 @@ public static void run(ConfigWrapper config, ScheduledExecutorService service) { @VisibleForTesting public static void run( ConfigWrapper config, ScheduledExecutorService service, OpenTelemetry otel) { - MeterProvider meterProvider = otel.getMeterProvider(); - - Runtime.getRuntime().addShutdownHook(new Thread(service::shutdown)); - WmqMonitor monitor = new WmqMonitor(config, service, meterProvider.get("websphere/mq")); + WmqMonitor monitor = new WmqMonitor(config, service, otel.getMeter("websphere/mq")); ScheduledFuture unused = service.scheduleAtFixedRate( monitor::run, From 73d069941974a2f8b4fce6009b5cae9c465befa3 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 31 Jul 2025 11:10:43 -0700 Subject: [PATCH 64/66] address code review comments --- ibm-mq-metrics/docs/metrics.md | 12 +++++------ ibm-mq-metrics/model/metrics.yaml | 12 +++++------ .../resources/conf/test-config.yml | 4 ++-- .../resources/conf/test-queuemgr-config.yml | 4 ++-- .../opentelemetry/ibm/mq/metrics/Metrics.java | 8 ++++---- .../ibm/mq/metrics/MetricsConfig.java | 8 ++++---- .../QueueCollectionBuddy.java | 8 ++++---- .../QueueCollectionBuddyTest.java | 8 ++++---- .../src/test/resources/conf/config.yml | 4 ++-- .../templates/registry/java/Metrics.java.j2 | 20 +++++++++++++++++-- .../registry/java/MetricsConfig.java.j2 | 2 +- 11 files changed, 53 insertions(+), 37 deletions(-) diff --git a/ibm-mq-metrics/docs/metrics.md b/ibm-mq-metrics/docs/metrics.md index 52b9165be..63a71e3f2 100644 --- a/ibm-mq-metrics/docs/metrics.md +++ b/ibm-mq-metrics/docs/metrics.md @@ -535,14 +535,14 @@ -## Metric `ibm.mq.onqtime.1` +## Metric `ibm.mq.onqtime.short_period` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.onqtime.1` | Gauge | `microseconds` | Amount of time, in microseconds, that a message spent on the queue, over a short period | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.onqtime.short_period` | Gauge | `microseconds` | Amount of time, in microseconds, that a message spent on the queue, over a short period | ![Development](https://img.shields.io/badge/-development-blue) | -### `ibm.mq.onqtime.1` Attributes +### `ibm.mq.onqtime.short_period` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| @@ -554,14 +554,14 @@ -## Metric `ibm.mq.onqtime.2` +## Metric `ibm.mq.onqtime.long_period` | Name | Instrument Type | Unit (UCUM) | Description | Stability | | -------- | --------------- | ----------- | -------------- | --------- | -| `ibm.mq.onqtime.2` | Gauge | `microseconds` | Amount of time, in microseconds, that a message spent on the queue, over a longer period | ![Development](https://img.shields.io/badge/-development-blue) | +| `ibm.mq.onqtime.long_period` | Gauge | `microseconds` | Amount of time, in microseconds, that a message spent on the queue, over a longer period | ![Development](https://img.shields.io/badge/-development-blue) | -### `ibm.mq.onqtime.2` Attributes +### `ibm.mq.onqtime.long_period` Attributes | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| diff --git a/ibm-mq-metrics/model/metrics.yaml b/ibm-mq-metrics/model/metrics.yaml index 057d72015..cdc20456a 100644 --- a/ibm-mq-metrics/model/metrics.yaml +++ b/ibm-mq-metrics/model/metrics.yaml @@ -225,7 +225,7 @@ groups: requirement_level: required - ref: messaging.destination.name requirement_level: required - - id: ibm.mq..queue.depth.high.event + - id: ibm.mq.queue.depth.high.event type: metric metric_name: ibm.mq.queue.depth.high.event stability: development @@ -237,7 +237,7 @@ groups: requirement_level: required - ref: messaging.destination.name requirement_level: required - - id: ibm.mq..queue.depth.low.event + - id: ibm.mq.queue.depth.low.event type: metric metric_name: ibm.mq.queue.depth.low.event stability: development @@ -419,9 +419,9 @@ groups: requirement_level: required - ref: ibm.mq.queue.type requirement_level: required - - id: ibm.mq.onqtime.1 + - id: ibm.mq.onqtime.short_period type: metric - metric_name: ibm.mq.onqtime.1 + metric_name: ibm.mq.onqtime.short_period stability: development brief: "Amount of time, in microseconds, that a message spent on the queue, over a short period" instrument: gauge @@ -433,9 +433,9 @@ groups: requirement_level: required - ref: ibm.mq.queue.type requirement_level: required - - id: ibm.mq.onqtime.2 + - id: ibm.mq.onqtime.long_period type: metric - metric_name: ibm.mq.onqtime.2 + metric_name: ibm.mq.onqtime.long_period stability: development brief: "Amount of time, in microseconds, that a message spent on the queue, over a longer period" instrument: gauge diff --git a/ibm-mq-metrics/src/integrationTest/resources/conf/test-config.yml b/ibm-mq-metrics/src/integrationTest/resources/conf/test-config.yml index 68e4030d2..0093bc9e7 100644 --- a/ibm-mq-metrics/src/integrationTest/resources/conf/test-config.yml +++ b/ibm-mq-metrics/src/integrationTest/resources/conf/test-config.yml @@ -148,9 +148,9 @@ metrics: enabled: true "ibm.mq.max.queue.depth": # Maximum queue depth enabled: true - "ibm.mq.onqtime.1": # Amount of time, in microseconds, that a message spent on the queue, over a short period + "ibm.mq.onqtime.short_period": # Amount of time, in microseconds, that a message spent on the queue, over a short period enabled: true - "ibm.mq.onqtime.2": # Amount of time, in microseconds, that a message spent on the queue, over a longer period + "ibm.mq.onqtime.long_period": # Amount of time, in microseconds, that a message spent on the queue, over a longer period enabled: true "ibm.mq.message.received.count": # Number of messages received enabled: true diff --git a/ibm-mq-metrics/src/integrationTest/resources/conf/test-queuemgr-config.yml b/ibm-mq-metrics/src/integrationTest/resources/conf/test-queuemgr-config.yml index 500694df1..9d2808906 100644 --- a/ibm-mq-metrics/src/integrationTest/resources/conf/test-queuemgr-config.yml +++ b/ibm-mq-metrics/src/integrationTest/resources/conf/test-queuemgr-config.yml @@ -120,9 +120,9 @@ metrics: enabled: true "ibm.mq.max.queue.depth": # Maximum queue depth enabled: true - "ibm.mq.onqtime.1": # Amount of time, in microseconds, that a message spent on the queue, over a short period + "ibm.mq.onqtime.short_period": # Amount of time, in microseconds, that a message spent on the queue, over a short period enabled: true - "ibm.mq.onqtime.2": # Amount of time, in microseconds, that a message spent on the queue, over a longer period + "ibm.mq.onqtime.long_period": # Amount of time, in microseconds, that a message spent on the queue, over a longer period enabled: true "ibm.mq.message.received.count": # Number of messages received enabled: true 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 f6e65ae9c..c54c9a431 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 @@ -277,9 +277,9 @@ public static LongGauge createIbmMqMaxQueueDepth(Meter meter) { .build(); } - public static LongGauge createIbmMqOnqtime1(Meter meter) { + public static LongGauge createIbmMqOnqtimeShortPeriod(Meter meter) { return meter - .gaugeBuilder("ibm.mq.onqtime.1") + .gaugeBuilder("ibm.mq.onqtime.short_period") .ofLongs() .setUnit("microseconds") .setDescription( @@ -287,9 +287,9 @@ public static LongGauge createIbmMqOnqtime1(Meter meter) { .build(); } - public static LongGauge createIbmMqOnqtime2(Meter meter) { + public static LongGauge createIbmMqOnqtimeLongPeriod(Meter meter) { return meter - .gaugeBuilder("ibm.mq.onqtime.2") + .gaugeBuilder("ibm.mq.onqtime.long_period") .ofLongs() .setUnit("microseconds") .setDescription( 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 e52fc1f7b..c172cd532 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 @@ -135,12 +135,12 @@ public boolean isIbmMqMaxQueueDepthEnabled() { return isEnabled("ibm.mq.max.queue.depth"); } - public boolean isIbmMqOnqtime1Enabled() { - return isEnabled("ibm.mq.onqtime.1"); + public boolean isIbmMqOnqtimeShortPeriodEnabled() { + return isEnabled("ibm.mq.onqtime.short_period"); } - public boolean isIbmMqOnqtime2Enabled() { - return isEnabled("ibm.mq.onqtime.2"); + public boolean isIbmMqOnqtimeLongPeriodEnabled() { + return isEnabled("ibm.mq.onqtime.long_period"); } public boolean isIbmMqMessageReceivedCountEnabled() { diff --git a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java index 1bb7da515..50187adeb 100644 --- a/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java +++ b/ibm-mq-metrics/src/main/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddy.java @@ -135,8 +135,8 @@ private static AllowedGauge createAllowedGauge( MetricsConfig::isIbmMqCurrentMaxQueueFilesizeEnabled, MIBY_TO_BYTES)); - this.onqtimeShort = Metrics.createIbmMqOnqtime1(meter); - this.onqtimeLong = Metrics.createIbmMqOnqtime2(meter); + this.onqtimeShort = Metrics.createIbmMqOnqtimeShortPeriod(meter); + this.onqtimeLong = Metrics.createIbmMqOnqtimeLongPeriod(meter); } /** @@ -300,10 +300,10 @@ private void updateMetrics( } if (pcfParam instanceof MQCFIL) { int[] metricVals = pcfMessage.getIntListParameterValue(constantValue); - if (context.getMetricsConfig().isIbmMqOnqtime1Enabled()) { + if (context.getMetricsConfig().isIbmMqOnqtimeShortPeriodEnabled()) { onqtimeShort.set(metricVals[0], attributes); } - if (context.getMetricsConfig().isIbmMqOnqtime2Enabled()) { + if (context.getMetricsConfig().isIbmMqOnqtimeLongPeriodEnabled()) { onqtimeLong.set(metricVals[1], attributes); } } diff --git a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java index f32192502..bd0c1ef97 100644 --- a/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java +++ b/ibm-mq-metrics/src/test/java/io/opentelemetry/ibm/mq/metricscollector/QueueCollectionBuddyTest.java @@ -74,16 +74,16 @@ void testProcessPcfRequestAndPublishQMetricsForInquireQStatusCmd() throws Except ImmutableMap.of( "ibm.mq.oldest.msg.age", -1L, "ibm.mq.uncommitted.messages", 0L, - "ibm.mq.onqtime.1", -1L, - "ibm.mq.onqtime.2", -1L, + "ibm.mq.onqtime.short_period", -1L, + "ibm.mq.onqtime.long_period", -1L, "ibm.mq.queue.depth", 0L)), "DEV.QUEUE.1", new HashMap<>( ImmutableMap.of( "ibm.mq.oldest.msg.age", -1L, "ibm.mq.uncommitted.messages", 10L, - "ibm.mq.onqtime.1", -1L, - "ibm.mq.onqtime.2", -1L, + "ibm.mq.onqtime.short_period", -1L, + "ibm.mq.onqtime.long_period", -1L, "ibm.mq.queue.depth", 1L)))); for (MetricData metric : otelTesting.getMetrics()) { diff --git a/ibm-mq-metrics/src/test/resources/conf/config.yml b/ibm-mq-metrics/src/test/resources/conf/config.yml index e49bd9978..51a11d53f 100644 --- a/ibm-mq-metrics/src/test/resources/conf/config.yml +++ b/ibm-mq-metrics/src/test/resources/conf/config.yml @@ -160,9 +160,9 @@ metrics: enabled: true "ibm.mq.max.queue.depth": # Maximum queue depth enabled: true - "ibm.mq.onqtime.1": # Amount of time, in microseconds, that a message spent on the queue, over a short period + "ibm.mq.onqtime.short_period": # Amount of time, in microseconds, that a message spent on the queue, over a short period enabled: true - "ibm.mq.onqtime.2": # Amount of time, in microseconds, that a message spent on the queue, over a longer period + "ibm.mq.onqtime.long_period": # Amount of time, in microseconds, that a message spent on the queue, over a longer period enabled: true "ibm.mq.message.received.count": # Number of messages received enabled: true diff --git a/ibm-mq-metrics/templates/registry/java/Metrics.java.j2 b/ibm-mq-metrics/templates/registry/java/Metrics.java.j2 index e47cfab8e..1b0097826 100644 --- a/ibm-mq-metrics/templates/registry/java/Metrics.java.j2 +++ b/ibm-mq-metrics/templates/registry/java/Metrics.java.j2 @@ -17,8 +17,24 @@ public final static Function MIBY_TO_BYTES = x -> x * 1024L * 102 private Metrics(){ } {% for metric in ctx %} - public static {% if metric.instrument == "gauge" %}LongGauge{% elif metric.instrument == "counter" %}LongCounter{% endif %} create{{ metric.metric_name.split('.')|map('capitalize')|join }}(Meter meter) { - return meter.{% if metric.instrument == "gauge" %}gauge{% elif metric.instrument == "counter" %}counter{% endif %}Builder("{{ metric.metric_name }}").{% if metric.instrument == "gauge" %}ofLongs().{% endif %}setUnit("{{ metric.unit }}").setDescription("{{ metric.brief }}").build(); + + {% if metric.instrument == "gauge" %} + public static LongGauge create{{ metric.metric_name.replace("_", ".")|split('.')|map('capitalize')|join }}(Meter meter) { + return meter + .gaugeBuilder("{{ metric.metric_name }}") + .ofLongs() + .setUnit("{{ metric.unit }}") + .setDescription("{{ metric.brief }}") + .build(); + } + {% elif metric.instrument == "counter" %} + public static LongCounter create{{ metric.metric_name.replace("_", ".")|split('.')|map('capitalize')|join }}(Meter meter) { + return meter + .counterBuilder("{{ metric.metric_name }}") + .setUnit("{{ metric.unit }}") + .setDescription("{{ metric.brief }}") + .build(); } + {% endif %} {% endfor %} } diff --git a/ibm-mq-metrics/templates/registry/java/MetricsConfig.java.j2 b/ibm-mq-metrics/templates/registry/java/MetricsConfig.java.j2 index 7c17bbb25..df6fae562 100644 --- a/ibm-mq-metrics/templates/registry/java/MetricsConfig.java.j2 +++ b/ibm-mq-metrics/templates/registry/java/MetricsConfig.java.j2 @@ -18,7 +18,7 @@ public final class MetricsConfig { this.config = config.getMetrics(); } {% for metric in ctx %} - public boolean is{{ metric.metric_name.split('.')|map('capitalize')|join }}Enabled() { + public boolean is{{ metric.metric_name.replace("_", ".")|split('.')|map('capitalize')|join }}Enabled() { return isEnabled("{{ metric.metric_name }}"); } {% endfor %} From 911e44fe13c953d66ed387d2518341aeefe1d6e8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 17:42:18 +0300 Subject: [PATCH 65/66] chore(deps): update dependency gradle to v9 (#2074) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Trask Stalnaker Co-authored-by: Lauri Tulmin (cherry picked from commit 89c1afbb8d6660c4243a51f37e9634c4d3ccc98a) --- disk-buffering/build.gradle.kts | 2 +- gcp-auth-extension/build.gradle.kts | 10 +++------- gradle/wrapper/gradle-wrapper.jar | Bin 43764 -> 45457 bytes gradle/wrapper/gradle-wrapper.properties | 4 ++-- gradlew | 2 +- jmx-metrics/build.gradle.kts | 2 +- jmx-scraper/build.gradle.kts | 2 +- maven-extension/build.gradle.kts | 2 +- settings.gradle.kts | 2 +- 9 files changed, 11 insertions(+), 15 deletions(-) diff --git a/disk-buffering/build.gradle.kts b/disk-buffering/build.gradle.kts index b3a842b1d..8849c67a9 100644 --- a/disk-buffering/build.gradle.kts +++ b/disk-buffering/build.gradle.kts @@ -4,7 +4,7 @@ import ru.vyarus.gradle.plugin.animalsniffer.AnimalSniffer plugins { id("otel.java-conventions") id("otel.publish-conventions") - id("com.github.johnrengelman.shadow") + id("com.gradleup.shadow") id("me.champeau.jmh") version "0.7.3" id("ru.vyarus.animalsniffer") version "2.0.1" id("com.squareup.wire") version "5.3.3" diff --git a/gcp-auth-extension/build.gradle.kts b/gcp-auth-extension/build.gradle.kts index fd95a653f..f81e5e521 100644 --- a/gcp-auth-extension/build.gradle.kts +++ b/gcp-auth-extension/build.gradle.kts @@ -1,8 +1,7 @@ plugins { id("otel.java-conventions") id("otel.publish-conventions") - id("com.github.johnrengelman.shadow") - id("org.springframework.boot") version "2.7.18" + id("com.gradleup.shadow") } description = "OpenTelemetry extension that provides GCP authentication support for OTLP exporters" @@ -14,6 +13,8 @@ val agent: Configuration by configurations.creating { } dependencies { + implementation(platform("org.springframework.boot:spring-boot-dependencies:2.7.18")) + annotationProcessor("com.google.auto.service:auto-service") // We use `compileOnly` dependency because during runtime all necessary classes are provided by // javaagent itself. @@ -88,11 +89,6 @@ tasks { assemble { dependsOn(shadowJar) } - - bootJar { - // disable bootJar in build since it only runs as part of test - enabled = false - } } val builtLibsDir = layout.buildDirectory.dir("libs").get().asFile.absolutePath diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 1b33c55baabb587c669f562ae36f953de2481846..8bdaf60c75ab801e22807dde59e12a8735a34077 100644 GIT binary patch delta 37256 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 delta 35551 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 78cb6e16a..3e781fbad 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=bd71102213493060956ec229d946beee57158dbd89d0e62b91bca0fa2c5f3531 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip +distributionSha256Sum=8fad3d78296ca518113f3d29016617c7f9367dc005f932bd9d93bf45ba46072b +distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 23d15a936..ef07e0162 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/jmx-metrics/build.gradle.kts b/jmx-metrics/build.gradle.kts index 77ff2c243..b254fc1d8 100644 --- a/jmx-metrics/build.gradle.kts +++ b/jmx-metrics/build.gradle.kts @@ -1,7 +1,7 @@ plugins { id("otel.java-conventions") application - id("com.github.johnrengelman.shadow") + id("com.gradleup.shadow") id("otel.groovy-conventions") id("otel.publish-conventions") diff --git a/jmx-scraper/build.gradle.kts b/jmx-scraper/build.gradle.kts index d58fa6490..9ef9a7277 100644 --- a/jmx-scraper/build.gradle.kts +++ b/jmx-scraper/build.gradle.kts @@ -1,6 +1,6 @@ plugins { application - id("com.github.johnrengelman.shadow") + id("com.gradleup.shadow") id("otel.java-conventions") diff --git a/maven-extension/build.gradle.kts b/maven-extension/build.gradle.kts index d14faa992..24f34f02c 100644 --- a/maven-extension/build.gradle.kts +++ b/maven-extension/build.gradle.kts @@ -1,6 +1,6 @@ plugins { id("java") - id("com.github.johnrengelman.shadow") + id("com.gradleup.shadow") id("otel.java-conventions") id("otel.publish-conventions") } diff --git a/settings.gradle.kts b/settings.gradle.kts index 90b8d7c0b..0d354ff51 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,6 +1,6 @@ pluginManagement { plugins { - id("com.github.johnrengelman.shadow") version "8.1.1" + id("com.gradleup.shadow") version "9.0.0-rc3" id("io.github.gradle-nexus.publish-plugin") version "2.0.0" id("com.gradle.develocity") version "4.0.2" } From 0953fe4ebe65883d8690f069f4382d67d4da8b5c Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 14 Aug 2025 11:33:49 -0700 Subject: [PATCH 66/66] use correct shadow after cherry picking gradle pr --- ibm-mq-metrics/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ibm-mq-metrics/build.gradle.kts b/ibm-mq-metrics/build.gradle.kts index 41ea1fa01..00a2c1988 100644 --- a/ibm-mq-metrics/build.gradle.kts +++ b/ibm-mq-metrics/build.gradle.kts @@ -1,6 +1,6 @@ plugins { application - id("com.github.johnrengelman.shadow") + id("com.gradleup.shadow") id("otel.java-conventions") id("otel.publish-conventions") }