[Zope-Checkins] SVN: Zope/trunk/utilities/tracelog.py Simple script
to analyze trace logs.
Jim Fulton
jim at zope.com
Tue Jan 24 18:38:55 EST 2006
Log message for revision 41425:
Simple script to analyze trace logs.
Changed:
A Zope/trunk/utilities/tracelog.py
-=-
Added: Zope/trunk/utilities/tracelog.py
===================================================================
--- Zope/trunk/utilities/tracelog.py 2006-01-24 22:36:17 UTC (rev 41424)
+++ Zope/trunk/utilities/tracelog.py 2006-01-24 23:38:54 UTC (rev 41425)
@@ -0,0 +1,223 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# 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.
+#
+##############################################################################
+"""Yet another trace log analysis tool
+
+$Id$
+"""
+
+import datetime, optparse, sys
+
+
+
+class Request:
+
+ output_bytes = '-'
+
+ def __init__(self, start, method, url):
+ self.method = method
+ self.url = url
+ self.start = start
+ self.state = 'input'
+
+ def I(self, input_time, input_bytes):
+ self.input_time = input_time
+ self.input_bytes = input_bytes
+ self.state = 'app'
+
+ def A(self, app_time, response, output_bytes):
+ self.app_time = app_time
+ self.response = response
+ self.output_bytes = output_bytes
+ self.state = 'output'
+
+ def E(self, end):
+ self.end = end
+
+ @property
+ def app_seconds(self):
+ return (self.app_time - self.input_time).seconds
+
+ @property
+ def total_seconds(self):
+ return (self.end - self.start).seconds
+
+def parsedt(s):
+ date, time = s.split('T')
+ return datetime.datetime(*(
+ map(int, date.split('-'))
+ +
+ map(int, time.split(':'))
+ ))
+
+def main(args=None):
+ if args is None:
+ args = sys.argv[1:]
+
+ options, args = parser.parse_args(args)
+ if options.event_log:
+ restarts = find_restarts(options.event_log)
+ else:
+ restarts = []
+
+ restarts.append(datetime.datetime.utcnow()+datetime.timedelta(1000))
+
+ [file] = args
+ lmin = ldt = None
+ requests = {}
+ input = apps = output = n = 0
+ spr = spa = 0.0
+ restart = restarts.pop(0)
+ for record in open(file):
+ record = record.split()
+ typ, rid, dt = record[:3]
+ min = dt[:-3]
+ dt = parsedt(dt)
+ if dt == restart:
+ continue
+ while dt > restart:
+ print_app_requests(requests, ldt,
+ options.old_requests,
+ options.app_requests,
+ "\nLeft over:")
+ requests = {}
+ input = apps = output = n = 0
+ spr = spa = 0.0
+ restart = restarts.pop(0)
+ ldt = dt
+
+ if min != lmin:
+ if lmin is not None:
+
+ print lmin.replace('T', ' '), "%4d I=%3d A=%3d O=%3d " % (
+ len(requests), input, apps, output),
+ if n:
+ print "N=%4d %10.2f %10.2f" % (n, spr/n, spa/n)
+ else:
+ print
+
+ if apps > options.apps:
+ print_app_requests(requests, dt,
+ options.old_requests,
+ options.app_requests,
+ )
+ lmin = min
+ spr = 0.0
+ spa = 0.0
+ n = 0
+
+ if typ == 'B':
+ input += 1
+ requests[rid] = Request(dt, *record[3:5])
+ elif typ == 'I':
+ if rid in requests:
+ input -= 1
+ apps += 1
+ requests[rid].I(dt, record[3])
+ elif typ == 'A':
+ if rid in requests:
+ apps -= 1
+ output += 1
+ requests[rid].A(dt, *record[3:5])
+ elif typ == 'E':
+ if rid in requests:
+ output -= 1
+ request = requests.pop(rid)
+ request.E(dt)
+ spr += request.total_seconds
+ spa += request.app_seconds
+ n += 1
+ else:
+ print 'WTF', record
+
+ print_app_requests(requests, dt,
+ options.old_requests,
+ options.app_requests,
+ "Left over:")
+
+def find_restarts(event_log):
+ result = []
+ for l in open(event_log):
+ if l.strip().endswith("Zope Ready to handle requests"):
+ result.append(parsedt(l.split()[0]))
+ return result
+
+def print_app_requests(requests, dt, min_seconds, max_requests, label=''):
+ requests = [
+ ((dt-request.input_time).seconds, request)
+ for request in requests.values()
+ if request.state == 'app'
+ ]
+ requests.sort()
+ requests.reverse()
+ for s, request in requests[:max_requests]:
+ if s < min_seconds:
+ continue
+ if label:
+ print label
+ label = ''
+ print s, request.url
+
+parser = optparse.OptionParser("""
+Usage: %prog [options] trace_log_file
+
+Output trace log data showing:
+
+- number of active requests,
+- number of input requests (requests gathering input),
+- number of application requests,
+- number of output requests,
+- number of requests completed in the minute shown,
+- mean seconds per request and
+- mean application seconds per request.
+
+Note that we don't seem to be logging when a connection to the client
+is broken, so the number of active requests, and especially the number
+of outputing requests tends to grow over time. This is spurious.
+
+Also, note that, unfortunately, application requests include requests
+that are running in application threads and requests waiting to get an
+application thread.
+
+When application threads get above the app request threshold, then we
+show the requests that have been waiting the longest.
+
+""")
+
+parser.add_option("--app-request-threshold", "-a", dest='apps',
+ type="int", default=10,
+ help="""
+Number of pending application requests at which detailed request information
+if printed.
+""")
+parser.add_option("--app-requests", "-r", dest='app_requests',
+ type="int", default=10,
+ help="""
+How many requests to show when the maximum number of pending
+apps is exceeded.
+""")
+parser.add_option("--old-requests", "-o", dest='old_requests',
+ type="int", default=10,
+ help="""
+Number of seconds beyond which a request is considered old.
+""")
+parser.add_option("--event-log", "-e", dest='event_log',
+ help="""
+The name of an event log that goes with the trace log. This is used
+to determine when the server is restarted, so that the running trace data structures can be reinitialized.
+""")
+
+
+
+if __name__ == '__main__':
+ main()
Property changes on: Zope/trunk/utilities/tracelog.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
More information about the Zope-Checkins
mailing list