ActiveMQ exposes all its internal state through JMX (Java Management Extensions). There are three distinct levels of metrics: broker, destination, and JVM. Each level surfaces a different class of failure, and missing any one of them leaves a blind spot. This guide covers what each metric means, what a bad value looks like in production, and how to expose the full set to Prometheus for continuous monitoring and alerting.
One important distinction up front: Apache ActiveMQ (Classic, current stable release 6.2.5) has no native Prometheus endpoint and requires the JMX Prometheus Exporter agent. Apache Artemis (formerly ActiveMQ Artemis, now an independent Apache Top-Level Project since December 2025, at artemis.apache.org) includes a native Prometheus plugin and requires no external agent. The metrics themselves are similar, but the names and setup differ. This guide covers both.
Key Takeaways
- Apache ActiveMQ (Classic) has no native Prometheus endpoint. Use the JMX Prometheus Exporter agent (latest: v1.3.0, released May 2025), which runs inside the broker JVM and serves metrics on a configurable port at /metrics
- Apache Artemis has a built-in Prometheus plugin via Micrometer. Enable it with one block in broker.xml. No external agent is needed. Metrics are served at port 8161 under /metrics
- Metrics live at three levels: broker (JVM process health), destination (queue/topic throughput and backlog), and JVM (heap, GC, threads). All three levels need monitoring. Broker and JVM metrics affect every queue simultaneously
- The five must-alert metrics are: QueueSize growth rate, MemoryPercentUsage (alert before 70%), StorePercentUsage (alert before 85%), ConsumerCount equal to zero, and AverageEnqueueTime rate of change
- AverageEnqueueTime is the leading indicator of downstream slowdowns. It rises before the queue depth becomes critical
- JVM heap exhaustion and full GC pauses manifest as message processing stalls before any broker-level alert fires. JVM metrics are not optional
How ActiveMQ Exposes Metrics
Apache ActiveMQ (Classic): JMX Exporter Agent
Apache ActiveMQ Classic requires the JMX Prometheus Exporter (v1.3.0 as of May 2025) running as a Java agent inside the broker JVM. The agent reads JMX MBeans and serves them at an HTTP endpoint that Prometheus scrapes.
Download the agent JAR:
wget https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/1.3.0/jmx_prometheus_javaagent-1.3.0.jarAdd the agent to ActiveMQ’s startup configuration. Edit <activemq-install>/bin/env and append to ACTIVEMQ_OPTS:
ACTIVEMQ_OPTS="$ACTIVEMQ_OPTS -javaagent:/opt/activemq/jmx_prometheus_javaagent-1.3.0.jar=9404:/opt/activemq/activemq-config.yml"Create activemq-config.yml to map ActiveMQ JMX MBeans to Prometheus metrics:
lowercaseOutputName: true
lowercaseOutputLabelNames: true
rules:
# Broker-level metrics
- pattern: "org.apache.activemq<type=Broker, brokerName=(.+)><>(.+)"
name: activemq_broker_$2
labels:
broker: "$1"
attrNameSnakeCase: true
# Per-destination metrics (queues and topics)
- pattern: "org.apache.activemq<type=Broker, brokerName=(.+), destinationType=Queue, destinationName=(.+)><>(.+)"
name: activemq_queue_$3
labels:
broker: "$1"
destination: "$2"
attrNameSnakeCase: true
- pattern: "org.apache.activemq<type=Broker, brokerName=(.+), destinationType=Topic, destinationName=(.+)><>(.+)"
name: activemq_topic_$3
labels:
broker: "$1"
destination: "$2"
attrNameSnakeCase: trueRestart ActiveMQ and verify the endpoint is responding:
curl http://localhost:9404/metrics | grep activemqApache Artemis: Native Prometheus Plugin
Apache Artemis ships with a native Micrometer-based metrics plugin. Enable it by adding the following to <artemis-instance>/etc/broker.xml inside the <core> block:
<metrics>
<jvm-memory>true</jvm-memory>
<jvm-gc>true</jvm-gc>
<jvm-threads>true</jvm-threads>
<plugin class-name="org.apache.activemq.artemis.core.server.metrics.plugins.ArtemisPrometheusMetricsPlugin"/>
</metrics>Restart the broker. Metrics are served at http://localhost:8161/metrics by default. The exact path depends on the metrics.war deployment configured in bootstrap.xml, which is present by default in standard Artemis installations. Verify:
curl http://localhost:8161/metrics | grep artemisNo Java agent or external process is required.
Configure Prometheus to Scrape ActiveMQ
Classic (JMX Exporter on port 9404)
scrape_configs:
- job_name: activemq-classic
scrape_interval: 30s
scrape_timeout: 25s
static_configs:
- targets:
- activemq-host1:9404
- activemq-host2:9404
labels:
env: productionA 30-second scrape interval is recommended for high-cardinality deployments with many destinations. Scraping more frequently increases the JMX attribute resolution load on the broker JVM. On small clusters with under 50 destinations, 15 seconds is acceptable.
Artemis (native plugin on port 8161)
scrape_configs:
- job_name: activemq-artemis
scrape_interval: 15s
metrics_path: /metrics
static_configs:
- targets:
- artemis-host1:8161
- artemis-host2:8161
labels:
env: productionThe Key Metrics, What They Mean, and When to Alert
Destination-Level Metrics (Per Queue / Per Topic)
These are the metrics that directly reflect whether your message processing is healthy.
| JMX Attribute (Classic) | Artemis metric | What it measures | Alert threshold |
| QueueSize | artemis_message_count | Messages currently in the queue waiting to be consumed | Alert when growing continuously for 10 or more minutes |
| ConsumerCount | artemis_consumer_count | Number of active consumers on the destination | Critical alert when it drops to zero for 2 or more minutes |
| ProducerCount | artemis_producer_count | Number of active producers on the destination | Alert on unexpected zero depending on your architecture |
| EnqueueCount | artemis_messages_added_total | Total messages published (counter). Use rate() to get per-second rate | Use to calculate publish rate and compare against dequeue rate |
| DequeueCount | artemis_messages_acknowledged_total | Total messages consumed and acknowledged (counter) | Sustained divergence from enqueue rate means a backlog is building |
| ExpiredCount | artemis_messages_expired_total | Messages that expired before being consumed | Any non-zero and rising value on a critical queue warrants investigation |
| InFlightCount | artemis_delivering_count | Messages delivered to consumers but not yet acknowledged | A plateau indicates slow or stuck consumers |
| AverageEnqueueTime | (derived from queue metrics) | Average time a message spent in the queue before delivery | A rising trend is the earliest warning of consumer slowdown |
AverageEnqueueTime deserves special attention. It rises before the queue depth becomes visible. If a downstream service your consumer calls starts slowing down, AverageEnqueueTime will trend upward within minutes while QueueSize may still look normal. Alert on the rate of change, not the absolute value, because the baseline varies by queue.
Broker-Level Metrics
These metrics apply to the entire broker. When they breach thresholds, every queue on that broker is affected.
| JMX Attribute (Classic) | Artemis metric | What it measures | Alert threshold |
| MemoryPercentUsage | (JVM heap metrics) | Percentage of the broker’s memory limit used by undelivered messages | Warning at 70%, critical at 85%. At 100%, producers are blocked via Producer Flow Control |
| StorePercentUsage | artemis_global_page_store_usage | Percentage of the persistent message store used | Warning at 70%, critical at 85%. At 100%, persistent message writes fail |
| TempPercentUsage | (disk metrics) | Percentage of temporary store used by non-persistent messages | Warning at 75% |
| TotalConnectionsCount | artemis_connection_count | Total active connections | Alert on sudden drop (network event) or unexpected spike (connection leak) |
MemoryPercentUsage at 100% causes Producer Flow Control to activate, which blocks all producers until memory is released. This is not a graceful slowdown. It is a hard stop. Alert at 70% to give your team time to respond before PFC triggers.
JVM Metrics
Because ActiveMQ runs inside the JVM, JVM resource exhaustion manifests as broker slowdowns before any ActiveMQ-specific metric fires. JVM metrics are not optional.
| Metric | What it measures | Alert threshold |
| jvm_memory_bytes_used (Classic via JMX exporter) / jvm.memory.used (Artemis via Micrometer) | JVM heap memory in use | Alert when heap used exceeds 80% of jvm_memory_bytes_max |
| jvm_gc_collection_seconds_sum | Cumulative time spent in garbage collection | Alert when GC time rate exceeds 10% of elapsed wall time |
| jvm_threads_current | Current JVM thread count | Alert on sustained unexpected growth (thread leak indicator) |
Full GC pauses freeze the entire JVM, including message dispatch. A broker that appears stuck with no error in application logs is often experiencing long GC pauses. Correlate GC metrics with any sudden plateau in DequeueCount.
Prometheus Alert Rules
groups:
- name: activemq
rules:
# Queue depth growing continuously (Classic)
# Uses deriv() because QueueSize is a gauge, not a counter
- alert: ActiveMQQueueDepthGrowing
expr: deriv(activemq_queue_queue_size[10m]) > 0
for: 10m
labels:
severity: warning
annotations:
summary: "ActiveMQ queue depth is growing"
description: >
Queue {{ $labels.destination }} on broker {{ $labels.broker }}
has been growing for 10 consecutive minutes.
# Zero consumers on a queue (Classic)
- alert: ActiveMQQueueNoConsumers
expr: activemq_queue_consumer_count == 0
for: 2m
labels:
severity: critical
annotations:
summary: "ActiveMQ queue has no consumers"
description: >
Queue {{ $labels.destination }} on broker {{ $labels.broker }}
has zero consumers. Messages are accumulating unprocessed.
# Broker memory pressure (Classic)
- alert: ActiveMQMemoryHigh
expr: activemq_broker_memory_percent_usage > 70
for: 5m
labels:
severity: warning
annotations:
summary: "ActiveMQ broker memory usage is high"
description: >
Broker {{ $labels.broker }} memory is at {{ $value }}%.
Producer Flow Control activates at 100%.
# Persistent store pressure (Classic)
- alert: ActiveMQStoreHigh
expr: activemq_broker_store_percent_usage > 70
for: 5m
labels:
severity: warning
annotations:
summary: "ActiveMQ persistent store usage is high"
description: >
Broker {{ $labels.broker }} store is at {{ $value }}%.
Persistent message writes fail at 100%.
# JVM heap pressure
- alert: ActiveMQJVMHeapHigh
expr: >
jvm_memory_bytes_used{area="heap"} /
jvm_memory_bytes_max{area="heap"} * 100 > 80
for: 5m
labels:
severity: warning
annotations:
summary: "ActiveMQ JVM heap usage above 80%"
description: >
JVM heap on {{ $labels.instance }} is at {{ $value | humanize }}%.
Full GC pauses will halt message processing.For Artemis, replace Classic metric names with their Artemis equivalents (artemis_message_count, artemis_consumer_count, etc.) and adjust label names from destination to address and queue as appropriate for your deployment.
Metric Availability: Classic vs Artemis
| Capability | Apache ActiveMQ (Classic) | Apache Artemis |
| Prometheus exposure method | JMX Exporter agent (external, v1.3.0) | Native plugin via Micrometer (built-in) |
| Metrics endpoint | Configurable port (e.g. 9404) at /metrics | Port 8161 at /metrics (default) |
| Per-destination labels | destination label via JMX config | address and queue labels natively |
| JVM metrics | Included by JMX exporter automatically | Enabled per metric category in broker.xml |
| Unrouted message detection | Not available | artemis_unrouted_message_count fires when messages are published to addresses with no queues |
| DLQ monitoring | Via per-destination metrics on the DLQ name | Via per-queue metrics on the DLQ address |
artemis_unrouted_message_count has no Classic equivalent. A non-zero and rising value means messages are being published to addresses that have no queues, which is a silent failure common after misconfigured deployments or schema changes.
Common Setup Problems
| Problem | Likely cause | Fix |
| No metrics at the JMX exporter endpoint | Agent JAR path in ACTIVEMQ_OPTS is wrong, or ActiveMQ was not restarted | Verify the path, restart ActiveMQ, and check the startup log for javaagent errors |
| Scrape timeout errors in Prometheus | Many destinations causing slow JMX attribute resolution | Increase scrape_timeout to 25s and scrape_interval to 30s. For very large deployments (500+ destinations), filter the YAML config to only the attributes you need |
| activemq_queue_queue_size has no destination label | YAML mapping rules not capturing the destination name | Verify the regex in your JMX exporter config matches the actual MBean object names. Use curl http://localhost:9404/metrics to inspect raw output |
| Artemis metrics missing after enabling the plugin | broker.xml change not saved correctly, or the broker was not fully restarted | Confirm the <metrics> block is inside <core>. Check the Artemis log for plugin initialization errors |
| JVM heap metrics absent | JMX exporter running in standalone HTTP server mode instead of Java agent mode | Run the exporter as a Java agent (-javaagent: flag). JVM metrics are only available when the exporter runs inside the broker JVM |
What Broker Metrics Cannot Tell You
When ActiveMQQueueDepthGrowing or ActiveMQMemoryHigh fires, your metrics show that something is wrong at the broker level. They do not show which consumer application instance is falling behind, which message type is taking the longest to process, or whether the bottleneck is in the consumer’s own code or in a downstream service it calls.
A queue accumulating because of a slow database call inside the consumer looks identical on a broker dashboard to one accumulating because a consumer pod has crashed. The difference matters because the remediation is completely different. One requires fixing or scaling consumer code. The other requires restarting a pod.
CubeAPM instruments your consumer application via OpenTelemetry, regardless of whether your broker is ActiveMQ, Artemis, RabbitMQ, or Kafka, and captures each message processing cycle as a span in the full distributed trace. When a broker alert fires, CubeAPM shows you which consumer instance is slowest, how long each message takes end-to-end, and which downstream service call is responsible. The broker alert tells you something is wrong. CubeAPM tells you what and where. It runs self-hosted inside your own infrastructure at $0.15/GB ingestion pricing, so no data leaves your environment.
Summary
ActiveMQ performance monitoring requires three layers working together: destination-level metrics for queue health, broker-level metrics for resource pressure, and JVM metrics for runtime health. The five metrics that catch most production incidents before they escalate are QueueSize growth rate, MemoryPercentUsage, StorePercentUsage, ConsumerCount equal to zero, and AverageEnqueueTime trend.
Apache ActiveMQ Classic (latest 6.2.5) requires the JMX Prometheus Exporter agent (v1.3.0). Apache Artemis (now an independent Apache TLP since December 2025) has a native plugin requiring one block of XML configuration.
| Metric | Classic JMX attribute | Artemis metric | Alert threshold |
| Queue depth | QueueSize | artemis_message_count | Growing for 10 or more minutes (use deriv()) |
| Consumer count | ConsumerCount | artemis_consumer_count | Zero for 2 or more minutes |
| Enqueue vs dequeue rate | EnqueueCount / DequeueCount | artemis_messages_added_total / artemis_messages_acknowledged_total | Sustained divergence |
| Broker memory | MemoryPercentUsage | JVM heap via Micrometer | Warning at 70%, critical at 85% |
| Persistent store | StorePercentUsage | artemis_global_page_store_usage | Warning at 70%, critical at 85% |
| Average enqueue time | AverageEnqueueTime | (derived from queue metrics) | Rising trend for 5 or more minutes |
| JVM heap | jvm_memory_bytes_used (via agent) | jvm.memory.used (via Micrometer) | Above 80% of max heap |
| Unrouted messages | Not available | artemis_unrouted_message_count | Any non-zero and rising value |
Disclaimer: Metric names, JMX MBean patterns, and alert thresholds are verified against Apache ActiveMQ Classic 6.2.5 documentation (activemq.apache.org), Apache Artemis documentation (artemis.apache.org), and the JMX Prometheus Exporter v1.3.0 release (github.com/prometheus/jmx_exporter) as of May 2026. Apache Artemis became an independent Apache Top-Level Project in December 2025 and is no longer part of the ActiveMQ project.
Also read:
RabbitMQ Alerts: How to Alert on RabbitMQ Queue Depth and Consumer Count





