[CalendarServer-changes] [10761] CalendarServer/trunk/contrib/tools/request_monitor.py
source_changes at macosforge.org
source_changes at macosforge.org
Tue Feb 19 14:13:57 PST 2013
Revision: 10761
http://trac.calendarserver.org//changeset/10761
Author: cdaboo at apple.com
Date: 2013-02-19 14:13:57 -0800 (Tue, 19 Feb 2013)
Log Message:
-----------
Allow number of top users to be set on the cmdline.
Modified Paths:
--------------
CalendarServer/trunk/contrib/tools/request_monitor.py
Modified: CalendarServer/trunk/contrib/tools/request_monitor.py
===================================================================
--- CalendarServer/trunk/contrib/tools/request_monitor.py 2013-02-19 20:42:18 UTC (rev 10760)
+++ CalendarServer/trunk/contrib/tools/request_monitor.py 2013-02-19 22:13:57 UTC (rev 10761)
@@ -65,10 +65,10 @@
VMSTAT = "/usr/bin/vmstat"
enableFreeMem = os.path.exists(VMSTAT)
-sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
+sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
-filenames = ["/var/log/caldavd/access.log",]
+filenames = ["/var/log/caldavd/access.log", ]
debug = False
def listenq():
@@ -79,7 +79,7 @@
stdout=PIPE, stderr=STDOUT,
)
output, _ignore_error = child.communicate()
- ssl = nonssl = 0
+ ssl = nonssl = 0
for line in output.split("\n"):
if line.find("8443") != -1:
ssl = int(line.split("/")[0])
@@ -121,6 +121,8 @@
results[filename].extend(output.splitlines())
return results
+
+
def range(filenames, start, end):
results = collections.defaultdict(list)
for filename in filenames:
@@ -132,6 +134,8 @@
break
return results
+
+
def cpuPerDaemon():
a = {}
child = Popen(
@@ -155,6 +159,7 @@
return ", ".join([v for _ignore_k, v in sorted(a.items(), key=lambda i:i[0])])
+
def cpuidle():
if OS == "OS X":
child = Popen(
@@ -175,6 +180,8 @@
output, _ignore_ = child.communicate()
return output.splitlines()[-2].split()[5]
+
+
def freemem():
try:
if OS == "OS X":
@@ -186,11 +193,11 @@
)
output, _ignore_ = child.communicate()
lines = output.split("\n")
-
+
line = lines[0]
- pageSize = int(line[line.find("page size of")+12:].split()[0])
+ pageSize = int(line[line.find("page size of") + 12:].split()[0])
line = lines[1]
- freeSize = int(line[line.find("Pages free:")+11:].split()[0][:-1])
+ freeSize = int(line[line.find("Pages free:") + 11:].split()[0][:-1])
freed = freeSize * pageSize
return "%d bytes (%.1f GB)" % (freed, freed / (1024.0 * 1024 * 1024),)
elif OS == "Linux":
@@ -202,7 +209,7 @@
)
output, _ignore_ = child.communicate()
lines = output.splitlines()
-
+
line = lines[4]
freed = int(line.split()[0]) * 1024
return "%d bytes (%.1f GB)" % (freed, freed / (1024.0 * 1024 * 1024),)
@@ -212,11 +219,13 @@
print traceback.print_exc()
return "error"
+
+
def parseLine(line):
startPos = line.find("- ")
endPos = line.find(" [")
- userId = line[startPos+2:endPos]
+ userId = line[startPos + 2:endPos]
startPos = endPos + 2
endPos = line.find(']', startPos)
@@ -236,7 +245,7 @@
uri = line[startPos:endPos]
startPos = endPos + 11
- status = int(line[startPos:startPos+3])
+ status = int(line[startPos:startPos + 3])
startPos += 4
endPos = line.find(' ', startPos)
@@ -266,16 +275,20 @@
endPos = line.find(' ', startPos)
extended["or"] = int(line[startPos:endPos])
else:
-
+
items = line[startPos:].split()
extended = dict([item.split('=') for item in items if item.find("=") != -1])
return userId, logTime, method, uri, status, bytes, referer, client, extended
+
+
def safePercent(value, total):
-
+
return value * 100.0 / total if total else 0.0
+
+
def usage():
print "request_monitor [OPTIONS] [FILENAME]"
print
@@ -288,6 +301,7 @@
print "--range M:N specifies a range of lines to analyze from access.log (default: all)"
print "--procs N specifies how many python processes are expected in the log file (default: 80)"
print "--top N how many long requests to print (default: 10)"
+ print "--users N how many top users to print (default: 5)"
print "--router analyze a partition server router node"
print "--worker analyze a partition server worker node"
print
@@ -296,10 +310,11 @@
numLines = 10000
numProcs = 80
numTop = 10
+numUsers = 5
lineRange = None
router = False
worker = False
-options, args = getopt.getopt(sys.argv[1:], "h", ["debug", "router", "worker", "lines=", "range=", "procs=", "top="])
+options, args = getopt.getopt(sys.argv[1:], "h", ["debug", "router", "worker", "lines=", "range=", "procs=", "top=", "users="])
for option, value in options:
if option == "-h":
usage()
@@ -318,6 +333,8 @@
numProcs = int(value)
elif option == "--top":
numTop = int(value)
+ elif option == "--users":
+ numUsers = int(value)
if len(args):
filenames = sorted([os.path.expanduser(arg) for arg in args])
@@ -367,7 +384,7 @@
totalOver1s = [0, 0]
totalOver10s = [0, 0]
requests = []
- users = { }
+ users = {}
startTime = None
endTime = None
errorCount = 0
@@ -379,35 +396,35 @@
for line in lines[filename]:
if not line or line.startswith("Log"):
continue
-
+
numRequests[filename] += 1
-
+
try:
userId, logTime, method, uri, status, bytes, _ignore_referer, client, extended = parseLine(line)
except Exception, e:
parseErrors += 1
-
+
if debug:
print "Access log line parse failure", e
print traceback.print_exc()
print "---"
print line
print "---"
-
+
continue
-
+
logTime = dateparse(logTime, fuzzy=True)
times.append(logTime)
perfile_times[filename].append(logTime)
-
+
if status >= 500:
errorCount += 1
-
+
if uri == "/ischedule":
numServerToServer[filename] += 1
elif uri.startswith("/calendars"):
numProxied[filename] += 1
-
+
outstanding = int(extended['or'])
logId = int(extended['i'] if extended['i'] else 0)
raw = rawCounts.get(logId, 0) + 1
@@ -416,7 +433,7 @@
if outstanding > prevMax:
ids[logId] = outstanding
slotCount[filename] += outstanding
-
+
respTime = float(extended['t'])
wrTime = float(extended.get('t-resp-wr', 0.0))
timeSpent = timesSpent.get(logId, 0.0) + respTime
@@ -425,65 +442,63 @@
totalRespWithoutWRTime[filename] += respTime - wrTime
if respTime > maxRespTime[filename]:
maxRespTime[filename] = respTime
-
+
for index, testTime in enumerate((respTime, respTime - wrTime,)):
if testTime >= 60000.0:
over60s[index] += 1
elif testTime >= 30000.0:
- over30s[index] +=1
+ over30s[index] += 1
elif testTime >= 10000.0:
- over10s[index] +=1
+ over10s[index] += 1
elif testTime >= 1000.0:
- over1s[index] +=1
+ over1s[index] += 1
elif testTime >= 100.0:
- over100ms[index] +=1
+ over100ms[index] += 1
elif testTime >= 10.0:
- over10ms[index] +=1
+ over10ms[index] += 1
else:
- under10ms[index] +=1
+ under10ms[index] += 1
if testTime >= 1000.0:
- totalOver1s[index] +=1
+ totalOver1s[index] += 1
if testTime >= 10000.0:
- totalOver10s[index] +=1
-
-
+ totalOver10s[index] += 1
+
ext = []
for key, value in extended.iteritems():
if key not in ('i', 't'):
if key == "cl":
- value = float(value)/1024
+ value = float(value) / 1024
value = "%.1fKB" % (value,)
key = "req"
ext.append("%s:%s" % (key, value))
ext = ", ".join(ext)
-
+
try:
client = client.split(";")[2]
client = client.strip()
except:
pass
-
+
if userId != "-":
- userStat = users.get(userId, { 'count' : 0, 'clients' : {} })
+ userStat = users.get(userId, {'count' : 0, 'clients' : {}})
userStat['count'] += 1
clientCount = userStat['clients'].get(client, 0)
userStat['clients'][client] = clientCount + 1
users[userId] = userStat
-
+
reqStartTime = logTime - datetime.timedelta(milliseconds=respTime)
- requests.append((respTime, userId, method, bytes/1024.0, ext, client, logId, logTime, reqStartTime))
+ requests.append((respTime, userId, method, bytes / 1024.0, ext, client, logId, logTime, reqStartTime))
-
times.sort()
if len(times) == 0:
print "No data to analyze"
time.sleep(10)
continue
-
+
totalRequests = sum(numRequests.values())
print "- " * 40
- print datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S"),
+ print datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S"),
if enableListenQueue:
q, lqssl, lqnon = listenQueueHistory()
print "Listenq (ssl+non):", q[0], " (Recent", ", ".join(q[1:]), "Oldest)"
@@ -497,14 +512,14 @@
table = tables.Table()
table.addHeader(
- ("Instance", "Requests", "Av. Requests", "Av. Response", "Av. Response", "Max. Response", "Slot", "Start", "End", "File Name"),
+ ("Instance", "Requests", "Av. Requests", "Av. Response", "Av. Response", "Max. Response", "Slot", "Start", "End", "File Name"),
)
table.addHeader(
- ( "", "", "per second", "(ms)", "no write(ms)", "(ms)", "Average", "Time", "Time", ""),
+ ("", "", "per second", "(ms)", "no write(ms)", "(ms)", "Average", "Time", "Time", ""),
)
table.setDefaultColumnFormats(
(
- tables.Table.ColumnFormat("%s", tables.Table.ColumnFormat.CENTER_JUSTIFY),
+ tables.Table.ColumnFormat("%s", tables.Table.ColumnFormat.CENTER_JUSTIFY),
tables.Table.ColumnFormat("%d", tables.Table.ColumnFormat.RIGHT_JUSTIFY),
tables.Table.ColumnFormat("%.1f", tables.Table.ColumnFormat.RIGHT_JUSTIFY),
tables.Table.ColumnFormat("%.1f", tables.Table.ColumnFormat.RIGHT_JUSTIFY),
@@ -516,7 +531,7 @@
tables.Table.ColumnFormat("%s", tables.Table.ColumnFormat.RIGHT_JUSTIFY),
)
)
-
+
totalAverage = 0.0
totalResponseTime = 0.0
totalResponseWithoutWRTime = 0.0
@@ -525,14 +540,14 @@
minStartTime = None
maxEndTime = None
for ctr, filename in enumerate(sorted(perfile_times.keys())):
-
+
times = sorted(perfile_times[filename])
startTime = times[0]
minStartTime = startTime if minStartTime is None else min(minStartTime, startTime)
endTime = times[-1]
maxEndTime = endTime if maxEndTime is None else min(maxEndTime, endTime)
-
+
deltaTime = endTime - startTime
avgRequests = float(len(times)) / deltaTime.seconds
@@ -540,16 +555,16 @@
avgResponse = totalRespTime[filename] / len(times)
totalResponseTime += totalRespTime[filename]
-
+
avgResponseWithWR = totalRespWithoutWRTime[filename] / len(times)
totalResponseWithoutWRTime += totalRespWithoutWRTime[filename]
-
+
maxResponseTime = max(maxResponseTime, maxRespTime[filename])
-
+
totalSlots += slotCount[filename]
table.addRow((
- "#%s" % (ctr+1,),
+ "#%s" % (ctr + 1,),
len(times),
avgRequests,
avgResponse,
@@ -560,7 +575,7 @@
endTime,
filename[prefix:],
))
-
+
if len(perfile_times) > 1:
table.addFooter((
"Total:",
@@ -574,7 +589,7 @@
maxEndTime,
"",
))
-
+
os = StringIO()
table.printTable(os=os)
print os.getvalue()
@@ -585,14 +600,14 @@
lqlatency[0],
lqlatency[1],
)
-
+
table = tables.Table()
table.addHeader(
- ("", "<10ms", "10ms<->100ms", "100ms<->1s", "1s<->10s", "10s<->30s", "30s<->60s", ">60s", "Over 1s", "Over 10s"),
+ ("", "<10ms", "10ms<->100ms", "100ms<->1s", "1s<->10s", "10s<->30s", "30s<->60s", ">60s", "Over 1s", "Over 10s"),
)
table.setDefaultColumnFormats(
(
- tables.Table.ColumnFormat("%s", tables.Table.ColumnFormat.CENTER_JUSTIFY),
+ tables.Table.ColumnFormat("%s", tables.Table.ColumnFormat.CENTER_JUSTIFY),
tables.Table.ColumnFormat("%d (%.1f%%)", tables.Table.ColumnFormat.RIGHT_JUSTIFY),
tables.Table.ColumnFormat("%d (%.1f%%)", tables.Table.ColumnFormat.RIGHT_JUSTIFY),
tables.Table.ColumnFormat("%d (%.1f%%)", tables.Table.ColumnFormat.RIGHT_JUSTIFY),
@@ -629,11 +644,11 @@
print
print "Proc: Peak outstanding: Seconds of processing (number of requests):"
- for l in xrange((numProcs-1)/10 + 1):
+ for l in xrange((numProcs - 1) / 10 + 1):
base = l * 10
- print "%2d-%2d: " % (base, base+9),
+ print "%2d-%2d: " % (base, base + 9),
- for i in xrange(base, base+10):
+ for i in xrange(base, base + 10):
try:
r = ids[i]
s = "%1d" % (r,)
@@ -643,16 +658,15 @@
print " ",
- for i in xrange(base, base+10):
+ for i in xrange(base, base + 10):
try:
r = timesSpent[i] / 1000
c = rawCounts[i]
- s = "%4.0f(%4d)" % (r,c)
+ s = "%4.0f(%4d)" % (r, c)
except KeyError:
s = " ."
print s,
-
print
print
@@ -675,16 +689,14 @@
except:
pass
-
-
print
- print "Top 5 busiest users (in most recent %d requests):" % (totalRequests,)
+ print "Top %d busiest users (in most recent %d requests):" % (numUsers, totalRequests,)
userlist = []
for user, userStat in users.iteritems():
userlist.append((userStat['count'], user, userStat))
userlist.sort()
userlist.reverse()
- for i in xrange(5):
+ for i in xrange(numUsers):
try:
count, user, userStat = userlist[i]
print "%3d %-12s " % (count, user),
@@ -701,7 +713,7 @@
pass
print
-
+
# lineRange => do loop only once
if lineRange is not None:
break
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130219/3cdf1b7b/attachment-0001.html>
More information about the calendarserver-changes
mailing list