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        try {
070
071            if (tokens.contains("topics")) {
072                displayTopicStats();
073            } else if (tokens.contains("queues")) {
074                displayQueueStats();
075            } else {
076                displayAllDestinations();
077            }
078
079            // Iterate through the queue names
080        } catch (Exception e) {
081            context.printException(new RuntimeException("Failed to execute dstat task. Reason: " + e.getMessage(), e));
082            throw new Exception(e);
083        }
084    }
085
086    @SuppressWarnings("unchecked")
087    private void displayAllDestinations() throws Exception {
088
089        String query = JmxMBeansUtil.createQueryString(queryString, "*");
090        List queueList = JmxMBeansUtil.queryMBeans(createJmxConnection(), query);
091
092        final String header = "%-50s  %10s  %10s  %10s  %10s  %10s  %10s  %10s";
093        final String tableRow = "%-50s  %10d  %10d  %10d  %10d  %10d  %10d  %10d";
094
095        // sort list so the names is A..Z
096        Collections.sort(queueList, new ObjectInstanceComparator());
097
098        context.print(String.format(Locale.US, header, "Name", "Queue Size", "Producer #", "Consumer #", "Enqueue #", "Dequeue #", "Forward #", "Memory %"));
099
100        // Iterate through the queue result
101        for (Object view : queueList) {
102            ObjectInstance obj = (ObjectInstance) view;
103            if (!filterMBeans(obj)) {
104                continue;
105            }
106            ObjectName queueName = obj.getObjectName();
107
108            QueueViewMBean queueView = MBeanServerInvocationHandler.
109                newProxyInstance(createJmxConnection(), queueName, QueueViewMBean.class, true);
110
111            context.print(String.format(Locale.US, tableRow,
112                    queueView.getName(),
113                    queueView.getQueueSize(),
114                    queueView.getProducerCount(),
115                    queueView.getConsumerCount(),
116                    queueView.getEnqueueCount(),
117                    queueView.getDequeueCount(),
118                    queueView.getForwardCount(),
119                    queueView.getMemoryPercentUsage()));
120        }
121    }
122
123    @SuppressWarnings("unchecked")
124    private void displayQueueStats() throws Exception {
125
126        String query = JmxMBeansUtil.createQueryString(queryString, "Queue");
127        List queueList = JmxMBeansUtil.queryMBeans(createJmxConnection(), query);
128
129        final String header = "%-50s  %10s  %10s  %10s  %10s  %10s  %10s  %10s";
130        final String tableRow = "%-50s  %10d  %10d  %10d  %10d  %10d  %10d  %10d";
131
132        context.print(String.format(Locale.US, header, "Name", "Queue Size", "Producer #", "Consumer #", "Enqueue #", "Dequeue #", "Forward #", "Memory %"));
133
134        Collections.sort(queueList, new ObjectInstanceComparator());
135
136        // Iterate through the queue result
137        for (Object view : queueList) {
138            ObjectInstance obj = (ObjectInstance) view;
139            if (!filterMBeans(obj)) {
140                continue;
141            }
142            ObjectName queueName = obj.getObjectName();
143
144            QueueViewMBean queueView = MBeanServerInvocationHandler.
145                newProxyInstance(createJmxConnection(), queueName, QueueViewMBean.class, true);
146
147            context.print(String.format(Locale.US, tableRow,
148                    queueView.getName(),
149                    queueView.getQueueSize(),
150                    queueView.getProducerCount(),
151                    queueView.getConsumerCount(),
152                    queueView.getEnqueueCount(),
153                    queueView.getDequeueCount(),
154                    queueView.getForwardCount(),
155                    queueView.getMemoryPercentUsage()));
156        }
157    }
158
159    @SuppressWarnings("unchecked")
160    private void displayTopicStats() throws Exception {
161
162        String query = JmxMBeansUtil.createQueryString(queryString, "Topic");
163        List topicsList = JmxMBeansUtil.queryMBeans(createJmxConnection(), query);
164
165        final String header = "%-50s  %10s  %10s  %10s  %10s  %10s  %10s  %10s";
166        final String tableRow = "%-50s  %10d  %10d  %10d  %10d  %10d  %10d  %10d";
167
168        // sort list so the names is A..Z
169        Collections.sort(topicsList, new ObjectInstanceComparator());
170
171        context.print(String.format(Locale.US, header, "Name", "Queue Size", "Producer #", "Consumer #", "Enqueue #", "Dequeue #", "Forward #", "Memory %"));
172
173        // Iterate through the topics result
174        for (Object view : topicsList) {
175            ObjectInstance obj = (ObjectInstance) view;
176            if (!filterMBeans(obj)) {
177                continue;
178            }
179            ObjectName topicName = obj.getObjectName();
180
181            TopicViewMBean topicView = MBeanServerInvocationHandler.
182                newProxyInstance(createJmxConnection(), topicName, TopicViewMBean.class, true);
183
184            context.print(String.format(Locale.US, tableRow,
185                    topicView.getName(),
186                    topicView.getQueueSize(),
187                    topicView.getProducerCount(),
188                    topicView.getConsumerCount(),
189                    topicView.getEnqueueCount(),
190                    topicView.getDequeueCount(),
191                    topicView.getForwardCount(),
192                    topicView.getMemoryPercentUsage()));
193        }
194    }
195
196    @Override
197    public String getName() {
198        return "dstat";
199    }
200
201    @Override
202    public String getOneLineDescription() {
203        return "Performs a predefined query that displays useful tabular statistics regarding the specified destination type";
204    }
205
206    /**
207     * Print the help messages for this command
208     */
209    @Override
210    protected void printHelp() {
211        context.printHelp(helpFile);
212    }
213
214    protected boolean filterMBeans(ObjectInstance obj) {
215        String className = obj.getClassName();
216        return className.equals(QueueView.class.getName()) || className.equals(TopicView.class.getName());
217    }
218
219    private static class ObjectInstanceComparator implements Comparator<ObjectInstance> {
220
221        @Override
222        public int compare(ObjectInstance o1, ObjectInstance o2) {
223            return o1.getObjectName().compareTo(o2.getObjectName());
224        }
225    }
226
227}