blob: ce3f5d1ef586ef5fc8c4e50ba2061b7ba6b591fd [file]
#!/usr/bin/env python
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
import os
from optparse import OptionParser, OptionGroup
from time import sleep ### debug
import sys
import locale
import socket
import re
from qmf.console import Session, Console
from qpid.disp import Display, Header, Sorter
class Config:
def __init__(self):
self._host = "localhost"
self._connTimeout = 10
self._types = ""
self._limit = 50
self._increasing = False
self._sortcol = None
self._cluster_detail = False
self._sasl_mechanism = None
config = Config()
def OptionsAndArguments(argv):
""" Set global variables for options, return arguments """
global config
parser = OptionParser(usage="usage: %prog [options] BROKER",
description="Example: $ qpid-stat -q broker-host:10000")
group1 = OptionGroup(parser, "General Options")
group1.add_option("-t", "--timeout", action="store", type="int", default=10, metavar="<secs>", help="Maximum time to wait for broker connection (in seconds)")
group1.add_option("--sasl-mechanism", action="store", type="string", metavar="<mech>", help="SASL mechanism for authentication (e.g. EXTERNAL, ANONYMOUS, PLAIN, CRAM-MD, DIGEST-MD5, GSSAPI). SASL automatically picks the most secure available mechanism - use this option to override.")
parser.add_option_group(group1)
group2 = OptionGroup(parser, "Display Options")
group2.add_option("-b", "--broker", help="Show Brokers",
action="store_const", const="b", dest="show")
group2.add_option("-c", "--connections", help="Show Connections",
action="store_const", const="c", dest="show")
group2.add_option("-e", "--exchanges", help="Show Exchanges",
action="store_const", const="e", dest="show")
group2.add_option("-q", "--queues", help="Show Queues",
action="store_const", const="q", dest="show")
group2.add_option("-u", "--subscriptions", help="Show Subscriptions",
action="store_const", const="u", dest="show")
group2.add_option("-S", "--sort-by", metavar="<colname>",
help="Sort by column name")
group2.add_option("-I", "--increasing", action="store_true", default=False,
help="Sort by increasing value (default = decreasing)")
group2.add_option("-L", "--limit", default=50, metavar="<n>",
help="Limit output to n rows")
group2.add_option("-C", "--cluster", action="store_true", default=False,
help="Display per-broker cluster detail.")
parser.add_option_group(group2)
opts, args = parser.parse_args(args=argv)
if not opts.show:
parser.error("You must specify one of these options: -b, -c, -e, -q. or -u. For details, try $ qpid-stat --help")
config._types = opts.show
config._sortcol = opts.sort_by
config._connTimeout = opts.timeout
config._increasing = opts.increasing
config._limit = opts.limit
config._cluster_detail = opts.cluster
config._sasl_mechanism = opts.sasl_mechanism
if args:
config._host = args[0]
return args
class IpAddr:
def __init__(self, text):
if text.find("@") != -1:
tokens = text.split("@")
text = tokens[1]
if text.find(":") != -1:
tokens = text.split(":")
text = tokens[0]
self.port = int(tokens[1])
else:
self.port = 5672
self.dottedQuad = socket.gethostbyname(text)
nums = self.dottedQuad.split(".")
self.addr = (int(nums[0]) << 24) + (int(nums[1]) << 16) + (int(nums[2]) << 8) + int(nums[3])
def bestAddr(self, addrPortList):
bestDiff = 0xFFFFFFFFL
bestAddr = None
for addrPort in addrPortList:
diff = IpAddr(addrPort[0]).addr ^ self.addr
if diff < bestDiff:
bestDiff = diff
bestAddr = addrPort
return bestAddr
class Broker(object):
def __init__(self, qmf, broker):
self.broker = broker
agents = qmf.getAgents()
for a in agents:
if a.getAgentBank() == '0':
self.brokerAgent = a
bobj = qmf.getObjects(_class="broker", _package="org.apache.qpid.broker", _agent=self.brokerAgent)[0]
self.currentTime = bobj.getTimestamps()[0]
try:
self.uptime = bobj.uptime
except:
self.uptime = 0
self.connections = {}
self.sessions = {}
self.exchanges = {}
self.queues = {}
self.subscriptions = {}
package = "org.apache.qpid.broker"
list = qmf.getObjects(_class="connection", _package=package, _agent=self.brokerAgent)
for conn in list:
if not conn.shadow:
self.connections[conn.getObjectId()] = conn
list = qmf.getObjects(_class="session", _package=package, _agent=self.brokerAgent)
for sess in list:
if sess.connectionRef in self.connections:
self.sessions[sess.getObjectId()] = sess
list = qmf.getObjects(_class="exchange", _package=package, _agent=self.brokerAgent)
for exchange in list:
self.exchanges[exchange.getObjectId()] = exchange
list = qmf.getObjects(_class="queue", _package=package, _agent=self.brokerAgent)
for queue in list:
self.queues[queue.getObjectId()] = queue
list = qmf.getObjects(_class="subscription", _package=package, _agent=self.brokerAgent)
for subscription in list:
self.subscriptions[subscription.getObjectId()] = subscription
def getName(self):
return self.broker.getUrl()
def getCurrentTime(self):
return self.currentTime
def getUptime(self):
return self.uptime
class BrokerManager(Console):
def __init__(self):
self.brokerName = None
self.qmf = None
self.broker = None
self.brokers = []
self.cluster = None
def SetBroker(self, brokerUrl, mechanism):
self.url = brokerUrl
self.qmf = Session()
self.mechanism = mechanism
self.broker = self.qmf.addBroker(brokerUrl, config._connTimeout, mechanism)
agents = self.qmf.getAgents()
for a in agents:
if a.getAgentBank() == '0':
self.brokerAgent = a
def Disconnect(self):
""" Release any allocated brokers. Ignore any failures as the tool is
shutting down.
"""
try:
if self.broker:
self.qmf.delBroker(self.broker)
else:
for b in self.brokers: self.qmf.delBroker(b.broker)
except:
pass
def _getCluster(self):
packages = self.qmf.getPackages()
if "org.apache.qpid.cluster" not in packages:
return None
clusters = self.qmf.getObjects(_class="cluster", _agent=self.brokerAgent)
if len(clusters) == 0:
print "Clustering is installed but not enabled on the broker."
return None
self.cluster = clusters[0]
def _getHostList(self, urlList):
hosts = []
hostAddr = IpAddr(config._host)
for url in urlList:
if url.find("amqp:") != 0:
raise Exception("Invalid URL 1")
url = url[5:]
addrs = str(url).split(",")
addrList = []
for addr in addrs:
tokens = addr.split(":")
if len(tokens) != 3:
raise Exception("Invalid URL 2")
addrList.append((tokens[1], tokens[2]))
# Find the address in the list that is most likely to be in the same subnet as the address
# with which we made the original QMF connection. This increases the probability that we will
# be able to reach the cluster member.
best = hostAddr.bestAddr(addrList)
bestUrl = best[0] + ":" + best[1]
hosts.append(bestUrl)
return hosts
def displaySubs(self, subs, indent, broker=None, conn=None, sess=None, exchange=None, queue=None):
if len(subs) == 0:
return
this = subs[0]
remaining = subs[1:]
newindent = indent + " "
if this == 'b':
pass
elif this == 'c':
if broker:
for oid in broker.connections:
iconn = broker.connections[oid]
self.printConnSub(indent, broker.getName(), iconn)
self.displaySubs(remaining, newindent, broker=broker, conn=iconn,
sess=sess, exchange=exchange, queue=queue)
elif this == 's':
pass
elif this == 'e':
pass
elif this == 'q':
pass
print
def displayBroker(self, subs):
disp = Display(prefix=" ")
heads = []
heads.append(Header('broker'))
heads.append(Header('cluster'))
heads.append(Header('uptime', Header.DURATION))
heads.append(Header('conn', Header.KMG))
heads.append(Header('sess', Header.KMG))
heads.append(Header('exch', Header.KMG))
heads.append(Header('queue', Header.KMG))
rows = []
for broker in self.brokers:
if self.cluster:
ctext = "%s(%s)" % (self.cluster.clusterName, self.cluster.status)
else:
ctext = "<standalone>"
row = (broker.getName(), ctext, broker.getUptime(),
len(broker.connections), len(broker.sessions),
len(broker.exchanges), len(broker.queues))
rows.append(row)
title = "Brokers"
if config._sortcol:
sorter = Sorter(heads, rows, config._sortcol, config._limit, config._increasing)
dispRows = sorter.getSorted()
else:
dispRows = rows
disp.formattedTable(title, heads, dispRows)
def displayConn(self, subs):
disp = Display(prefix=" ")
heads = []
if self.cluster:
heads.append(Header('broker'))
heads.append(Header('client-addr'))
heads.append(Header('cproc'))
heads.append(Header('cpid'))
heads.append(Header('auth'))
heads.append(Header('connected', Header.DURATION))
heads.append(Header('idle', Header.DURATION))
heads.append(Header('msgIn', Header.KMG))
heads.append(Header('msgOut', Header.KMG))
rows = []
for broker in self.brokers:
for oid in broker.connections:
conn = broker.connections[oid]
row = []
if self.cluster:
row.append(broker.getName())
row.append(conn.address)
row.append(conn.remoteProcessName)
row.append(conn.remotePid)
row.append(conn.authIdentity)
row.append(broker.getCurrentTime() - conn.getTimestamps()[1])
idle = broker.getCurrentTime() - conn.getTimestamps()[0]
row.append(broker.getCurrentTime() - conn.getTimestamps()[0])
row.append(conn.framesFromClient)
row.append(conn.framesToClient)
rows.append(row)
title = "Connections"
if self.cluster:
title += " for cluster '%s'" % self.cluster.clusterName
if config._sortcol:
sorter = Sorter(heads, rows, config._sortcol, config._limit, config._increasing)
dispRows = sorter.getSorted()
else:
dispRows = rows
disp.formattedTable(title, heads, dispRows)
def displaySession(self, subs):
disp = Display(prefix=" ")
def displayExchange(self, subs):
disp = Display(prefix=" ")
heads = []
if self.cluster:
heads.append(Header('broker'))
heads.append(Header("exchange"))
heads.append(Header("type"))
heads.append(Header("dur", Header.Y))
heads.append(Header("bind", Header.KMG))
heads.append(Header("msgIn", Header.KMG))
heads.append(Header("msgOut", Header.KMG))
heads.append(Header("msgDrop", Header.KMG))
heads.append(Header("byteIn", Header.KMG))
heads.append(Header("byteOut", Header.KMG))
heads.append(Header("byteDrop", Header.KMG))
rows = []
for broker in self.brokers:
for oid in broker.exchanges:
ex = broker.exchanges[oid]
row = []
if self.cluster:
row.append(broker.getName())
row.append(ex.name)
row.append(ex.type)
row.append(ex.durable)
row.append(ex.bindingCount)
row.append(ex.msgReceives)
row.append(ex.msgRoutes)
row.append(ex.msgDrops)
row.append(ex.byteReceives)
row.append(ex.byteRoutes)
row.append(ex.byteDrops)
rows.append(row)
title = "Exchanges"
if self.cluster:
title += " for cluster '%s'" % self.cluster.clusterName
if config._sortcol:
sorter = Sorter(heads, rows, config._sortcol, config._limit, config._increasing)
dispRows = sorter.getSorted()
else:
dispRows = rows
disp.formattedTable(title, heads, dispRows)
def displayQueue(self, subs):
disp = Display(prefix=" ")
heads = []
if self.cluster:
heads.append(Header('broker'))
heads.append(Header("queue"))
heads.append(Header("dur", Header.Y))
heads.append(Header("autoDel", Header.Y))
heads.append(Header("excl", Header.Y))
heads.append(Header("msg", Header.KMG))
heads.append(Header("msgIn", Header.KMG))
heads.append(Header("msgOut", Header.KMG))
heads.append(Header("bytes", Header.KMG))
heads.append(Header("bytesIn", Header.KMG))
heads.append(Header("bytesOut", Header.KMG))
heads.append(Header("cons", Header.KMG))
heads.append(Header("bind", Header.KMG))
rows = []
for broker in self.brokers:
for oid in broker.queues:
q = broker.queues[oid]
row = []
if self.cluster:
row.append(broker.getName())
row.append(q.name)
row.append(q.durable)
row.append(q.autoDelete)
row.append(q.exclusive)
row.append(q.msgDepth)
row.append(q.msgTotalEnqueues)
row.append(q.msgTotalDequeues)
row.append(q.byteDepth)
row.append(q.byteTotalEnqueues)
row.append(q.byteTotalDequeues)
row.append(q.consumerCount)
row.append(q.bindingCount)
rows.append(row)
title = "Queues"
if self.cluster:
title += " for cluster '%s'" % self.cluster.clusterName
if config._sortcol:
sorter = Sorter(heads, rows, config._sortcol, config._limit, config._increasing)
dispRows = sorter.getSorted()
else:
dispRows = rows
disp.formattedTable(title, heads, dispRows)
def displaySubscriptions(self, subs):
disp = Display(prefix=" ")
heads = []
if self.cluster:
heads.append(Header('broker'))
heads.append(Header("subscription"))
heads.append(Header("queue"))
heads.append(Header("connection"))
heads.append(Header("processName"))
heads.append(Header("processId"))
heads.append(Header("browsing", Header.Y))
heads.append(Header("acknowledged", Header.Y))
heads.append(Header("exclusive", Header.Y))
heads.append(Header("creditMode"))
heads.append(Header("delivered", Header.KMG))
rows = []
for broker in self.brokers:
for oid in broker.subscriptions:
s = broker.subscriptions[oid]
row = []
try:
if self.cluster:
row.append(broker.getName())
row.append(s.name)
row.append(self.qmf.getObjects(_objectId=s.queueRef)[0].name)
connectionRef = self.qmf.getObjects(_objectId=s.sessionRef)[0].connectionRef
row.append(self.qmf.getObjects(_objectId=connectionRef)[0].address)
row.append(self.qmf.getObjects(_objectId=connectionRef)[0].remoteProcessName)
row.append(self.qmf.getObjects(_objectId=connectionRef)[0].remotePid)
row.append(s.browsing)
row.append(s.acknowledged)
row.append(s.exclusive)
row.append(s.creditMode)
row.append(s.delivered)
rows.append(row)
except:
pass
title = "Subscriptions"
if self.cluster:
title += " for cluster '%s'" % self.cluster.clusterName
if config._sortcol:
sorter = Sorter(heads, rows, config._sortcol, config._limit, config._increasing)
dispRows = sorter.getSorted()
else:
dispRows = rows
disp.formattedTable(title, heads, dispRows)
def displayMain(self, main, subs):
if main == 'b': self.displayBroker(subs)
elif main == 'c': self.displayConn(subs)
elif main == 's': self.displaySession(subs)
elif main == 'e': self.displayExchange(subs)
elif main == 'q': self.displayQueue(subs)
elif main == 'u': self.displaySubscriptions(subs)
def display(self):
if config._cluster_detail or config._types[0] == 'b':
# always show cluster detail when dumping broker stats
self._getCluster()
if self.cluster:
memberList = self.cluster.members.split(";")
hostList = self._getHostList(memberList)
self.qmf.delBroker(self.broker)
self.broker = None
if config._host.find("@") > 0:
authString = config._host.split("@")[0] + "@"
else:
authString = ""
for host in hostList:
b = self.qmf.addBroker(authString + host, config._connTimeout)
self.brokers.append(Broker(self.qmf, b))
else:
self.brokers.append(Broker(self.qmf, self.broker))
self.displayMain(config._types[0], config._types[1:])
def main(argv=None):
args = OptionsAndArguments(argv)
bm = BrokerManager()
try:
bm.SetBroker(config._host, config._sasl_mechanism)
bm.display()
bm.Disconnect()
return 0
except KeyboardInterrupt:
print
except Exception,e:
print "Failed: %s - %s" % (e.__class__.__name__, e)
bm.Disconnect() # try to deallocate brokers
return 1
if __name__ == "__main__":
sys.exit(main())