[Zope-Checkins] SVN: Zope/trunk/src/Zope2/utilities/requestprofiler.py Restore the requestprofiler, Tres still relies on it
Hanno Schlichting
hannosch at hannosch.eu
Sat Jul 2 16:26:21 EDT 2011
Log message for revision 122068:
Restore the requestprofiler, Tres still relies on it
Changed:
A Zope/trunk/src/Zope2/utilities/requestprofiler.py
-=-
Copied: Zope/trunk/src/Zope2/utilities/requestprofiler.py (from rev 122057, Zope/trunk/src/Zope2/utilities/requestprofiler.py)
===================================================================
--- Zope/trunk/src/Zope2/utilities/requestprofiler.py (rev 0)
+++ Zope/trunk/src/Zope2/utilities/requestprofiler.py 2011-07-02 20:26:21 UTC (rev 122068)
@@ -0,0 +1,841 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Foundation and Contributors.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+"""Request log profiler script
+"""
+
+import sys, time, getopt, math, cPickle
+from types import StringType
+try: import gzip
+except: pass
+
+class ProfileException(Exception): pass
+
+class Request:
+ def __init__(self):
+ self.url = None
+ self.start = None
+ self.method = None
+ self.t_recdinput = None
+ self.isize = None
+ self.t_recdoutput = None
+ self.osize = None
+ self.httpcode = None
+ self.t_end = None
+ self.elapsed = "I"
+ self.active = 0
+
+ def put(self, code, t, desc):
+ if code not in ('A', 'B', 'I', 'E'):
+ raise "unknown request code %s" % code
+ if code == 'B':
+ self.start = t
+ self.method, self.url = desc.strip().split()
+ elif code == "I":
+ self.t_recdinput = t
+ self.isize = desc.strip()
+ elif code == "A":
+ self.t_recdoutput = t
+ self.httpcode, self.osize = desc.strip().split()
+ elif code == 'E':
+ self.t_end = t
+ self.elapsed = int(self.t_end - self.start)
+
+ def isfinished(self):
+ return not self.elapsed == "I"
+
+ def prettystart(self):
+ if self.start is not None:
+ t = time.localtime(self.start)
+ return time.strftime('%Y-%m-%dT%H:%M:%S', t)
+ else:
+ return "NA"
+
+ def shortprettystart(self):
+ if self.start is not None:
+ t = time.localtime(self.start)
+ return time.strftime('%H:%M:%S', t)
+ else:
+ return "NA"
+
+ def win(self):
+ if self.t_recdinput is not None and self.start is not None:
+ return self.t_recdinput - self.start
+ else:
+ return "NA"
+
+ def wout(self):
+ if self.t_recdoutput is not None and self.t_recdinput is not None:
+ return self.t_recdoutput - self.t_recdinput
+ else:
+ return "NA"
+
+ def wend(self):
+ if self.t_end is not None and self.t_recdoutput is not None:
+ return self.t_end - self.t_recdoutput
+ else:
+ return "NA"
+
+ def endstage(self):
+ if self.t_end is not None:
+ stage = "E"
+ elif self.t_recdoutput is not None:
+ stage = "A"
+ elif self.t_recdinput is not None:
+ stage = "I"
+ else:
+ stage = "B"
+ return stage
+
+ def total(self):
+ stage = self.endstage()
+ if stage == "B": return 0
+ if stage == "I": return self.t_recdinput - self.start
+ if stage == "A": return self.t_recdoutput - self.start
+ if stage == "E": return self.elapsed
+
+ def prettyisize(self):
+ if self.isize is not None:
+ return self.isize
+ else:
+ return "NA"
+
+ def prettyosize(self):
+ if self.osize is not None:
+ return self.osize
+ else:
+ return "NA"
+
+ def prettyhttpcode(self):
+ if self.httpcode is not None:
+ return self.httpcode
+ else:
+ return "NA"
+
+ def __str__(self):
+ body = (
+ self.prettystart(), self.win(), self.wout(), self.wend(),
+ self.total(), self.endstage(), self.prettyosize(),
+ self.prettyhttpcode(), self.active, self.url
+ )
+ return self.fmt % body
+
+ fmt = "%19s %4s %4s %4s %3s %1s %7s %4s %4s %s"
+
+ def getheader(self):
+ body = ('Start', 'WIn', 'WOut', 'WEnd', 'Tot', 'S', 'OSize',
+ 'Code', 'Act', 'URL')
+ return self.fmt % body
+
+class StartupRequest(Request):
+ def endstage(self):
+ return "U"
+
+ def total(self):
+ return 0
+
+class Cumulative:
+ def __init__(self, url):
+ self.url = url
+ self.times = []
+ self.hangs = 0
+ self.allelapsed = None
+
+ def put(self, request):
+ elapsed = request.elapsed
+ if elapsed == "I": self.hangs = self.hangs + 1
+ self.times.append(elapsed)
+
+ def all(self):
+ if self.allelapsed == None:
+ self.allelapsed = []
+ for elapsed in self.times:
+ self.allelapsed.append(elapsed)
+ self.allelapsed.sort()
+ return self.allelapsed
+
+ def __str__(self):
+ body = (
+ self.hangs, self.hits(), self.total(), self.max(), self.min(),
+ self.median(), self.mean(), self.url
+ )
+ return self.fmt % body
+
+ def getheader(self):
+ return self.fmt % ('Hangs', 'Hits', 'Total', 'Max', 'Min', 'Median',
+ 'Mean', 'URL')
+
+ fmt = "%5s %5s %5s %5s %5s %6s %5s %s"
+
+ def hits(self):
+ return len(self.times)
+
+ def max(self):
+ return max(self.all())
+
+ def min(self):
+ return min(self.all())
+
+ def mean(self):
+ l = len(self.times)
+ if l == 0:
+ return "I"
+ else:
+ t = self.total()
+ if t == "I": return "I"
+ return t/l
+
+ def median(self):
+ all = self.all()
+ l = len(all)
+ if l == 0:
+ return "I"
+ else:
+ if l == 1:
+ return all[0]
+ elif l % 2 != 0:
+ i = l/2 + 1
+ return all[i]
+ else:
+ i = l/2 - 1
+ i2 = i + 1
+ v1 = all[i]
+ v2 = all[i2]
+ if isinstance(v1, StringType) or isinstance(v2, StringType):
+ return "I"
+ else: return (v1 + v2) / 2
+
+ def total(self):
+ t = 0
+ all = self.all()
+ for elapsed in all:
+ if elapsed == "I": continue
+ t = t + elapsed
+ return t
+
+def parsebigmlogline(line):
+ tup = line.split(None, 3)
+ if len(tup) == 3:
+ code, id, timestr = tup
+ return code, id, timestr, ''
+ elif len(tup) == 4:
+ return tup
+ else:
+ return None
+
+def get_earliest_file_data(files):
+ temp = {}
+ earliest_fromepoch = 0
+ earliest = None
+ retn = None
+ for file in files:
+ line = file.readline()
+ if not line:
+ continue
+ linelen = len(line)
+ line = line.strip()
+ tup = parsebigmlogline(line)
+ if tup is None:
+ print "Could not interpret line: %s" % line
+ continue
+ code, id, timestr, desc = tup
+ timestr = timestr.strip()
+ fromepoch = getdate(timestr)
+ temp[file] = linelen
+ if earliest_fromepoch == 0 or fromepoch < earliest_fromepoch:
+ earliest_fromepoch = fromepoch
+ earliest = file
+ retn = [code, id, fromepoch, desc]
+
+ for file, linelen in temp.items():
+ if file is not earliest:
+ file.seek(file.tell() - linelen)
+
+ return retn
+
+def get_requests(files, start=None, end=None, statsfname=None,
+ writestats=None, readstats=None):
+ finished = []
+ unfinished = {}
+ if readstats:
+ fp = open(statsfname, 'r')
+ u = cPickle.Unpickler(fp)
+ requests = u.load()
+ fp.close()
+ del u
+ del fp
+ else:
+ while 1:
+ tup = get_earliest_file_data(files)
+ if tup is None:
+ break
+ code, id, fromepoch, desc = tup
+ if start is not None and fromepoch < start: continue
+ if end is not None and fromepoch > end: break
+ if code == 'U':
+ finished.extend(unfinished.values())
+ unfinished.clear()
+ request = StartupRequest()
+ request.url = desc
+ request.start = int(fromepoch)
+ finished.append(request)
+ continue
+ request = unfinished.get(id)
+ if request is None:
+ if code != "B": continue # garbage at beginning of file
+ request = Request()
+ for pending_req in unfinished.values():
+ pending_req.active = pending_req.active + 1
+ unfinished[id] = request
+ t = int(fromepoch)
+ try:
+ request.put(code, t, desc)
+ except:
+ print "Unable to handle entry: %s %s %s"%(code, t, desc)
+ if request.isfinished():
+ del unfinished[id]
+ finished.append(request)
+
+ finished.extend(unfinished.values())
+ requests = finished
+
+ if writestats:
+ fp = open(statsfname, 'w')
+ p = cPickle.Pickler(fp)
+ p.dump(requests)
+ fp.close()
+ del p
+ del fp
+
+ return requests
+
+def analyze(requests, top, sortf, start=None, end=None, mode='cumulative',
+ resolution=60, urlfocusurl=None, urlfocustime=60):
+
+ if mode == 'cumulative':
+ cumulative = {}
+ for request in requests:
+ url = request.url
+ stats = cumulative.get(url)
+ if stats is None:
+ stats = Cumulative(url)
+ cumulative[url] = stats
+ stats.put(request)
+ requests = cumulative.values()
+ requests.sort(sortf)
+ write(requests, top)
+
+ elif mode=='timed':
+ computed_start = requests[0].start
+ computed_end = requests[-1].t_end
+ if start and end:
+ timewrite(requests,start,end,resolution)
+ if start and not end:
+ timewrite(requests,start,computed_end,resolution)
+ if end and not start:
+ timewrite(requests,computed_start,end,resolution)
+ if not end and not start:
+ timewrite(requests,computed_start,computed_end,resolution)
+
+ elif mode == 'urlfocus':
+ requests.sort(sortf)
+ urlfocuswrite(requests, urlfocusurl, urlfocustime)
+
+ else:
+ requests.sort(sortf)
+ write(requests, top)
+
+def urlfocuswrite(requests, url, t):
+ l = []
+ i = 0
+ for request in requests:
+ if request.url == url: l.append(i)
+ i = i + 1
+ before = {}
+ after = {}
+ x = 0
+ for n in l:
+ x = x + 1
+ r = requests[n]
+ start = r.start
+ earliest = start - t
+ latest = start + t
+ print 'URLs invoked %s seconds before and after %s (#%s, %s)' % \
+ (t, url, x, r.shortprettystart())
+ print '---'
+ i = -1
+ for request in requests:
+ i = i + 1
+ if request.start < earliest: continue
+ if request.start > latest: break
+ if n == i: # current request
+ print '%3d' % (request.start - start),
+ print '%s' % (request.shortprettystart()),
+ print request.url
+ continue
+ if request.start <= start:
+ if before.get(i):
+ before[i] = before[i] + 1
+ else:
+ before[i] = 1
+ if request.start > start:
+ if after.get(i):
+ after[i] = after[i] + 1
+ else:
+ after[i] = 1
+ print '%3d' % (request.start - start),
+ print '%s' % (request.shortprettystart()),
+ print request.url
+ print
+ print ('Summary of URLs invoked before (and at the same time as) %s '
+ '(times, url)' % url)
+ before = before.items()
+ before.sort()
+ for k,v in before:
+ print v, requests[k].url
+ print
+ print 'Summary of URLs invoked after %s (times, url)' % url
+ after = after.items()
+ after.sort()
+ for k,v in after:
+ print v, requests[k].url
+
+def write(requests, top=0):
+ if len(requests) == 0:
+ print "No data.\n"
+ return
+ i = 0
+ header = requests[0].getheader()
+ print header
+ for stat in requests:
+ i = i + 1
+ if verbose:
+ print str(stat)
+ else:
+ print str(stat)[:78]
+ if i == top:
+ break
+
+def getdate(val):
+ try:
+ val = val.strip()
+ year, month, day = int(val[:4]), int(val[5:7]), int(val[8:10])
+ hour,minute,second=int(val[11:13]),int(val[14:16]),int(val[17:19])
+ t = time.mktime((year, month, day, hour, minute, second, 0, 0, -1))
+ return t
+ except:
+ raise ProfileException, "bad date %s" % val
+
+def getTimeslice(period, utime):
+ low = int(math.floor(utime)) - period + 1
+ high = int(math.ceil(utime)) + 1
+ for x in range(low, high):
+ if x % period == 0:
+ return x
+
+def timewrite(requests, start, end, resolution):
+ print "Start: %s End: %s Resolution: %d secs" % \
+ (tick2str(start), tick2str(end), resolution)
+ print "-" * 78
+ print
+ print "Date/Time #requests requests/second"
+
+ d = {}
+ max = 0
+ min = None
+ for r in requests:
+ t = r.start
+ slice = getTimeslice(resolution,t)
+ if slice > max: max = slice
+ if (min is None) or (slice < min): min = slice
+ if d.has_key(slice):
+ d[slice] = d[slice] + 1
+ else:
+ d[slice] = 1
+
+ num = 0
+ hits = 0
+ avg_requests = None
+ max_requests = 0
+ for slice in range(min, max, resolution):
+ num = d.get(slice, 0)
+ if num>max_requests: max_requests = num
+ hits = hits + num
+
+ if avg_requests is None:
+ avg_requests = num
+ else:
+ avg_requests = (avg_requests + num) / 2
+
+ s = tick2str(slice)
+ s = s + " %6d %4.2lf" % (num,num*1.0/resolution)
+ print s
+
+ print '='*78
+ print " Peak: %6d %4.2lf" % \
+ (max_requests,max_requests*1.0/resolution)
+ print " Avg: %6d %4.2lf" % \
+ (avg_requests,avg_requests*1.0/resolution)
+ print "Total: %6d n/a " % (hits)
+
+def tick2str(t):
+ return time.strftime('%Y-%m-%dT%H:%M:%S', time.localtime(t))
+
+def codesort(v1, v2):
+ v1 = v1.endstage()
+ v2 = v2.endstage()
+ if v1 == v2:
+ return 0
+
+ if v1 == "B":
+ return -1 # v1 is smaller than v2
+ if v1 == "I":
+ if v2 == "B": return 1 # v1 is larger than v2
+ else: return -1
+ if v1 == "A":
+ if v2 in ['B', 'I']: return 1
+ else: return -1
+ if v1 == "E":
+ return 1
+
+class Sort:
+ def __init__(self, fname, ascending=0):
+ self.fname = fname
+ self.ascending = ascending
+
+ def __call__(self, i1, i2):
+ f1 = getattr(i1, self.fname)
+ f2 = getattr(i2, self.fname)
+ if callable(f1): f1 = f1()
+ if callable(f2): f2 = f2()
+ if f1 < f2:
+ if self.ascending: return -1
+ else: return 1
+ elif f1 == f2:
+ return 0
+ else:
+ if self.ascending: return 1
+ else: return -1
+
+def detailedusage():
+ details = usage(0)
+ pname = sys.argv[0]
+ details = details + """
+Reports are of four types: cumulative, detailed, timed, or urlfocus. The
+default is cumulative. Data is taken from one or more Zope detailed request
+logs (-M logs, aka 'big M' logs) or from a preprocessed statistics file.
+
+For cumulative reports, each line in the profile indicates information
+about a Zope method (URL) collected via a detailed request log.
+
+For detailed reports, each line in the profile indicates information about
+a single request.
+
+For timed reports, each line in the profile indicates informations about
+the number of requests and the number of requests/second for a period of time.
+
+For urlfocus reports, ad-hoc information about requests surrounding the
+specified url is given.
+
+Each 'filename' is a path to a '-M' log that contains detailed request data.
+Multiple input files can be analyzed at the same time by providing the path
+to each file. (Analyzing multiple big M log files at once is useful if you
+have more than one Zope client on a single machine and you'd like to
+get an overview of all Zope activity on that machine).
+
+If you wish to make multiple analysis runs against the same input data, you
+may want to use the --writestats option. The --writestats option creates a
+file which holds preprocessed data representing the specfified input files.
+Subsequent runs (for example with a different sort spec) will be much
+faster if the --readstats option is used to specify a preprocessed stats
+file instead of actual input files because the logfile parse step is skipped.
+
+If a 'sort' value is specified, sort the profile info by the spec. The sort
+order is descending unless indicated. The default cumulative sort spec is
+'total'. The default detailed sort spec is 'start'.
+
+For cumulative reports, the following sort specs are accepted:
+
+ 'hits' -- the number of hits against the method
+ 'hangs' -- the number of unfinished requests to the method
+ 'max' -- the maximum time in secs taken by a request to this method
+ 'min' -- the minimum time in secs taken by a request to this method
+ 'mean' -- the mean time in secs taken by a request to this method
+ 'median' -- the median time in secs taken by a request to this method
+ 'total' -- the total time in secs across all requests to this method
+ 'url' -- the URL/method name (ascending)
+
+For detailed (non-cumulative) reports, the following sort specs are accepted:
+
+ 'start' -- the start time of the request to ZServer (ascending)
+ 'win' -- the num of secs ZServer spent waiting for input from client
+ 'wout' -- the secs ZServer spent waiting for output from ZPublisher
+ 'wend' -- the secs ZServer spent sending data to the client
+ 'total' -- the secs taken for the request from begin to end
+ 'endstage' -- the last successfully completed request stage (B, I, A, E)
+ 'osize' -- the size in bytes of output provided by ZPublisher
+ 'httpcode' -- the HTTP response code provided by ZPublisher (ascending)
+ 'active' -- total num of requests pending at the end of this request
+ 'url' -- the URL/method name (ascending)
+
+For timed and urlfocus reports, there are no sort specs allowed.
+
+If the 'top' argument is specified, only report on the top 'n' entries in
+the profile (as per the sort). The default is to show all data in the profile.
+
+If the 'verbose' argument is specified, do not trim url to fit into 80 cols.
+
+If the 'today' argument is specified, limit results to hits received today.
+
+If the 'daysago' argument is specified, limit results to hits received n days ago.
+
+The 'resolution' argument is used only for timed reports and specifies the
+number of seconds between consecutive lines in the report
+(default is 60 seconds).
+
+The 'urlfocustime' argument is used only for urlfocus reports and specifies the
+number of seconds to target before and after the URL provided in urlfocus mode.
+(default is 10 seconds).
+
+If the 'start' argument is specified in the form 'DD/MM/YYYY HH:MM:SS' (UTC),
+limit results to hits received after this date/time.
+
+If the 'end' argument is specified in the form 'DD/MM/YYYY HH:MM:SS' (UTC),
+limit results to hits received before this date/time.
+
+'start' and 'end' arguments are not honored when request stats are obtained
+via the --readstats argument.
+
+Examples:
+
+ %(pname)s debug.log
+
+ Show cumulative report statistics for information in the file 'debug.log',
+ by default sorted by 'total'.
+
+ %(pname)s debug.log --detailed
+
+ Show detailed report statistics sorted by 'start' (by default).
+
+ %(pname)s debug.log debug2.log --detailed
+
+ Show detailed report statistics for both logs sorted by 'start'
+ (by default).
+
+ %(pname)s debug.log --cumulative --sort=mean --today --verbose
+
+ Show cumulative report statistics sorted by mean for entries in the log
+ which happened today, and do not trim the URL in the resulting report.
+
+ %(pname)s debug.log --cumulative --sort=mean --daysago=3 --verbose
+
+ Show cumulative report statistics sorted by mean for entries in the log
+ which happened three days ago, and do not trim the URL in the resulting report.
+
+ %(pname)s debug.log --urlfocus='/manage_main' --urlfocustime=60
+
+ Show 'urlfocus' report which displays statistics about requests
+ surrounding the invocation of '/manage_main'. Focus on the time periods
+ 60 seconds before and after each invocation of the '/manage_main' URL.
+
+ %(pname)s debug.log --detailed --start='2001/05/10 06:00:00'
+ --end='2001/05/11 23:00:00'
+
+ Show detailed report statistics for entries in 'debug.log' which
+ begin after 6am UTC on May 10, 2001 and which end before
+ 11pm UTC on May 11, 2001.
+
+ %(pname)s debug.log --timed --resolution=300 --start='2001/05/10 06:00:00'
+ --end='2001/05/11 23:00:00'
+
+ Show timed report statistics for entries in the log for one day
+ with a resolution of 5 minutes
+
+ %(pname)s debug.log --top=100 --sort=max
+
+ Show cumulative report of the the 'top' 100 methods sorted by maximum
+ elapsed time.
+
+ %(pname)s debug.log debug2.log --writestats='requests.stat'
+
+ Write stats file for debug.log and debug2.log into 'requests.stat' and
+ show default report.
+
+ %(pname)s --readstats='requests.stat' --detailed
+
+ Read from 'requests.stat' stats file (instead of actual -M log files)
+ and show detailed report against this data.""" % {'pname':pname}
+ return details
+
+def usage(basic=1):
+ usage = (
+ """
+Usage: %s filename1 [filename2 ...]
+ [--cumulative | --detailed | [--timed --resolution=seconds]]
+ [--sort=spec]
+ [--top=n]
+ [--verbose]
+ [--today | [--start=date] [--end=date] | --daysago=n ]
+ [--writestats=filename | --readstats=filename]
+ [--urlfocus=url]
+ [--urlfocustime=seconds]
+ [--help]
+
+Provides a profile of one or more Zope "-M" request log files.
+""" % sys.argv[0]
+ )
+ if basic == 1:
+ usage = usage + """
+If the --help argument is given, detailed usage docs are provided."""
+ return usage
+
+
+def main():
+ if len(sys.argv) == 1:
+ print usage()
+ sys.exit(0)
+ if sys.argv[1] == '--help': print detailedusage(); sys.exit(0)
+ mode = 'cumulative'
+ sortby = None
+ trim = 0
+ top = 0
+ verbose = 0
+ start = None
+ end = None
+ resolution=60
+ urlfocustime=10
+ urlfocusurl=None
+ statsfname = None
+ readstats = 0
+ writestats = 0
+
+ files = []
+ i = 1
+ for arg in sys.argv[1:]:
+ if arg[:2] != '--':
+ if arg[-3:] == '.gz' and globals().has_key('gzip'):
+ files.append(gzip.GzipFile(arg,'r'))
+ else:
+ files.append(open(arg))
+ sys.argv.remove(arg)
+ i = i + 1
+
+ try:
+ opts, extra = getopt.getopt(
+ sys.argv[1:], '', ['sort=', 'top=', 'help', 'verbose', 'today',
+ 'cumulative', 'detailed', 'timed','start=',
+ 'end=','resolution=', 'writestats=','daysago=',
+ 'readstats=','urlfocus=','urlfocustime=']
+ )
+ for opt, val in opts:
+
+ if opt=='--readstats':
+ statsfname = val
+ readstats = 1
+ elif opt=='--writestats':
+ statsfname = val
+ writestats = 1
+ if opt=='--sort': sortby = val
+ if opt=='--top': top=int(val)
+ if opt=='--help': print detailedusage(); sys.exit(0)
+ if opt=='--verbose':
+ verbose = 1
+ if opt=='--resolution':
+ resolution=int(val)
+ if opt=='--today':
+ now = time.localtime(time.time())
+ # for testing - now = (2001, 04, 19, 0, 0, 0, 0, 0, -1)
+ start = list(now)
+ start[3] = start[4] = start[5] = 0
+ start = time.mktime(start)
+ end = list(now)
+ end[3] = 23; end[4] = 59; end[5] = 59
+ end = time.mktime(end)
+ if opt=='--daysago':
+ now = time.localtime(time.time() - int(val)*3600*24 )
+ # for testing - now = (2001, 04, 19, 0, 0, 0, 0, 0, -1)
+ start = list(now)
+ start[3] = start[4] = start[5] = 0
+ start = time.mktime(start)
+ end = list(now)
+ end[3] = 23; end[4] = 59; end[5] = 59
+ end = time.mktime(end)
+ if opt=='--start':
+ start = getdate(val)
+ if opt=='--end':
+ end = getdate(val)
+ if opt=='--detailed':
+ mode='detailed'
+ d_sortby = sortby
+ if opt=='--cumulative':
+ mode='cumulative'
+ if opt=='--timed':
+ mode='timed'
+ if opt=='--urlfocus':
+ mode='urlfocus'
+ urlfocusurl = val
+ if opt=='--urlfocustime':
+ urlfocustime=int(val)
+
+ validcumsorts = ['url', 'hits', 'hangs', 'max', 'min', 'median',
+ 'mean', 'total']
+ validdetsorts = ['start', 'win', 'wout', 'wend', 'total',
+ 'endstage', 'isize', 'osize', 'httpcode',
+ 'active', 'url']
+
+ if mode == 'cumulative':
+ if sortby is None: sortby = 'total'
+ assert sortby in validcumsorts, (sortby, mode, validcumsorts)
+ if sortby in ['url']:
+ sortf = Sort(sortby, ascending=1)
+ else:
+ sortf = Sort(sortby)
+ elif mode == 'detailed':
+ if sortby is None: sortby = 'start'
+ assert sortby in validdetsorts, (sortby, mode, validdetsorts)
+ if sortby in ['start', 'url', 'httpcode']:
+ sortf = Sort(sortby, ascending=1)
+ elif sortby == 'endstage':
+ sortf = codesort
+ else:
+ sortf = Sort(sortby)
+ elif mode=='timed':
+ sortf = None
+ elif mode=='urlfocus':
+ sortf = Sort('start', ascending=1)
+ else:
+ raise 'Invalid mode'
+
+ req=get_requests(files, start, end, statsfname, writestats, readstats)
+ analyze(req, top, sortf, start, end, mode, resolution, urlfocusurl,
+ urlfocustime)
+
+ except AssertionError, val:
+ a = "%s is not a valid %s sort spec, use one of %s"
+ print a % (val[0], val[1], val[2])
+ sys.exit(0)
+ except getopt.error, val:
+ print val
+ sys.exit(0)
+ except ProfileException, val:
+ print val
+ sys.exit(0)
+ except SystemExit:
+ sys.exit(0)
+ except:
+ import traceback
+ traceback.print_exc()
+ print usage()
+ sys.exit(0)
+
+if __name__ == '__main__':
+ main()
More information about the Zope-Checkins
mailing list