Apache ActiveMQ Monitoring Tutorial
Apache ActiveMQ (AMQ) is an open source messaging server written in Java which implements JMS 1.1 specifications. In this example, I will explain how to monitor an AMQ server.
Table Of Contents
1. Introduction
Apache ActiveMQ (AMQ) is an open source messaging server written in Java which implements JMS 1.1 specifications. Most of the enterprise applications use AMQ as a building block for their MOM infrastructure, so it’s critical that the AMQ server functions as expected. In this example, I will explain how to monitor an AMQ server from these four aspects:
- Java Virtual Machine (JVM)
- AMQ Web Console
- File System
- Message Broker
2. Monitor ActiveMQ JVM
AMQ is a JVM. Oracle provides free monitoring tools to monitor the JVM’s CPU, Memory and threads.
- Java Mission Control
- jcmd Utility
- Java visualVM
- JConsole Utility
- jmap Utility
- jps Utility
- jstack Utility
- jstat Utility
- jstatd Daemon
- visualgc Utility
- Native Tools
Open Source JVM monitor tools:
3. Monitor ActiveMQ Web Console
AMQ provides a web console (Ex: http://localhost:8161/admin/index.jsp
) to enable users to administrate and monitor the AMQ. The administrator can check any queue which has no consumer or has large amounts of pending messages. AMQ also provides the XML feeds to retrieve the information from the queues. (Ex: http://localhost:8161/admin/xml/queues.jsp
). Users can use a web application monitoring tool to monitor the web console index web page and the XML feed page.
Web application monitoring tools:
- updown
- Pingometer
- Uptime Robot
- Pingdom
- StatusCake
- New Relic
- Monitis
- StatusOK
- Monitority
- Montastic
- AppBeat
- Uptrends
- HostTracker
- Site24x7
- SiteScope
4. Monitor ActiveMQ File System
AMQ uses log4j
to generate three log files under the data
directory with the default settings.
- activemq.log
- audit.log
- wrapper.log
The log file’s information and location can be changed by following these instructions. These log files grow as time goes by. Users can use a file system monitoring tool to monitor the disk space.
File system monitoring tools:
- Watch 4 Folder
- Directory Monitor
- TheFolderSpy
- Track Folder Changes
- FolderChangesView
- Windows Explorer Tracker
- Spy-The-Spy
- SpyMe Tools
- Disk Pulse
- File Alert Monitor
5. Monitor ActiveMQ Application
AMQ is a message broker which transfers the message from the sender to the receiver. Users monitor the AMQ broker to ensure that the messaging broker is in a healthy state.
AMQ broker monitoring tools:
- AMQ JMX MBeans
- AMQ Advisory Message
- Visualisation
- Statistics
- jmxtrans
- ActiveMQ Monitor (AMon)
- Apache ActiveMQBrowser
- HermesJMS
- HermesJMS/soapUI
- Hyperic HQ and Hyperic HQ Enterprise
- FuseHQ (based on Hyperic HQ Enterprise)
- iTKO LISA Test
- Geronimo Administration Console (JMS Resources)
- Media Driver Integrated Console
- Hawt
- Jolokia
6. Java Example
In this example, I will demonstrate how to build a simple Java scheduler application which monitors AMQ queues and then sends notifications when it detects a queue with no consumers or a large amount of pending messages.
6.1 Technologies used
The example code in this article was built and run using:
- Java 1.8.101 (1.8.x will do fine)
- Maven 3.3.9 (3.3.x will do fine)
- Quartz 2.2.1 (2.x will do fine)
- Eclipse Neon (Any Java IDE would work)
6.2 Data Model
AMQ provides a XML feeds to retrieve the information from the queues.
http://localhost:8161/admin/xml/queues.jsp
<queues> <queue name="test.queue"> <stats size="0" consumerCount="0" enqueueCount="0" dequeueCount="0" /> <feed> <atom>queueBrowse/test.queue?view=rss&feedType=atom_1.0</atom> <rss>queueBrowse/test.queue?view=rss&feedType=rss_2.0</rss> </feed> </queue> </queues>
I create a ListOfActiveMqQueue
to map to the root of the XML element queues
.
ListOfActiveMqQueue.java
package jcg.demo.model; import java.util.List; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name = "queues") public class ListOfActiveMqQueue { private List queue; public List getQueue() { return queue; } public void setQueue(List queue) { this.queue = queue; } }
I create a ActiveMqQueue
to map to the child element queue
.
ActiveMqQueue.java
package jcg.demo.model; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name="queue") @XmlAccessorType(XmlAccessType.FIELD) public class ActiveMqQueue { @XmlAttribute private String name; private Stats stats; public String getName() { return name; } public Stats getStats() { return stats; } public void setName(String name) { this.name = name; } public void setStats(Stats stats) { this.stats = stats; } }
I create a Stats
to map to the child element stats
.
Stats.java
package jcg.demo.model; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Stats { @XmlAttribute private Integer size; @XmlAttribute private int consumerCount; @XmlAttribute private int enqueueCount; @XmlAttribute private int dequeueCount; public Integer getSize() { return size; } public int getConsumerCount() { return consumerCount; } public int getEnqueueCount() { return enqueueCount; } public int getDequeueCount() { return dequeueCount; } public void setSize(Integer size) { this.size = size; } public void setConsumerCount(int consumerCount) { this.consumerCount = consumerCount; } public void setEnqueueCount(int enqueueCount) { this.enqueueCount = enqueueCount; } public void setDequeueCount(int dequeueCount) { this.dequeueCount = dequeueCount; } }
6.3 Monitor Service
Create a monitor service which monitors the given AMQ server’s queues and invokes the NotificationService
to send an email when it detects that the queue has no consumers or there is a queue with too many pending messages.
ActiveMQMonitorService.java
package jcg.demo.service; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import jcg.demo.model.ActiveMqQueue; import jcg.demo.model.NotificationEmail; import jcg.demo.model.ListOfActiveMqQueue; public class ActiveMQMonitorService { private ActiveMqQueueTransformer transformer = new ActiveMqQueueTransformer(); private NotificationService notService = new NotificationService(); @SuppressWarnings("resource") public void monitorAndNotify(String brokerUrl, String username, String password, int maxPendingMessageLimit) { System.out.println("monitorAndNotify starts for " + brokerUrl); NotificationEmail email = dummyEmail(); InputStream xmlFeedData = readXmlFeeds(brokerUrl, username, password); ListOfActiveMqQueue activeMqXmlData = transformer.convertFromInputStream(xmlFeedData); if (activeMqXmlData != null) { for (ActiveMqQueue queue : activeMqXmlData.getQueue()) { if (queue.getStats().getConsumerCount() == 0) { email.setSubject("Must check activeMQ, queue: " + queue.getName() + " has no consumer."); notService.sendEmail(email); } else{ int pendingMessageCounts = queue.getStats().getSize() - queue.getStats().getEnqueueCount(); if( pendingMessageCounts > maxPendingMessageLimit){ email.setSubject("Must check activeMQ, queue: " + queue.getName() + " has large pending message. "); notService.sendEmail(email); } } } } System.out.println("monitorAndNotify completes for " + brokerUrl); } private InputStream readXmlFeeds(String brokerUrl, String username, String password) { try { URL url = new URL(brokerUrl); URLConnection uc = url.openConnection(); String userpass = username + ":" + password; String basicAuth = "Basic " + javax.xml.bind.DatatypeConverter.printBase64Binary(userpass.getBytes()); uc.setRequestProperty("Authorization", basicAuth); return uc.getInputStream(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } private NotificationEmail dummyEmail() { NotificationEmail noConsumerEmail = new NotificationEmail(); noConsumerEmail.setFromAddress("monitorApp@noreply.com"); noConsumerEmail.setToAddress("activeMQServerMonitorTeam@test.com"); noConsumerEmail.setBody("test email body message"); return noConsumerEmail; } }
- Line 22: Read the AMQ queue data
- Line 24: Transform the AMQ queue data from
InputStream
toListOfActiveMqQueue
- Line 27: Send notification when detects the queue has no consumer
- Line 33: Send notification when detects the queue has large pending messages
6.4 Quartz Job
Create a Quartz job to monitor the AMQ server.
QuartzJob.java
package jcg.demo.scheduler.quartz2; import java.time.LocalDateTime; import java.util.List; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import jcg.demo.model.NotificationEmail; import jcg.demo.service.ActiveMQMonitorService; import jcg.demo.service.NotificationService; /** * This class implements Quartz Job interface, anything you wish to be executed * by the Quartz Scheduler should be here it should invokes business class to * perform task. * * @author Mary.Zheng * */ public class QuartzJob implements Job { private static final String LOGIN = "admin"; private static final int MAX_PENDING_MESSAGE_SIZE_LIMIT = 10; private String brokerXmlUrl = "http://localhost:8161/admin/xml/queues.jsp"; private ActiveMQMonitorService activeMqMonitorService = new ActiveMQMonitorService(); @Override public void execute(JobExecutionContext context) throws JobExecutionException { LocalDateTime localTime = LocalDateTime.now(); System.out.println(Thread.currentThread().getName() + ": Run QuartzJob at " + localTime.toString()); activeMqMonitorService.monitorAndNotify(brokerXmlUrl, LOGIN, LOGIN, MAX_PENDING_MESSAGE_SIZE_LIMIT); } }
6.5 Monitor Application
Create a monitor application which runs every minutes to monitor the given AMQ server’s queues and sends notifications when it detects that the queue has no consumers or there is a queue with too many pending messages.
QuartzSchedulerApp.java
package jcg.demo.scheduler.quartz2; import java.util.List; import org.quartz.CronScheduleBuilder; import org.quartz.JobBuilder; import org.quartz.JobDetail; import org.quartz.JobExecutionContext; import org.quartz.Scheduler; import org.quartz.Trigger; import org.quartz.TriggerBuilder; import org.quartz.impl.StdSchedulerFactory; /** * This application schedule a job to run every minute * * @author Mary.Zheng * */ public class QuartzSchedulerApp { private static final String TRIGGER_NAME = "MyTriggerName"; private static final String GROUP = "simple_Group"; private static final String JOB_NAME = "someJob"; private static Scheduler scheduler; public static void main(String[] args) throws Exception { System.out.println("QuartzSchedulerApp main thread: " + Thread.currentThread().getName()); scheduler = new StdSchedulerFactory().getScheduler(); scheduler.start(); List currentJobs = scheduler.getCurrentlyExecutingJobs(); for (JobExecutionContext currJob : currentJobs) { System.out.println("running job" + currJob.toString() + currJob.getJobDetail()); } Trigger trigger = buildCronSchedulerTrigger(); scheduleJob(trigger); } private static void scheduleJob(Trigger trigger) throws Exception { JobDetail someJobDetail = JobBuilder.newJob(QuartzJob.class).withIdentity(JOB_NAME, GROUP).build(); scheduler.scheduleJob(someJobDetail, trigger); } private static Trigger buildCronSchedulerTrigger() { String CRON_EXPRESSION = "0 * * * * ?"; Trigger trigger = TriggerBuilder.newTrigger().withIdentity(TRIGGER_NAME, GROUP) .withSchedule(CronScheduleBuilder.cronSchedule(CRON_EXPRESSION)).build(); return trigger; } }
6.6 Monitor Application execution
Start the AMQ server locally ad then execute the monitor application.
Output
QuartzSchedulerApp main thread: main SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. DefaultQuartzScheduler_Worker-1: Run QuartzJob at 2017-12-28T14:15:00.058 monitorAndNotify starts for http://localhost:8161/admin/xml/queues.jsp NotificationService send email EmailNotification [ toAddress=activeMQServerMonitorTeam@test.com, subject=Must check activeMQ, queue: test.queue has no consumer., body=test email body message] monitorAndNotify completes for http://localhost:8161/admin/xml/queues.jsp DefaultQuartzScheduler_Worker-2: Run QuartzJob at 2017-12-28T14:16:00.002 monitorAndNotify starts for http://localhost:8161/admin/xml/queues.jsp NotificationService send email EmailNotification [ toAddress=activeMQServerMonitorTeam@test.com, subject=Must check activeMQ, queue: test.queue has no consumer., body=test email body message] monitorAndNotify completes for http://localhost:8161/admin/xml/queues.jsp
7. Summary
In this example, I outlined how to monitor an AMQ server from four aspects: JVM, AMQ web console, the data file system, and the message broker. I also built a simple Java monitor application to monitor the AMQ based on the web console. There are lots of monitoring tools in the market. Use your best judgement to pick the best monitoring tool for your business. Here are few items to consider when choosing a monitoring tool:
- any security concern?
- any impact to the AMQ server?
- any interface to your notification tool?
8. References
- https://helpx.adobe.com/experience-manager/6-3/assets/using/assets-monitoring-best-practices.html
- http://www.jvmmonitor.org/doc/
- https://examples.javacodegeeks.com/enterprise-java/jms/apache-activemq-advisory-example/
- https://docs.oracle.com/javase/tutorial/jmx/overview/javavm.html
- https://docs.appdynamics.com/display/PRO41/Monitor+JVMs
- https://www.manageengine.com/products/applications_manager/file-monitor.html
- http://www.consulting-notes.com/2010/08/monitoring-and-managing-activemq-with.html
- https://help.talend.com/reader/SUzvVjxkFWs4p6BXVXwyHQ/7ibzi_Da4WqFWdxQZIrMhg
- http://activemq.2283324.n4.nabble.com/Your-favorite-AMQ-monitoring-tool-td3163580.html
- http://activemq.apache.org/audit-logging.html
- http://activemq.apache.org/jmx.html
- http://activemq.apache.org/how-do-i-change-the-logging.html
- http://activemq.apache.org/how-can-i-monitor-activemq.html
9. Download the Source Code
This example consists of a Quartz scheduler to monitor an AMQ server based on the web console queue data.
You can download the full source code of this example here: Apache ActiveMQ Monitoring Tutorial