Skip to content

Commit 89aa698

Browse files
authored
jmx-metrics: Activemq (#188)
* wip * Added activeMQ update * updated docs * implemented changes recommended by pr review * updated docs to remove curly braces * spotless check * added activemq to list * fixed incorrect link * forced reset * forced reset
1 parent ee25bac commit 89aa698

File tree

9 files changed

+492
-3
lines changed

9 files changed

+492
-3
lines changed

jmx-metrics/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ mutually exclusive with `otel.jmx.groovy.script`. The currently supported target
6969
| `otel.jmx.target.system` |
7070
| ------------------------ |
7171
| [`jvm`](./docs/target-systems/jvm.md) |
72+
| [`activemq`](./docs/target-systems/activemq.md)|
7273
| [`cassandra`](./docs/target-systems/cassandra.md) |
7374
| [`kafka`](./docs/target-systems/kafka.md) |
7475
| [`kafka-consumer`](./docs/target-systems/kafka-consumer.md) |
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# ActiveMQ Metrics
2+
3+
The JMX Metric Gatherer provides built in ActiveMQ metric gathering capabilities.
4+
These metrics are sourced from: https://activemq.apache.org/jmx
5+
6+
### Metrics
7+
8+
* Name: `activemq.consumer.count`
9+
* Description: The number of consumers currently reading from the broker.
10+
* Unit: `consumers`
11+
* Labels: `destination`
12+
* Instrument Type: ObservableLongUpDownCounter
13+
14+
15+
* Name: `activemq.producer.count`
16+
* Description: The number of producers currently attached to the broker.
17+
* Unit: `producers`
18+
* Labels: `destination`
19+
* Instrument Type: ObservableLongUpDownCounter
20+
21+
22+
* Name: `activemq.connectin.count`
23+
* Description: The total number of current connections.
24+
* Unit: `connections`
25+
* Instrument Type: ObservableLongUpDownCounter
26+
27+
28+
* Name: `activemq.memory.usage`
29+
* Description: The percentage of configured memory used.
30+
* Unit: `%`
31+
* Labels: `destination`
32+
* Instrument Type: ObservableDoubleValue
33+
34+
35+
* Name: `activemq.disk.store_usage`
36+
* Description: The percentage of configured disk used for persistent messages.
37+
* Unit: `%`
38+
* Instrument Type: ObservableDoubleValue
39+
40+
41+
* Name: `activemq.disk.temp_usage`
42+
* Description: The percentage of configured disk used for non-persistent messages.
43+
* Unit: `%`
44+
* Instrument Type: ObservableDoubleValue
45+
46+
47+
* Name: `activemq.message.current`
48+
* Description: The current number of messages waiting to be consumed.
49+
* Unit: `messages`
50+
* Labels: `destination`
51+
* Instrument Type: ObservableLongUpDownCounter
52+
53+
54+
* Name: `activemq.message.expired`
55+
* Description: The total number of messages not delivered because they expired.
56+
* Unit: `messages`
57+
* Labels: `destination`
58+
* Instrument Type: ObservableLongCounter
59+
60+
61+
* Name: `activemq.message.enqueued`
62+
* Description: The total number of messages received by the broker.
63+
* Unit: `messages`
64+
* Labels: `destination`
65+
* Instrument Type: ObservableLongCounter
66+
67+
68+
* Name: `activemq.message.dequeued`
69+
* Description: The total number of messages delivered to consumers.
70+
* Unit: `messages`
71+
* Labels: `destination`
72+
* Instrument Type: ObservableLongCounter
73+
74+
75+
* Name: `activemq.message.wait_time.avg`
76+
* Description: The average time a message was held on a destination.
77+
* Unit: `ms`
78+
* Labels: `destination`
79+
* Instrument Type: ObservableDoubleValue
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.contrib.jmxmetrics.target_systems;
7+
8+
import static org.assertj.core.api.Assertions.entry;
9+
10+
import io.opentelemetry.contrib.jmxmetrics.AbstractIntegrationTest;
11+
import java.time.Duration;
12+
import org.junit.jupiter.api.Test;
13+
import org.testcontainers.containers.GenericContainer;
14+
import org.testcontainers.containers.Network;
15+
import org.testcontainers.containers.wait.strategy.Wait;
16+
import org.testcontainers.images.builder.ImageFromDockerfile;
17+
import org.testcontainers.junit.jupiter.Container;
18+
19+
class ActivemqIntegrationTest extends AbstractIntegrationTest {
20+
21+
ActivemqIntegrationTest() {
22+
super(/* configFromStdin= */ false, "target-systems/activemq.properties");
23+
}
24+
25+
@Container
26+
GenericContainer<?> activemq =
27+
new GenericContainer<>(
28+
new ImageFromDockerfile()
29+
.withFileFromClasspath("config/env", "activemq/config/env")
30+
.withFileFromClasspath("Dockerfile", "activemq/Dockerfile"))
31+
.withNetwork(Network.SHARED)
32+
.withEnv("LOCAL_JMX", "no")
33+
.withNetworkAliases("activemq")
34+
.withExposedPorts(10991)
35+
.withStartupTimeout(Duration.ofMinutes(2))
36+
.waitingFor(Wait.forListeningPort());
37+
38+
@Test
39+
void endToEnd() {
40+
waitAndAssertMetrics(
41+
metric ->
42+
assertSumWithAttributes(
43+
metric,
44+
"activemq.consumer.count",
45+
"The number of consumers currently reading from the broker.",
46+
"consumers",
47+
attrs ->
48+
attrs.containsOnly(
49+
entry("destination", "ActiveMQ.Advisory.MasterBroker"),
50+
entry("broker", "localhost"))),
51+
metric ->
52+
assertSumWithAttributes(
53+
metric,
54+
"activemq.producer.count",
55+
"The number of producers currently attached to the broker.",
56+
"producers",
57+
attrs ->
58+
attrs.containsOnly(
59+
entry("destination", "ActiveMQ.Advisory.MasterBroker"),
60+
entry("broker", "localhost"))),
61+
metric ->
62+
assertSum(
63+
metric,
64+
"activemq.connection.count",
65+
"The total number of current connections.",
66+
"connections",
67+
/* isMonotonic= */ false),
68+
metric ->
69+
assertGaugeWithAttributes(
70+
metric,
71+
"activemq.memory.usage",
72+
"The percentage of configured memory used.",
73+
"%",
74+
attrs ->
75+
attrs.containsOnly(
76+
entry("destination", "ActiveMQ.Advisory.MasterBroker"),
77+
entry("broker", "localhost"))),
78+
metric ->
79+
assertGauge(
80+
metric,
81+
"activemq.disk.store_usage",
82+
"The percentage of configured disk used for persistent messages.",
83+
"%"),
84+
metric ->
85+
assertGauge(
86+
metric,
87+
"activemq.disk.temp_usage",
88+
"The percentage of configured disk used for non-persistent messages.",
89+
"%"),
90+
metric ->
91+
assertSumWithAttributes(
92+
metric,
93+
"activemq.message.current",
94+
"The current number of messages waiting to be consumed.",
95+
"messages",
96+
attrs ->
97+
attrs.containsOnly(
98+
entry("destination", "ActiveMQ.Advisory.MasterBroker"),
99+
entry("broker", "localhost"))),
100+
metric ->
101+
assertSumWithAttributes(
102+
metric,
103+
"activemq.message.current",
104+
"The current number of messages waiting to be consumed.",
105+
"messages",
106+
attrs ->
107+
attrs.containsOnly(
108+
entry("destination", "ActiveMQ.Advisory.MasterBroker"),
109+
entry("broker", "localhost"))),
110+
metric ->
111+
assertSumWithAttributes(
112+
metric,
113+
"activemq.message.expired",
114+
"The total number of messages not delivered because they expired.",
115+
"messages",
116+
attrs ->
117+
attrs.containsOnly(
118+
entry("destination", "ActiveMQ.Advisory.MasterBroker"),
119+
entry("broker", "localhost"))),
120+
metric ->
121+
assertSumWithAttributes(
122+
metric,
123+
"activemq.message.enqueued",
124+
"The total number of messages received by the broker.",
125+
"messages",
126+
attrs ->
127+
attrs.containsOnly(
128+
entry("destination", "ActiveMQ.Advisory.MasterBroker"),
129+
entry("broker", "localhost"))),
130+
metric ->
131+
assertSumWithAttributes(
132+
metric,
133+
"activemq.message.dequeued",
134+
"The total number of messages delivered to consumers.",
135+
"messages",
136+
attrs ->
137+
attrs.containsOnly(
138+
entry("destination", "ActiveMQ.Advisory.MasterBroker"),
139+
entry("broker", "localhost"))),
140+
metric ->
141+
assertGaugeWithAttributes(
142+
metric,
143+
"activemq.message.wait_time.avg",
144+
"The average time a message was held on a destination.",
145+
"ms",
146+
attrs ->
147+
attrs.containsOnly(
148+
entry("destination", "ActiveMQ.Advisory.MasterBroker"),
149+
entry("broker", "localhost"))));
150+
}
151+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
FROM rmohr/activemq:5.15.9-alpine
2+
3+
4+
COPY --chown=activemq config/env /opt/activemq/bin/env
5+
ENV ACTIVEMQ_JMX=10991
6+
EXPOSE $ACTIVEMQ_JMX
7+
8+
ENV ACTIVEMQ_JMX_OPTS="-Dcom.sun.management.jmxremote.port=10991 -Dcom.sun.management.jmxremote.rmi.port=10991 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#!/bin/sh
2+
# ------------------------------------------------------------------------
3+
# Licensed to the Apache Software Foundation (ASF) under one or more
4+
# contributor license agreements. See the NOTICE file distributed with
5+
# this work for additional information regarding copyright ownership.
6+
# The ASF licenses this file to You under the Apache License, Version 2.0
7+
# (the "License"); you may not use this file except in compliance with
8+
# the License. You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
# ------------------------------------------------------------------------
18+
#
19+
# Configuration file for running Apache Active MQ as standalone provider.
20+
#
21+
# This file overwrites the predefined settings of the sysv init-script.
22+
# You can also use alternate location for default settings -
23+
# invoke the init-script without a argument an review help section "Configuration of this script"
24+
# /etc/default/activemq <activemq user home>/.activemqrc <activemq installation dir>/bin/env
25+
26+
# Active MQ installation dirs
27+
# ACTIVEMQ_HOME="<Installationdir>/"
28+
# ACTIVEMQ_BASE="$ACTIVEMQ_HOME"
29+
# ACTIVEMQ_CONF="$ACTIVEMQ_BASE/conf"
30+
# ACTIVEMQ_DATA="$ACTIVEMQ_BASE/data"
31+
# ACTIVEMQ_TMP="$ACTIVEMQ_BASE/tmp"
32+
33+
# Set jvm memory configuration (minimal/maximum amount of memory)
34+
ACTIVEMQ_OPTS_MEMORY="-Xms64M -Xmx256M"
35+
36+
if [ -z "$ACTIVEMQ_OPTS" ] ; then
37+
ACTIVEMQ_OPTS="$ACTIVEMQ_OPTS_MEMORY -Djava.util.logging.config.file=logging.properties -Djava.security.auth.login.config=$ACTIVEMQ_CONF/login.config"
38+
fi
39+
40+
if [ -z "$ACTIVEMQ_OUT" ]; then
41+
ACTIVEMQ_OUT="/dev/null"
42+
fi
43+
44+
# Uncomment to enable audit logging
45+
#ACTIVEMQ_OPTS="$ACTIVEMQ_OPTS -Dorg.apache.activemq.audit=true"
46+
47+
# Set jvm jmx configuration
48+
# This enables jmx access over a configured jmx-tcp-port.
49+
# You have to configure the first four settings if you run a ibm jvm, caused by the
50+
# fact that IBM's jvm does not support VirtualMachine.attach(PID).
51+
# JMX access is needed for quering a running activemq instance to gain data or to
52+
# trigger management operations.
53+
#
54+
# Example for ${ACTIVEMQ_CONF}/jmx.access:
55+
# ---
56+
# # The "monitorRole" role has readonly access.
57+
# # The "controlRole" role has readwrite access.
58+
# monitorRole readonly
59+
# controlRole readwrite
60+
# ---
61+
#
62+
# Example for ${ACTIVEMQ_CONF}/jmx.password:
63+
# ---
64+
# # The "monitorRole" role has password "abc123".
65+
# # # The "controlRole" role has password "abcd1234".
66+
# monitorRole abc123
67+
# controlRole abcd1234
68+
# ---
69+
#
70+
# ACTIVEMQ_SUNJMX_START="$ACTIVEMQ_SUNJMX_START -Dcom.sun.management.jmxremote.port=11099 "
71+
# ACTIVEMQ_SUNJMX_START="$ACTIVEMQ_SUNJMX_START -Dcom.sun.management.jmxremote.password.file=${ACTIVEMQ_CONF}/jmx.password"
72+
# ACTIVEMQ_SUNJMX_START="$ACTIVEMQ_SUNJMX_START -Dcom.sun.management.jmxremote.access.file=${ACTIVEMQ_CONF}/jmx.access"
73+
# ACTIVEMQ_SUNJMX_START="$ACTIVEMQ_SUNJMX_START -Dcom.sun.management.jmxremote.ssl=false"
74+
# ACTIVEMQ_SUNJMX_START="$ACTIVEMQ_SUNJMX_START -Dcom.sun.management.jmxremote"
75+
ACTIVEMQ_SUNJMX_START="$ACTIVEMQ_SUNJMX_START -Dcom.sun.management.jmxremote"
76+
77+
# Set jvm jmx configuration for controlling the broker process
78+
# You only have to configure the first four settings if you run a ibm jvm, caused by the
79+
# fact that IBM's jvm does not support VirtualMachine.attach(PID)
80+
# (see also com.sun.management.jmxremote.port, .jmx.password.file and .jmx.access.file )
81+
#ACTIVEMQ_SUNJMX_CONTROL="--jmxurl service:jmx:rmi:///jndi/rmi://127.0.0.1:1099/jmxrmi --jmxuser controlRole --jmxpassword abcd1234"
82+
ACTIVEMQ_SUNJMX_CONTROL=""
83+
84+
# Specify the queue manager URL for using "browse" option of sysv initscript
85+
if [ -z "$ACTIVEMQ_QUEUEMANAGERURL" ]; then
86+
ACTIVEMQ_QUEUEMANAGERURL="--amqurl tcp://localhost:61616"
87+
fi
88+
89+
# Set additional JSE arguments
90+
if [ -z "$ACTIVEMQ_SSL_OPTS" ] ; then
91+
#ACTIVEMQ_SSL_OPTS="-Djava.security.properties=$ACTIVEMQ_CONF/java.security"
92+
ACTIVEMQ_SSL_OPTS=""
93+
fi
94+
95+
# Uncomment to enable remote debugging
96+
#ACTIVEMQ_DEBUG_OPTS="-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"
97+
98+
# ActiveMQ tries to shutdown the broker by jmx,
99+
# after a specified number of seconds send SIGKILL
100+
if [ -z "$ACTIVEMQ_KILL_MAXSECONDS" ]; then
101+
ACTIVEMQ_KILL_MAXSECONDS=30
102+
fi
103+
104+
# Configure a user with non root privileges, if no user is specified do not change user
105+
# (the entire activemq installation should be owned by this user)
106+
ACTIVEMQ_USER=""
107+
108+
# location of the pidfile
109+
# ACTIVEMQ_PIDFILE="$ACTIVEMQ_DATA/activemq.pid"
110+
111+
# Location of the java installation
112+
# Specify the location of your java installation using JAVA_HOME, or specify the
113+
# path to the "java" binary using JAVACMD
114+
# (set JAVACMD to "auto" for automatic detection)
115+
#JAVA_HOME=""
116+
JAVACMD="auto"
117+
ACTIVEMQ_OPTS="$ACTIVEMQ_OPTS $ACTIVEMQ_JMX_OPTS -Dhawtio.authenticationEnabled=false -Dhawtio.realm=activemq -Dhawtio.role=admins -Dhawtio.rolePrincipalClasses=org.apache.activemq.jaas.GroupPrincipal"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
otel.jmx.interval.milliseconds = 3000
2+
otel.metrics.exporter = otlp
3+
otel.jmx.service.url = service:jmx:rmi:///jndi/rmi://activemq:10991/jmxrmi
4+
otel.jmx.target.system = activemq
5+
6+
# these will be overridden by cmd line
7+
otel.exporter.otlp.endpoint = http://host.testcontainers.internal

jmx-metrics/src/main/groovy/io/opentelemetry/contrib/jmxmetrics/JmxConfig.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ class JmxConfig {
3333
static final String JMX_REALM = PREFIX + "jmx.realm";
3434

3535
static final List<String> AVAILABLE_TARGET_SYSTEMS =
36-
Arrays.asList("cassandra", "jvm", "kafka", "kafka-consumer", "kafka-producer", "tomcat");
36+
Arrays.asList(
37+
"activemq", "cassandra", "jvm", "kafka", "kafka-consumer", "kafka-producer", "tomcat");
3738

3839
final String serviceUrl;
3940
final String groovyScript;

0 commit comments

Comments
 (0)