summaryrefslogtreecommitdiff
path: root/qpid/tools
diff options
context:
space:
mode:
authorKim van der Riet <kpvdr@apache.org>2011-11-16 16:11:31 +0000
committerKim van der Riet <kpvdr@apache.org>2011-11-16 16:11:31 +0000
commite77fa983d2b127b1d0c1d6aaf73dc605b5c05a3e (patch)
tree64e21a6b64899396e57952339f7bf2a328e86e0f /qpid/tools
parent937f24744e430008edb9d5063eeac5030f01c2f7 (diff)
downloadqpid-python-e77fa983d2b127b1d0c1d6aaf73dc605b5c05a3e.tar.gz
QPID-3623, QPID-3624: Fixed transaction accounting, also replaced argparse module with optparse module for use on earlier versions of Python than 2.7. Some minor code tidy-up was also included.
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1202763 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/tools')
-rwxr-xr-xqpid/tools/src/py/qpid-analyze-trace128
1 files changed, 79 insertions, 49 deletions
diff --git a/qpid/tools/src/py/qpid-analyze-trace b/qpid/tools/src/py/qpid-analyze-trace
index dbe31a95fc..003080ca8d 100755
--- a/qpid/tools/src/py/qpid-analyze-trace
+++ b/qpid/tools/src/py/qpid-analyze-trace
@@ -20,11 +20,20 @@
#
import sys
-from argparse import ArgumentParser
+#from argparse import ArgumentParser
from datetime import datetime
+from optparse import OptionParser
# Version of this tool software
-VERSION = "1.0"
+MAJOR_VERSION = 1
+MINOR_VERSION = 1
+# === Version history ===
+# 2011-11-16 1.1: Bugfixs:
+# QPID-3623 - Incorrect handling of transactions
+# QPID-3624 - Replace argparse lib with optparse so tool can be used on Python 2.6.
+# 2011-11-07 1.0: Initial checkin
+# QPID-3579: Initial version checked in
+
# AMQP 0-10 commands - these increment the command counter
EXEC_COMMANDS = ["ExecutionSync", "ExecutionResult", "ExecutionException", "MessageTransfer", "MessageAccept",
@@ -37,8 +46,9 @@ EXEC_COMMANDS = ["ExecutionSync", "ExecutionResult", "ExecutionException", "Mess
"FileOpen", "FileOpenOk", "FileStage", "FilePublish", "FileReturn", "FileDeliver", "FileAck",
"FileReject", "StreamQos", "StreamQosOk", "StreamConsume", "StreamConsumeOk", "StreamCancel",
"StreamPublish", "StreamReturn", "StreamDeliver"]
+HEADER_STR = " -line ----------timestamp -----------connection ssn recv send- txn-- operation---------->"
-LINES_PER_DOT = 100000
+PROGRESS_LINES_PER_DOT = 100000
class LogLevel:
CRITICAL = (1, "critical")
@@ -96,6 +106,9 @@ class LogLine:
return self.get_identifier().partition("-")[2]
def get_named_value(self, name):
return self.line.partition("%s=" % name)[2].partition(";")[0]
+ def get_msg_accept_range(self):
+ str_nums = self.get_named_value("transfers").strip(" {[]}").split(",")
+ return range(int(str_nums[0]), int(str_nums[1]) + 1)
def is_log_level(self, level):
if self.level is None: return None
return level[0] == self.level[0]
@@ -113,15 +126,15 @@ class ConnectionProperty:
class Connection(ConnectionProperty):
def __init__(self, line):
ConnectionProperty.__init__(self, line)
- self.sessionList = [] # Keeps session creation order
- self.sessionDict = {} # For looking up by channel no.
+ self.session_list = [] # Keeps session creation order
+ self.session_dict = {} # For looking up by channel no.
def __str__(self):
- return "Connection %s (ops=%d; sessions=%d):" % (self.addr, len(self.ops), len(self.sessionDict))
+ return "Connection %s (ops=%d; sessions=%d):" % (self.addr, len(self.ops), len(self.session_dict))
def add_session(self, session):
- self.sessionList.append(session)
- self.sessionDict[session.channel] = session
+ self.session_list.append(session)
+ self.session_dict[session.channel] = session
def get_session(self, channel):
- return self.sessionDict[channel]
+ return self.session_dict[channel]
class Session(ConnectionProperty):
def __init__(self, line):
@@ -131,6 +144,8 @@ class Session(ConnectionProperty):
self.recv_cnt = 0
self.txn_flag = False
self.txn_cnt = 0
+ self.recv_cmds = {} # For looking up by cmd no
+ self.send_cmds = {} # For looking up by cmd no
def __str__(self):
if self.txn_flag:
return " + Session %d (name=%s send-cmds=%d recv-cmds=%d txns=%d):" % (self.channel, self.name,
@@ -138,27 +153,34 @@ class Session(ConnectionProperty):
self.txn_cnt)
return " + Session %d (name=%s send-cmds=%d recv-cmds=%d non-txn):" % (self.channel, self.name, self.send_cnt,
self.recv_cnt)
+ def incr_recv_cnt(self, line):
+ self.recv_cmds[self.recv_cnt] = line
+ self.recv_cnt += 1
+ def incr_send_cnt(self, line):
+ self.send_cmds[self.send_cnt] = line
+ self.send_cnt += 1
+ def set_send_txn_cnt(self, cmd):
+ self.send_cmds[cmd].txn_cnt = self.txn_cnt
class TraceAnalysis:
def __init__(self):
- self.connectionList = [] # Keeps connection creation order
- self.connectionDict = {} # For looking up by connection address
- parser = ArgumentParser(description="Analyze trace level logs from a Qpid broker log file.")
- parser.add_argument("--connection-summary", action="store_true", default=False,
- help="Hide connection details, provide one-line summary")
- parser.add_argument("--session-summary", action="store_true", default=False,
- help="Hide session details, provide one-line summary")
- parser.add_argument("-s", "--summary", action="store_true", default=False,
- help="Hide both connection and session details. Equivalent to --connection-summary and "
- "--session-summary")
- parser.add_argument("log_file", action="store",
- help="Log file")
- parser.add_argument("-v", "--version", action='version', version="%%(prog)s %s" % VERSION)
- self.args = parser.parse_args()
+ self.connection_list = [] # Keeps connection creation order
+ self.connection_dict = {} # For looking up by connection address
+ parser = OptionParser(usage="%prog [options] trace-file", version="%%prog %d.%d" % (MAJOR_VERSION, MINOR_VERSION),
+ description="A tool to structure and display Qpid broker trace logs.")
+ parser.add_option("--connection-summary", action="store_true", default=False, dest="connection_summary",
+ help="Hide connection details, provide one-line summary")
+ parser.add_option("--session-summary", action="store_true", default=False, dest="session_summary",
+ help="Hide session details, provide one-line summary")
+ parser.add_option("--summary", "-s", action="store_true", default=False, dest="summary",
+ help="Hide both connection and session details. Equivalent to --connection-summary and"
+ "--session-summary")
+ self.opts, self.args = parser.parse_args()
+ if len(self.args) == 0: raise Exception("Missing trace-file argument")
def analyze_trace(self):
lcnt = 0
- print "Reading trace file %s:" % self.args.log_file
- log_file = open(self.args.log_file, "r")
+ print "Reading trace file %s:" % self.args[0]
+ log_file = open(self.args[0], "r")
try:
for fline in log_file:
lcnt += 1
@@ -167,25 +189,30 @@ class TraceAnalysis:
if lline.is_log_level(LogLevel.TRACE) and lline.is_frame():
if lline.contains("{ConnectionStartBody"):
conn = Connection(lline)
- self.connectionList.append(conn)
- self.connectionDict[conn.addr] = conn
+ self.connection_list.append(conn)
+ self.connection_dict[conn.addr] = conn
elif lline.contains("{Connection"):
- self.connectionDict[lline.get_identifier_remote_addr()].add_op(lline)
+ self.connection_dict[lline.get_identifier_remote_addr()].add_op(lline)
elif lline.contains("{SessionAttachBody"):
ssn = Session(lline)
- self.connectionDict[ssn.addr].add_session(ssn)
+ self.connection_dict[ssn.addr].add_session(ssn)
else:
- ssn = self.connectionDict[lline.get_identifier_remote_addr()].get_session(lline.get_channel())
+ ssn = self.connection_dict[lline.get_identifier_remote_addr()].get_session(lline.get_channel())
ssn.add_op(lline)
if lline.line[lline.find("{") + 1 : lline.find("Body")] in EXEC_COMMANDS:
if lline.contains("RECV"):
lline.cmd_cnt = ssn.recv_cnt
- if ssn.txn_flag and lline.contains("MessageTransferBody"): lline.txn_cnt = ssn.txn_cnt
- ssn.recv_cnt += 1
+ if ssn.txn_flag:
+ if lline.contains("MessageAcceptBody"):
+ lline.txn_cnt = ssn.txn_cnt
+ for cmd in lline.get_msg_accept_range():
+ ssn.set_send_txn_cnt(cmd)
+ if lline.contains("MessageTransferBody"): lline.txn_cnt = ssn.txn_cnt
+ ssn.incr_recv_cnt(lline)
elif lline.contains("SEND") or lline.contains("SENT"):
lline.cmd_cnt = ssn.send_cnt
- if ssn.txn_flag and lline.contains("MessageTransferBody"): lline.txn_cnt = ssn.txn_cnt
- ssn.send_cnt += 1
+ ssn.incr_send_cnt(lline)
+ # TODO: This treatment will probably break down for DTX
if lline.contains("xSelectBody"):
ssn.txn_flag = True
elif lline.contains("xCommitBody") or lline.contains("xRollbackBody"):
@@ -193,26 +220,29 @@ class TraceAnalysis:
ssn.txn_cnt += 1
except KeyboardInterrupt as e: raise e
except: pass
- if (lcnt + 1) % LINES_PER_DOT == 0:
+ if (lcnt + 1) % PROGRESS_LINES_PER_DOT == 0:
sys.stdout.write(".")
sys.stdout.flush()
finally: log_file.close()
- if lcnt > LINES_PER_DOT: print
+ if lcnt > PROGRESS_LINES_PER_DOT: print
print "Read and analyzed", lcnt, "lines."
def print_analysis(self):
- for c in self.connectionList:
- print
- if not self.args.connection_summary and not self.args.session_summary and not self.args.summary:
- print " ---line ----------timestamp -----------connection ssn recv send- txn-- operation---------->"
- print c
- if not self.args.connection_summary and not self.args.summary:
- for o in c.ops:
- print o
- for s in c.sessionList:
- print s
- if not self.args.session_summary and not self.args.summary:
- for o in s.ops:
+ if len(self.connection_list) > 0:
+ for c in self.connection_list:
+ print
+ print c
+ if not self.opts.connection_summary and not self.opts.summary:
+ print HEADER_STR
+ for o in c.ops:
print o
+ for s in c.session_list:
+ print s
+ if not self.opts.session_summary and not self.opts.summary:
+ print HEADER_STR
+ for o in s.ops:
+ print o
+ else:
+ print "No trace-level entries found in log."
def check_python_version(major, minor, micro):
if sys.version_info < (major, minor, micro):
@@ -222,7 +252,7 @@ def check_python_version(major, minor, micro):
# === Main program ===
if __name__ == '__main__':
- check_python_version(2, 7, 0) # need at least v2.7
+ check_python_version(2, 4, 0)
t = TraceAnalysis()
t.analyze_trace()
t.print_analysis()