001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.activemq.console.command;
018
019import java.util.Collections;
020import java.util.Comparator;
021import java.util.List;
022import java.util.Locale;
023import javax.management.MBeanServerInvocationHandler;
024import javax.management.ObjectInstance;
025import javax.management.ObjectName;
026
027import org.apache.activemq.broker.jmx.QueueView;
028import org.apache.activemq.broker.jmx.QueueViewMBean;
029import org.apache.activemq.broker.jmx.TopicView;
030import org.apache.activemq.broker.jmx.TopicViewMBean;
031import org.apache.activemq.console.util.JmxMBeansUtil;
032
033public class DstatCommand extends AbstractJmxCommand {
034
035    private static final String queryString =
036        "type=Broker,brokerName=*,destinationType=%1,destinationName=*,*";
037
038    protected String[] helpFile = new String[] {
039        "Task Usage: activemq-admin dstat [dstat-options] [destination-type]",
040        "Description: Performs a predefined query that displays useful statistics regarding the specified .",
041        "             destination type (Queues or Topics) and displays those results in a tabular format.",
042        "             If no broker name is specified, it will try and select from all registered brokers.",
043        "",
044        "dstat Options:",
045        "    --jmxurl <url>                Set the JMX URL to connect to.",
046        "    --pid <pid>                   Set the pid to connect to (only on Sun JVM).",
047        "    --jmxuser <user>              Set the JMX user used for authenticating.",
048        "    --jmxpassword <password>      Set the JMX password used for authenticating.",
049        "    --jmxlocal                    Use the local JMX server instead of a remote one.",
050        "    --version                     Display the version information.",
051        "    -h,-?,--help                  Display the query broker help information.",
052        "",
053        "Examples:",
054        "    activemq-admin dstat queues",
055        "        - Display a tabular summary of statistics for the queues on the broker.",
056        "    activemq-admin dstat topics",
057        "        - Display a tabular summary of statistics for the queues on the broker."
058    };
059
060    /**
061     * Execute the dstat command, which allows you to display information for topics or queue in
062     * a tabular format.
063     *
064     * @param tokens - command arguments
065     * @throws Exception
066     */
067    @Override
068    protected void runTask(List<String> tokens) throws Exception {
069        if (tokens.contains("topics")) {
070            displayTopicStats();
071        } else if (tokens.contains("queues")) {
072            displayQueueStats();
073        } else {
074            displayAllDestinations();
075        }
076    }
077
078    @SuppressWarnings("unchecked")
079    private void displayAllDestinations() throws Exception {
080
081        String query = JmxMBeansUtil.createQueryString(queryString, "*");
082        List queueList = JmxMBeansUtil.queryMBeans(createJmxConnection(), query);
083
084        final String header = "%-50s  %10s  %10s  %10s  %10s  %10s  %10s  %10s";
085        final String tableRow = "%-50s  %10d  %10d  %10d  %10d  %10d  %10d  %10d";
086
087        // sort list so the names is A..Z
088        Collections.sort(queueList, new ObjectInstanceComparator());
089
090        context.print(String.format(Locale.US, header, "Name", "Queue Size", "Producer #", "Consumer #", "Enqueue #", "Dequeue #", "Forward #", "Memory %"));
091
092        // Iterate through the queue result
093        for (Object view : queueList) {
094            ObjectInstance obj = (ObjectInstance) view;
095            if (!filterMBeans(obj)) {
096                continue;
097            }
098            ObjectName queueName = obj.getObjectName();
099
100            QueueViewMBean queueView = MBeanServerInvocationHandler.
101                newProxyInstance(createJmxConnection(), queueName, QueueViewMBean.class, true);
102
103            context.print(String.format(Locale.US, tableRow,
104                    queueView.getName(),
105                    queueView.getQueueSize(),
106                    queueView.getProducerCount(),
107                    queueView.getConsumerCount(),
108                    queueView.getEnqueueCount(),
109                    queueView.getDequeueCount(),
110                    queueView.getForwardCount(),
111                    queueView.getMemoryPercentUsage()));
112        }
113    }
114
115    @SuppressWarnings("unchecked")
116    private void displayQueueStats() throws Exception {
117
118        String query = JmxMBeansUtil.createQueryString(queryString, "Queue");
119        List queueList = JmxMBeansUtil.queryMBeans(createJmxConnection(), query);
120
121        final String header = "%-50s  %10s  %10s  %10s  %10s  %10s  %10s  %10s  %10s";
122        final String tableRow = "%-50s  %10d  %10d  %10d  %10d  %10d  %10d  %10d  %10d";
123
124        context.print(String.format(Locale.US, header, "Name", "Queue Size", "Producer #", "Consumer #", "Enqueue #", "Dequeue #", "Forward #", "Memory %", "Inflight #"));
125
126        Collections.sort(queueList, new ObjectInstanceComparator());
127
128        // Iterate through the queue result
129        for (Object view : queueList) {
130            ObjectInstance obj = (ObjectInstance) view;
131            if (!filterMBeans(obj)) {
132                continue;
133            }
134            ObjectName queueName = obj.getObjectName();
135
136            QueueViewMBean queueView = MBeanServerInvocationHandler.
137                newProxyInstance(createJmxConnection(), queueName, QueueViewMBean.class, true);
138
139            context.print(String.format(Locale.US, tableRow,
140                    queueView.getName(),
141                    queueView.getQueueSize(),
142                    queueView.getProducerCount(),
143                    queueView.getConsumerCount(),
144                    queueView.getEnqueueCount(),
145                    queueView.getDequeueCount(),
146                    queueView.getForwardCount(),
147                    queueView.getMemoryPercentUsage(),
148                    queueView.getInFlightCount()));
149        }
150    }
151
152    @SuppressWarnings("unchecked")
153    private void displayTopicStats() throws Exception {
154
155        String query = JmxMBeansUtil.createQueryString(queryString, "Topic");
156        List topicsList = JmxMBeansUtil.queryMBeans(createJmxConnection(), query);
157
158        final String header = "%-50s  %10s  %10s  %10s  %10s  %10s  %10s  %10s";
159        final String tableRow = "%-50s  %10d  %10d  %10d  %10d  %10d  %10d  %10d";
160
161        // sort list so the names is A..Z
162        Collections.sort(topicsList, new ObjectInstanceComparator());
163
164        context.print(String.format(Locale.US, header, "Name", "Queue Size", "Producer #", "Consumer #", "Enqueue #", "Dequeue #", "Forward #", "Memory %"));
165
166        // Iterate through the topics result
167        for (Object view : topicsList) {
168            ObjectInstance obj = (ObjectInstance) view;
169            if (!filterMBeans(obj)) {
170                continue;
171            }
172            ObjectName topicName = obj.getObjectName();
173
174            TopicViewMBean topicView = MBeanServerInvocationHandler.
175                newProxyInstance(createJmxConnection(), topicName, TopicViewMBean.class, true);
176
177            context.print(String.format(Locale.US, tableRow,
178                    topicView.getName(),
179                    topicView.getQueueSize(),
180                    topicView.getProducerCount(),
181                    topicView.getConsumerCount(),
182                    topicView.getEnqueueCount(),
183                    topicView.getDequeueCount(),
184                    topicView.getForwardCount(),
185                    topicView.getMemoryPercentUsage()));
186        }
187    }
188
189    @Override
190    public String getName() {
191        return "dstat";
192    }
193
194    @Override
195    public String getOneLineDescription() {
196        return "Performs a predefined query that displays useful tabular statistics regarding the specified destination type";
197    }
198
199    /**
200     * Print the help messages for this command
201     */
202    @Override
203    protected void printHelp() {
204        context.printHelp(helpFile);
205    }
206
207    protected boolean filterMBeans(ObjectInstance obj) {
208        String className = obj.getClassName();
209        return className.equals(QueueView.class.getName()) || className.equals(TopicView.class.getName());
210    }
211
212    private static class ObjectInstanceComparator implements Comparator<ObjectInstance> {
213
214        @Override
215        public int compare(ObjectInstance o1, ObjectInstance o2) {
216            return o1.getObjectName().compareTo(o2.getObjectName());
217        }
218    }
219
220}