<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[15069] CalendarServer/trunk</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.calendarserver.org//changeset/15069">15069</a></dd>
<dt>Author</dt> <dd>cdaboo@apple.com</dd>
<dt>Date</dt> <dd>2015-08-26 11:01:05 -0700 (Wed, 26 Aug 2015)</dd>
</dl>
<h3>Log Message</h3>
<pre>Log sync and sync-home separately. Log more detail about POST requests. Include display of method usage in dashboard.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#CalendarServertrunkcalendarserveraccesslogpy">CalendarServer/trunk/calendarserver/accesslog.py</a></li>
<li><a href="#CalendarServertrunkcalendarserverlogAnalysispy">CalendarServer/trunk/calendarserver/logAnalysis.py</a></li>
<li><a href="#CalendarServertrunkcalendarservertoolsdashboardpy">CalendarServer/trunk/calendarserver/tools/dashboard.py</a></li>
<li><a href="#CalendarServertrunkcontribtoolsprotocolanalysispy">CalendarServer/trunk/contrib/tools/protocolanalysis.py</a></li>
<li><a href="#CalendarServertrunktwistedcaldavmethodpostpy">CalendarServer/trunk/twistedcaldav/method/post.py</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="CalendarServertrunkcalendarserveraccesslogpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/calendarserver/accesslog.py (15068 => 15069)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/calendarserver/accesslog.py        2015-08-26 17:25:45 UTC (rev 15068)
+++ CalendarServer/trunk/calendarserver/accesslog.py        2015-08-26 18:01:05 UTC (rev 15069)
</span><span class="lines">@@ -493,6 +493,8 @@
</span><span class="cx"> current["user-agent"][adjustedClient] += 1
</span><span class="cx"> if stats["statusCode"] >= 500:
</span><span class="cx"> current["500"] += 1
</span><ins>+ elif stats["statusCode"] == 401:
+ current["401"] += 1
</ins><span class="cx"> current["t"] += stats.get("t", 0.0)
</span><span class="cx"> current["t-resp-wr"] += stats.get("t-resp-wr", 0.0)
</span><span class="cx"> current["slots"] += stats.get("outstandingRequests", 0)
</span></span></pre></div>
<a id="CalendarServertrunkcalendarserverlogAnalysispy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/calendarserver/logAnalysis.py (15068 => 15069)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/calendarserver/logAnalysis.py        2015-08-26 17:25:45 UTC (rev 15068)
+++ CalendarServer/trunk/calendarserver/logAnalysis.py        2015-08-26 18:01:05 UTC (rev 15069)
</span><span class="lines">@@ -36,10 +36,12 @@
</span><span class="cx"> METHOD_REPORT_CALENDAR_MULTIGET = "REPORT cal-multi"
</span><span class="cx"> METHOD_REPORT_CALENDAR_QUERY = "REPORT cal-query"
</span><span class="cx"> METHOD_REPORT_CALENDAR_FREEBUSY = "REPORT freebusy"
</span><ins>+METHOD_REPORT_CALENDAR_HOME_SYNC = "REPORT cal-home-sync"
</ins><span class="cx"> METHOD_REPORT_CALENDAR_SYNC = "REPORT cal-sync"
</span><span class="cx"> METHOD_REPORT_ADDRESSBOOK_MULTIGET = "REPORT adbk-multi"
</span><span class="cx"> METHOD_REPORT_ADDRESSBOOK_QUERY = "REPORT adbk-query"
</span><span class="cx"> METHOD_REPORT_DIRECTORY_QUERY = "REPORT dir-query"
</span><ins>+METHOD_REPORT_ADDRESSBOOK_HOME_SYNC = "REPORT adbk-home-sync"
</ins><span class="cx"> METHOD_REPORT_ADDRESSBOOK_SYNC = "REPORT adbk-sync"
</span><span class="cx"> METHOD_REPORT_P_SEARCH_P_SET = "REPORT p-set"
</span><span class="cx"> METHOD_REPORT_P_P_SEARCH = "REPORT p-search"
</span><span class="lines">@@ -48,9 +50,15 @@
</span><span class="cx"> # POSTs
</span><span class="cx"> METHOD_POST_CALENDAR_HOME = "POST Calendar Home"
</span><span class="cx"> METHOD_POST_CALENDAR = "POST Calendar"
</span><del>-METHOD_POST_CALENDAR_OBJECT = "POST Calendar Object"
</del><ins>+METHOD_POST_CALENDAR_ADD_MEMBER = "POST Calendar-add"
+METHOD_POST_CALENDAR_OBJECT = "POST ics"
+METHOD_POST_CALENDAR_OBJECT_SPLIT = "POST split"
+METHOD_POST_CALENDAR_OBJECT_ATTACHMENT_ADD = "POST att-add"
+METHOD_POST_CALENDAR_OBJECT_ATTACHMENT_UPDATE = "POST att-update"
+METHOD_POST_CALENDAR_OBJECT_ATTACHMENT_REMOVE = "POST att-remove"
</ins><span class="cx"> METHOD_POST_ADDRESSBOOK_HOME = "POST Adbk Home"
</span><span class="cx"> METHOD_POST_ADDRESSBOOK = "POST Adbk"
</span><ins>+METHOD_POST_ADDRESSBOOK_ADD_MEMBER = "POST Adbk-add"
</ins><span class="cx"> METHOD_POST_ISCHEDULE_FREEBUSY = "POST Freebusy iSchedule"
</span><span class="cx"> METHOD_POST_ISCHEDULE = "POST iSchedule"
</span><span class="cx"> METHOD_POST_TIMEZONES = "POST Timezones"
</span><span class="lines">@@ -89,12 +97,15 @@
</span><span class="cx"> METHOD_DELETE_VCF = "DELETE vcf"
</span><span class="cx">
</span><span class="cx">
</span><del>-def getAdjustedMethodName(stats):
</del><ins>+def getAdjustedMethodName(stats, method=None, uri=None):
</ins><span class="cx">
</span><del>- method = stats["method"]
- uribits = stats["uri"].rstrip("/").split('/')[1:]
</del><ins>+ if method is None:
+ method = stats["method"]
+ if uri is None:
+ uri = stats["uri"]
+ uribits = uri.rstrip("/").split('/')[1:]
</ins><span class="cx"> if len(uribits) == 0:
</span><del>- uribits = [stats["uri"]]
</del><ins>+ uribits = [uri]
</ins><span class="cx">
</span><span class="cx"> calendar_specials = ("attachments", "dropbox", "notification", "freebusy", "outbox",)
</span><span class="cx"> adbk_specials = ("notification",)
</span><span class="lines">@@ -143,17 +154,25 @@
</span><span class="cx"> report_type = "directory-query"
</span><span class="cx"> if report_type == "sync-collection":
</span><span class="cx"> if uribits[0] == "calendars":
</span><del>- report_type = "cal-sync"
</del><ins>+ if len(uribits) == 3:
+ report_type = "cal-home-sync"
+ else:
+ report_type = "cal-sync"
</ins><span class="cx"> elif uribits[0] == "addressbooks":
</span><del>- report_type = "adbk-sync"
</del><ins>+ if len(uribits) == 3:
+ report_type = "adbk-home-sync"
+ else:
+ report_type = "adbk-sync"
</ins><span class="cx"> mappedNames = {
</span><span class="cx"> "calendar-multiget" : METHOD_REPORT_CALENDAR_MULTIGET,
</span><span class="cx"> "calendar-query" : METHOD_REPORT_CALENDAR_QUERY,
</span><span class="cx"> "free-busy-query" : METHOD_REPORT_CALENDAR_FREEBUSY,
</span><ins>+ "cal-home-sync" : METHOD_REPORT_CALENDAR_HOME_SYNC,
</ins><span class="cx"> "cal-sync" : METHOD_REPORT_CALENDAR_SYNC,
</span><span class="cx"> "addressbook-multiget" : METHOD_REPORT_ADDRESSBOOK_MULTIGET,
</span><span class="cx"> "addressbook-query" : METHOD_REPORT_ADDRESSBOOK_QUERY,
</span><span class="cx"> "directory-query" : METHOD_REPORT_DIRECTORY_QUERY,
</span><ins>+ "adbk-home-sync" : METHOD_REPORT_ADDRESSBOOK_HOME_SYNC,
</ins><span class="cx"> "adbk-sync" : METHOD_REPORT_ADDRESSBOOK_SYNC,
</span><span class="cx"> "principal-search-property-set" : METHOD_REPORT_P_SEARCH_P_SET,
</span><span class="cx"> "principal-property-search" : METHOD_REPORT_P_P_SEARCH,
</span><span class="lines">@@ -178,7 +197,18 @@
</span><span class="cx">
</span><span class="cx"> if uribits[0] == "calendars":
</span><span class="cx">
</span><del>- if len(uribits) == 3:
</del><ins>+ if "(" in method:
+ post_type = method.split("(")[1][:-1]
+ mappedNames = {
+ "add-member" : METHOD_POST_CALENDAR_ADD_MEMBER,
+ "split" : METHOD_POST_CALENDAR_OBJECT_SPLIT,
+ "attachment-add" : METHOD_POST_CALENDAR_OBJECT_ATTACHMENT_ADD,
+ "attachment-update" : METHOD_POST_CALENDAR_OBJECT_ATTACHMENT_UPDATE,
+ "attachment-remove" : METHOD_POST_CALENDAR_OBJECT_ATTACHMENT_REMOVE,
+ }
+ return mappedNames.get(post_type, "POST %s" % (post_type,))
+
+ elif len(uribits) == 3:
</ins><span class="cx"> return METHOD_POST_CALENDAR_HOME
</span><span class="cx"> elif len(uribits) == 4:
</span><span class="cx"> if uribits[3] == "outbox":
</span><span class="lines">@@ -334,6 +364,7 @@
</span><span class="cx">
</span><span class="cx"> osClients = (
</span><span class="cx"> "Mac OS X/",
</span><ins>+ "Mac+OS+X/",
</ins><span class="cx"> "Mac_OS_X/",
</span><span class="cx"> "iOS/",
</span><span class="cx"> )
</span></span></pre></div>
<a id="CalendarServertrunkcalendarservertoolsdashboardpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/calendarserver/tools/dashboard.py (15068 => 15069)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/calendarserver/tools/dashboard.py        2015-08-26 17:25:45 UTC (rev 15068)
+++ CalendarServer/trunk/calendarserver/tools/dashboard.py        2015-08-26 18:01:05 UTC (rev 15069)
</span><span class="lines">@@ -195,6 +195,7 @@
</span><span class="cx"> self.displayWindow(self.registered_windows["h"])
</span><span class="cx">
</span><span class="cx"> self.resetWindows()
</span><ins>+
</ins><span class="cx"> # Reset the screen to the default config
</span><span class="cx"> else:
</span><span class="cx"> if self.windows:
</span><span class="lines">@@ -209,15 +210,18 @@
</span><span class="cx"> self.windows.append(wtype(self.usesCurses, self.client).makeWindow(top=top))
</span><span class="cx"> self.windows[-1].activate()
</span><span class="cx"> top += self.windows[-1].nlines + 1
</span><ins>+
</ins><span class="cx"> # Don't display help panel if the window is too narrow
</span><del>- term_w, term_h = terminal_size()
- logging.debug("logger displayWindow: rows: %s cols: %s" % (term_h, term_w))
- if int(term_w) > 100:
- logging.debug('term_w > 100, making window with top at %d' % (top))
- self.windows.append(HelpWindow(self.usesCurses, self.client).makeWindow(top=top))
- self.windows[-1].activate()
</del><ins>+ if self.usesCurses:
+ term_w, term_h = terminal_size()
+ logging.debug("logger displayWindow: rows: %s cols: %s" % (term_h, term_w))
+ if int(term_w) > 100:
+ logging.debug('term_w > 100, making window with top at %d' % (top))
+ self.windows.append(HelpWindow(self.usesCurses, self.client).makeWindow(top=top))
+ self.windows[-1].activate()
</ins><span class="cx">
</span><del>- curses.panel.update_panels()
</del><ins>+ if self.usesCurses:
+ curses.panel.update_panels()
</ins><span class="cx"> self.updateDisplay(True)
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -350,7 +354,8 @@
</span><span class="cx"> Update the current data from the server.
</span><span class="cx"> """
</span><span class="cx">
</span><del>- self.currentData = self.readSock(self.items)
</del><ins>+ # Only read each item once
+ self.currentData = self.readSock(list(set(self.items)))
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def getOneItem(self, item):
</span><span class="lines">@@ -513,6 +518,9 @@
</span><span class="cx"> x = 1
</span><span class="cx"> y = 1
</span><span class="cx">
</span><ins>+ if not self.usesCurses:
+ print("------------ {}".format(self.title))
+
</ins><span class="cx"> items = []
</span><span class="cx"> for keypress, wtype in sorted(
</span><span class="cx"> Dashboard.registered_windows.items(), key=lambda x: x[0]
</span><span class="lines">@@ -526,6 +534,9 @@
</span><span class="cx"> print(item)
</span><span class="cx"> y += 1
</span><span class="cx">
</span><ins>+ if not self.usesCurses:
+ print("")
+
</ins><span class="cx"> if self.usesCurses:
</span><span class="cx"> self.window.refresh()
</span><span class="cx">
</span><span class="lines">@@ -574,6 +585,7 @@
</span><span class="cx"> self.window.addstr(y, x, s1, curses.A_REVERSE)
</span><span class="cx"> self.window.addstr(y + 1, x, s2, curses.A_REVERSE)
</span><span class="cx"> else:
</span><ins>+ print("------------ {}".format(self.title))
</ins><span class="cx"> print(s1)
</span><span class="cx"> print(s2)
</span><span class="cx"> y += 2
</span><span class="lines">@@ -633,6 +645,7 @@
</span><span class="cx"> self.window.addstr(y, x, s)
</span><span class="cx"> else:
</span><span class="cx"> print(s)
</span><ins>+ print("")
</ins><span class="cx"> y += 1
</span><span class="cx">
</span><span class="cx"> if self.usesCurses:
</span><span class="lines">@@ -685,6 +698,7 @@
</span><span class="cx"> if self.usesCurses:
</span><span class="cx"> self.window.addstr(y, x, s, curses.A_REVERSE)
</span><span class="cx"> else:
</span><ins>+ print("------------ {}".format(self.title))
</ins><span class="cx"> print(s)
</span><span class="cx"> y += 1
</span><span class="cx"> total_assigned = 0
</span><span class="lines">@@ -727,6 +741,7 @@
</span><span class="cx"> self.window.addstr(y, x, s)
</span><span class="cx"> else:
</span><span class="cx"> print(s)
</span><ins>+ print("")
</ins><span class="cx"> y += 1
</span><span class="cx">
</span><span class="cx"> if self.usesCurses:
</span><span class="lines">@@ -780,6 +795,7 @@
</span><span class="cx"> if self.usesCurses:
</span><span class="cx"> self.window.addstr(y, x, s, curses.A_REVERSE)
</span><span class="cx"> else:
</span><ins>+ print("------------ {}".format(self.title))
</ins><span class="cx"> print(s)
</span><span class="cx"> y += 1
</span><span class="cx"> for record in sorted(records, key=lambda x: x["slot"]):
</span><span class="lines">@@ -837,6 +853,7 @@
</span><span class="cx"> if data["overloaded"]:
</span><span class="cx"> s += " OVERLOADED"
</span><span class="cx"> print(s)
</span><ins>+ print("")
</ins><span class="cx"> y += 1
</span><span class="cx">
</span><span class="cx"> if self.usesCurses:
</span><span class="lines">@@ -887,6 +904,7 @@
</span><span class="cx"> if self.usesCurses:
</span><span class="cx"> self.window.addstr(y, x, s, curses.A_REVERSE)
</span><span class="cx"> else:
</span><ins>+ print("------------ {}".format(self.title))
</ins><span class="cx"> print(s)
</span><span class="cx"> y += 1
</span><span class="cx">
</span><span class="lines">@@ -917,6 +935,9 @@
</span><span class="cx"> pass
</span><span class="cx"> y += 1
</span><span class="cx">
</span><ins>+ if not self.usesCurses:
+ print("")
+
</ins><span class="cx"> if self.usesCurses:
</span><span class="cx"> self.window.refresh()
</span><span class="cx">
</span><span class="lines">@@ -959,6 +980,7 @@
</span><span class="cx"> self.window.addstr(y, x, s1, curses.A_REVERSE)
</span><span class="cx"> self.window.addstr(y + 1, x, s2, curses.A_REVERSE)
</span><span class="cx"> else:
</span><ins>+ print("------------ {}".format(self.title))
</ins><span class="cx"> print(s1)
</span><span class="cx"> print(s2)
</span><span class="cx"> y += 2
</span><span class="lines">@@ -992,6 +1014,9 @@
</span><span class="cx"> pass
</span><span class="cx"> y += 1
</span><span class="cx">
</span><ins>+ if not self.usesCurses:
+ print("")
+
</ins><span class="cx"> if self.usesCurses:
</span><span class="cx"> self.window.refresh()
</span><span class="cx">
</span><span class="lines">@@ -999,6 +1024,128 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><ins>+class MethodsWindow(BaseWindow):
+ """
+ Display the status of the server's request methods.
+ """
+
+ help = "server methods"
+ clientItem = "stats"
+ FORMAT_WIDTH = 116
+ stats_keys = ("current", "1m", "5m", "1h",)
+
+ def makeWindow(self, top=0, left=0):
+ stats = defaultIfNone(self.clientData(), {})
+ methods = set()
+ for key in self.stats_keys:
+ methods.update(stats.get(key, {}).get("method", {}).keys())
+ nlines = len(methods)
+ self.rowCount = nlines
+ self._createWindow("Methods", self.rowCount + 7, ncols=self.FORMAT_WIDTH, begin_y=top, begin_x=left)
+ return self
+
+
+ def update(self):
+ stats = defaultIfNone(self.clientData(), {})
+ methods = set()
+ for key in self.stats_keys:
+ methods.update(stats.get(key, {}).get("method", {}).keys())
+
+ records = {}
+ records_t = {}
+ for key in self.stats_keys:
+ records[key] = defaultIfNone(self.clientData(), {}).get(key, {}).get("method", {})
+ records_t[key] = defaultIfNone(self.clientData(), {}).get(key, {}).get("method-t", {})
+ self.iter += 1
+
+ if self.usesCurses:
+ self.window.erase()
+ self.window.border()
+ self.window.addstr(
+ 0, 2,
+ self.title + " {} ({})".format(len(records), self.iter)
+ )
+
+ x = 1
+ y = 1
+ s1 = " {:<40}{:>8}{:>10}{:>8}{:>10}{:>8}{:>10}{:>8}{:>10} ".format(
+ "", "------", "current---", "------", "1m--------", "------", "5m--------", "------", "1h--------",
+ )
+ s2 = " {:<40}{:>8}{:>10}{:>8}{:>10}{:>8}{:>10}{:>8}{:>10} ".format(
+ "Method", "Number", "Av-Time", "Number", "Av-Time", "Number", "Av-Time", "Number", "Av-Time",
+ )
+ s3 = " {:<40}{:>8}{:>10}{:>8}{:>10}{:>8}{:>10}{:>8}{:>10} ".format(
+ "", "", "(ms)", "", "(ms)", "", "(ms)", "", "(ms)",
+ )
+ if self.usesCurses:
+ self.window.addstr(y, x, s1, curses.A_REVERSE)
+ self.window.addstr(y + 1, x, s2, curses.A_REVERSE)
+ self.window.addstr(y + 2, x, s3, curses.A_REVERSE)
+ else:
+ print("------------ {}".format(self.title))
+ print(s1)
+ print(s2)
+ print(s3)
+ y += 2
+ total_methods = dict([(key, 0) for key in self.stats_keys])
+ total_time = dict([(key, 0.0) for key in self.stats_keys])
+ for method_type in sorted(methods):
+ for key in self.stats_keys:
+ total_methods[key] += records[key].get(method_type, 0)
+ total_time[key] += records_t[key].get(method_type, 0.0)
+ changed = self.lastResult.get(method_type, 0) != records["current"].get(method_type, 0)
+ items = [method_type]
+ for key in self.stats_keys:
+ items.append(records[key].get(method_type, 0))
+ items.append(safeDivision(records_t[key].get(method_type, 0), records[key].get(method_type, 0)))
+ s = " {:<40}{:>8}{:>10.1f}{:>8}{:>10.1f}{:>8}{:>10.1f}{:>8}{:>10.1f} ".format(
+ *items
+ )
+ try:
+ if self.usesCurses:
+ self.window.addstr(
+ y, x, s,
+ curses.A_REVERSE if changed else curses.A_NORMAL,
+ )
+ else:
+ print(s)
+ except curses.error:
+ pass
+ y += 1
+
+ items = ["Total:"]
+ for key in self.stats_keys:
+ items.append(total_methods[key])
+ items.append(safeDivision(total_time[key], total_methods[key]))
+ s1 = " {:<40}{:>8}{:>10.1f}{:>8}{:>10.1f}{:>8}{:>10.1f}{:>8}{:>10.1f} ".format(
+ *items
+ )
+ items = ["401s:"]
+ for key in self.stats_keys:
+ items.append(defaultIfNone(self.clientData(), {}).get(key, {}).get("401", 0))
+ items.append("")
+ s2 = " {:<40}{:>8}{:>10}{:>8}{:>10}{:>8}{:>10}{:>8}{:>10} ".format(
+ *items
+ )
+ if self.usesCurses:
+ self.window.hline(y, x, "-", self.FORMAT_WIDTH - 2)
+ y += 1
+ self.window.addstr(y, x, s1)
+ y += 1
+ self.window.addstr(y, x, s2)
+ else:
+ print(s1)
+ print(s2)
+ print("")
+ y += 1
+
+ if self.usesCurses:
+ self.window.refresh()
+
+ self.lastResult = defaultIfNone(self.clientData(), {}).get("current", {}).get("method", {})
+
+
+
</ins><span class="cx"> class DirectoryStatsWindow(BaseWindow):
</span><span class="cx"> """
</span><span class="cx"> Displays the status of the server's directory service calls
</span><span class="lines">@@ -1044,6 +1191,7 @@
</span><span class="cx"> self.window.addstr(y, x, s1, curses.A_REVERSE)
</span><span class="cx"> self.window.addstr(y + 1, x, s2, curses.A_REVERSE)
</span><span class="cx"> else:
</span><ins>+ print("------------ {}".format(self.title))
</ins><span class="cx"> print(s1)
</span><span class="cx"> print(s2)
</span><span class="cx"> y += 2
</span><span class="lines">@@ -1111,6 +1259,7 @@
</span><span class="cx"> print(s)
</span><span class="cx"> print(s1)
</span><span class="cx"> print(s2)
</span><ins>+ print("")
</ins><span class="cx"> y += 3
</span><span class="cx">
</span><span class="cx"> if self.usesCurses:
</span><span class="lines">@@ -1122,6 +1271,7 @@
</span><span class="cx"> Dashboard.registerWindow(SystemWindow, "s")
</span><span class="cx"> Dashboard.registerWindow(AssignmentsWindow, "w")
</span><span class="cx"> Dashboard.registerWindow(RequestStatsWindow, "r")
</span><ins>+Dashboard.registerWindow(MethodsWindow, "m")
</ins><span class="cx"> Dashboard.registerWindow(JobsWindow, "j")
</span><span class="cx"> Dashboard.registerWindow(HTTPSlotsWindow, "c")
</span><span class="cx"> Dashboard.registerWindow(DirectoryStatsWindow, "d")
</span></span></pre></div>
<a id="CalendarServertrunkcontribtoolsprotocolanalysispy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/contrib/tools/protocolanalysis.py (15068 => 15069)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/contrib/tools/protocolanalysis.py        2015-08-26 17:25:45 UTC (rev 15068)
+++ CalendarServer/trunk/contrib/tools/protocolanalysis.py        2015-08-26 18:01:05 UTC (rev 15069)
</span><span class="lines">@@ -26,6 +26,13 @@
</span><span class="cx"> import tables
</span><span class="cx"> import traceback
</span><span class="cx"> import glob
</span><ins>+from calendarserver.logAnalysis import getAdjustedMethodName, METHOD_PUT_ICS, \
+ METHOD_PUT_ORGANIZER, METHOD_PUT_ATTENDEE, METHOD_PROPFIND_CALENDAR, \
+ METHOD_POST_FREEBUSY, METHOD_POST_ORGANIZER, METHOD_POST_ISCHEDULE_FREEBUSY, \
+ METHOD_POST_ISCHEDULE, METHOD_GET_DROPBOX, METHOD_PROPFIND_CALENDAR_HOME, \
+ METHOD_PROPFIND_CACHED_CALENDAR_HOME, METHOD_PROPFIND_ADDRESSBOOK_HOME, \
+ METHOD_PROPFIND_CACHED_ADDRESSBOOK_HOME, METHOD_PROPFIND_PRINCIPALS, \
+ METHOD_PROPFIND_CACHED_PRINCIPALS
</ins><span class="cx">
</span><span class="cx"> def safePercent(x, y, multiplier=100):
</span><span class="cx"> return ((multiplier * x) / y) if y else 0
</span><span class="lines">@@ -114,79 +121,6 @@
</span><span class="cx"> "SEARCH",
</span><span class="cx"> ))
</span><span class="cx">
</span><del>-# Adjust method names
-
-# PROPFINDs
-METHOD_PROPFIND_CALENDAR_HOME = "PROPFIND Calendar Home"
-METHOD_PROPFIND_CACHED_CALENDAR_HOME = "PROPFIND cached Calendar Home"
-METHOD_PROPFIND_CALENDAR = "PROPFIND Calendar"
-METHOD_PROPFIND_INBOX = "PROPFIND Inbox"
-METHOD_PROPFIND_ADDRESSBOOK_HOME = "PROPFIND Adbk Home"
-METHOD_PROPFIND_CACHED_ADDRESSBOOK_HOME = "PROPFIND cached Adbk Home"
-METHOD_PROPFIND_ADDRESSBOOK = "PROPFIND Adbk"
-METHOD_PROPFIND_DIRECTORY = "PROPFIND Directory"
-METHOD_PROPFIND_PRINCIPALS = "PROPFIND Principals"
-METHOD_PROPFIND_CACHED_PRINCIPALS = "PROPFIND cached Principals"
-
-# PROPPATCHs
-METHOD_PROPPATCH_CALENDAR = "PROPPATCH Calendar"
-METHOD_PROPPATCH_ADDRESSBOOK = "PROPPATCH Adbk Home"
-
-# REPORTs
-METHOD_REPORT_CALENDAR_MULTIGET = "REPORT cal-multi"
-METHOD_REPORT_CALENDAR_QUERY = "REPORT cal-query"
-METHOD_REPORT_CALENDAR_FREEBUSY = "REPORT freebusy"
-METHOD_REPORT_CALENDAR_SYNC = "REPORT cal-sync"
-METHOD_REPORT_ADDRESSBOOK_MULTIGET = "REPORT adbk-multi"
-METHOD_REPORT_ADDRESSBOOK_QUERY = "REPORT adbk-query"
-METHOD_REPORT_DIRECTORY_QUERY = "REPORT dir-query"
-METHOD_REPORT_ADDRESSBOOK_SYNC = "REPORT adbk-sync"
-METHOD_REPORT_P_SEARCH_P_SET = "REPORT p-set"
-METHOD_REPORT_P_P_SEARCH = "REPORT p-search"
-METHOD_REPORT_EXPAND_P = "REPORT expand"
-
-# POSTs
-METHOD_POST_CALENDAR_HOME = "POST Calendar Home"
-METHOD_POST_CALENDAR = "POST Calendar"
-METHOD_POST_ADDRESSBOOK_HOME = "POST Adbk Home"
-METHOD_POST_ADDRESSBOOK = "POST Adbk"
-METHOD_POST_ISCHEDULE_FREEBUSY = "POST Freebusy iSchedule"
-METHOD_POST_ISCHEDULE = "POST iSchedule"
-METHOD_POST_TIMEZONES = "POST Timezones"
-METHOD_POST_FREEBUSY = "POST Freebusy"
-METHOD_POST_ORGANIZER = "POST Organizer"
-METHOD_POST_ATTENDEE = "POST Attendee"
-METHOD_POST_OUTBOX = "POST Outbox"
-METHOD_POST_APNS = "POST apns"
-
-# PUTs
-METHOD_PUT_ICS = "PUT ics"
-METHOD_PUT_ORGANIZER = "PUT Organizer"
-METHOD_PUT_ATTENDEE = "PUT Attendee"
-METHOD_PUT_DROPBOX = "PUT dropbox"
-METHOD_PUT_VCF = "PUT VCF"
-
-# GETs
-METHOD_GET_CALENDAR_HOME = "GET Calendar Home"
-METHOD_GET_CALENDAR = "GET Calendar"
-METHOD_GET_ICS = "GET ics"
-METHOD_GET_INBOX_ICS = "GET inbox ics"
-METHOD_GET_DROPBOX = "GET dropbox"
-METHOD_GET_ADDRESSBOOK_HOME = "GET Adbk Home"
-METHOD_GET_ADDRESSBOOK = "GET Adbk"
-METHOD_GET_VCF = "GET VCF"
-METHOD_GET_TIMEZONES = "GET Timezones"
-
-# DELETEs
-METHOD_DELETE_CALENDAR_HOME = "DELETE Calendar Home"
-METHOD_DELETE_CALENDAR = "DELETE Calendar"
-METHOD_DELETE_ICS = "DELETE ics"
-METHOD_DELETE_INBOX_ICS = "DELETE inbox ics"
-METHOD_DELETE_DROPBOX = "DELETE dropbox"
-METHOD_DELETE_ADDRESSBOOK_HOME = "DELETE Adbk Home"
-METHOD_DELETE_ADDRESSBOOK = "DELETE Adbk"
-METHOD_DELETE_VCF = "DELETE vcf"
-
</del><span class="cx"> # 401s
</span><span class="cx"> METHOD_401 = "Z 401s"
</span><span class="cx">
</span><span class="lines">@@ -332,7 +266,7 @@
</span><span class="cx"> continue
</span><span class="cx">
</span><span class="cx"> # Filter method
</span><del>- if self.ignoreNonHTTPMethods and not self.currentLine.method.startswith("REPORT(") and self.currentLine.method not in httpMethods:
</del><ins>+ if self.ignoreNonHTTPMethods and not self.currentLine.method.startswith("REPORT(") and not self.currentLine.method.startswith("POST(") and self.currentLine.method not in httpMethods:
</ins><span class="cx"> self.currentLine.method = "???"
</span><span class="cx">
</span><span class="cx"> # Do hour ranges
</span><span class="lines">@@ -674,213 +608,9 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def getAdjustedMethodName(self):
</span><ins>+ return getAdjustedMethodName(self.currentLine.extended, self.currentLine.method, self.currentLine.uri)
</ins><span class="cx">
</span><del>- uribits = self.currentLine.uri.rstrip("/").split('/')[1:]
- if len(uribits) == 0:
- uribits = [self.currentLine.uri]
</del><span class="cx">
</span><del>- calendar_specials = ("dropbox", "notification", "freebusy", "outbox",)
- adbk_specials = ("notification",)
-
- if self.currentLine.method == "PROPFIND":
-
- cached = "cached" in self.currentLine.extended
-
- if uribits[0] == "calendars":
-
- if len(uribits) == 3:
- return METHOD_PROPFIND_CACHED_CALENDAR_HOME if cached else METHOD_PROPFIND_CALENDAR_HOME
- elif len(uribits) > 3:
- if uribits[3] in calendar_specials:
- return "PROPFIND %s" % (uribits[3],)
- elif len(uribits) == 4:
- if uribits[3] == "inbox":
- return METHOD_PROPFIND_INBOX
- else:
- return METHOD_PROPFIND_CALENDAR
-
- elif uribits[0] == "addressbooks":
-
- if len(uribits) == 3:
- return METHOD_PROPFIND_CACHED_ADDRESSBOOK_HOME if cached else METHOD_PROPFIND_ADDRESSBOOK_HOME
- elif len(uribits) > 3:
- if uribits[3] in adbk_specials:
- return "PROPFIND %s" % (uribits[3],)
- elif len(uribits) == 4:
- return METHOD_PROPFIND_ADDRESSBOOK
-
- elif uribits[0] == "directory":
- return METHOD_PROPFIND_DIRECTORY
-
- elif uribits[0] == "principals":
- return METHOD_PROPFIND_CACHED_PRINCIPALS if cached else METHOD_PROPFIND_PRINCIPALS
-
- elif self.currentLine.method.startswith("REPORT"):
-
- if "(" in self.currentLine.method:
- report_type = self.currentLine.method.split("}" if "}" in self.currentLine.method else ":")[1][:-1]
- if report_type == "addressbook-query":
- if uribits[0] == "directory":
- report_type = "directory-query"
- if report_type == "sync-collection":
- if uribits[0] == "calendars":
- report_type = "cal-sync"
- elif uribits[0] == "addressbooks":
- report_type = "adbk-sync"
- mappedNames = {
- "calendar-multiget" : METHOD_REPORT_CALENDAR_MULTIGET,
- "calendar-query" : METHOD_REPORT_CALENDAR_QUERY,
- "free-busy-query" : METHOD_REPORT_CALENDAR_FREEBUSY,
- "cal-sync" : METHOD_REPORT_CALENDAR_SYNC,
- "addressbook-multiget" : METHOD_REPORT_ADDRESSBOOK_MULTIGET,
- "addressbook-query" : METHOD_REPORT_ADDRESSBOOK_QUERY,
- "directory-query" : METHOD_REPORT_DIRECTORY_QUERY,
- "adbk-sync" : METHOD_REPORT_ADDRESSBOOK_SYNC,
- "principal-search-property-set" : METHOD_REPORT_P_SEARCH_P_SET,
- "principal-property-search" : METHOD_REPORT_P_P_SEARCH,
- "expand-property" : METHOD_REPORT_EXPAND_P,
- }
- return mappedNames.get(report_type, "REPORT %s" % (report_type,))
-
- elif self.currentLine.method == "PROPPATCH":
-
- if uribits[0] == "calendars":
- return METHOD_PROPPATCH_CALENDAR
- elif uribits[0] == "addressbooks":
- return METHOD_PROPPATCH_ADDRESSBOOK
-
- elif self.currentLine.method == "POST":
-
- if uribits[0] == "calendars":
-
- if len(uribits) == 3:
- return METHOD_POST_CALENDAR_HOME
- elif len(uribits) == 4:
- if uribits[3] == "outbox":
- if "recipients" in self.currentLine.extended:
- return METHOD_POST_FREEBUSY
- elif "freebusy" in self.currentLine.extended:
- return METHOD_POST_FREEBUSY
- elif "itip.request" in self.currentLine.extended or "itip.cancel" in self.currentLine.extended:
- return METHOD_POST_ORGANIZER
- elif "itip.reply" in self.currentLine.extended:
- return METHOD_POST_ATTENDEE
- else:
- return METHOD_POST_OUTBOX
- elif uribits[3] in calendar_specials:
- pass
- else:
- return METHOD_POST_CALENDAR
-
- elif uribits[0] == "addressbooks":
-
- if len(uribits) == 3:
- return METHOD_POST_ADDRESSBOOK_HOME
- elif len(uribits) == 4:
- if uribits[3] in adbk_specials:
- pass
- else:
- return METHOD_POST_ADDRESSBOOK
-
- elif uribits[0] == "ischedule":
- if "fb-cached" in self.currentLine.extended or "fb-uncached" in self.currentLine.extended or "freebusy" in self.currentLine.extended:
- return METHOD_POST_ISCHEDULE_FREEBUSY
- else:
- return METHOD_POST_ISCHEDULE
-
- elif uribits[0].startswith("timezones"):
- return METHOD_POST_TIMEZONES
-
- elif uribits[0].startswith("apns"):
- return METHOD_POST_APNS
-
- elif self.currentLine.method == "PUT":
-
- if uribits[0] == "calendars":
- if len(uribits) > 3:
- if uribits[3] in calendar_specials:
- return "PUT %s" % (uribits[3],)
- elif len(uribits) == 4:
- pass
- else:
- if "itip.requests" in self.currentLine.extended:
- return METHOD_PUT_ORGANIZER
- elif "itip.reply" in self.currentLine.extended:
- return METHOD_PUT_ATTENDEE
- else:
- return METHOD_PUT_ICS
-
- elif uribits[0] == "addressbooks":
- if len(uribits) > 3:
- if uribits[3] in adbk_specials:
- return "PUT %s" % (uribits[3],)
- elif len(uribits) == 4:
- pass
- else:
- return METHOD_PUT_VCF
-
- elif self.currentLine.method == "GET":
-
- if uribits[0] == "calendars":
-
- if len(uribits) == 3:
- return METHOD_GET_CALENDAR_HOME
- elif len(uribits) > 3:
- if uribits[3] in calendar_specials:
- return "GET %s" % (uribits[3],)
- elif len(uribits) == 4:
- return METHOD_GET_CALENDAR
- elif uribits[3] == "inbox":
- return METHOD_GET_INBOX_ICS
- else:
- return METHOD_GET_ICS
-
- elif uribits[0] == "addressbooks":
-
- if len(uribits) == 3:
- return METHOD_GET_ADDRESSBOOK_HOME
- elif len(uribits) > 3:
- if uribits[3] in adbk_specials:
- return "GET %s" % (uribits[3],)
- elif len(uribits) == 4:
- return METHOD_GET_ADDRESSBOOK
- else:
- return METHOD_GET_VCF
-
- elif uribits[0].startswith("timezones"):
- return METHOD_GET_TIMEZONES
-
- elif self.currentLine.method == "DELETE":
-
- if uribits[0] == "calendars":
-
- if len(uribits) == 3:
- return METHOD_DELETE_CALENDAR_HOME
- elif len(uribits) > 3:
- if uribits[3] in calendar_specials:
- return "DELETE %s" % (uribits[3],)
- elif len(uribits) == 4:
- return METHOD_DELETE_CALENDAR
- elif uribits[3] == "inbox":
- return METHOD_DELETE_INBOX_ICS
- else:
- return METHOD_DELETE_ICS
-
- elif uribits[0] == "addressbooks":
-
- if len(uribits) == 3:
- return METHOD_DELETE_ADDRESSBOOK_HOME
- elif len(uribits) > 3:
- if uribits[3] in adbk_specials:
- return "DELETE %s" % (uribits[3],)
- elif len(uribits) == 4:
- return METHOD_DELETE_ADDRESSBOOK
- else:
- return METHOD_DELETE_VCF
-
- return self.currentLine.method
-
-
</del><span class="cx"> def getCountBucket(self, count, buckets):
</span><span class="cx">
</span><span class="cx"> for limit, key in buckets:
</span></span></pre></div>
<a id="CalendarServertrunktwistedcaldavmethodpostpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/twistedcaldav/method/post.py (15068 => 15069)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/twistedcaldav/method/post.py        2015-08-26 17:25:45 UTC (rev 15068)
+++ CalendarServer/trunk/twistedcaldav/method/post.py        2015-08-26 18:01:05 UTC (rev 15069)
</span><span class="lines">@@ -36,6 +36,7 @@
</span><span class="cx"> if request.params:
</span><span class="cx"> if request.params == "add-member":
</span><span class="cx"> if config.EnableAddMember and hasattr(self, "POST_handler_add_member"):
</span><ins>+ request.submethod = "add-member"
</ins><span class="cx"> result = (yield self.POST_handler_add_member(request))
</span><span class="cx"> returnValue(result)
</span><span class="cx">
</span><span class="lines">@@ -45,6 +46,7 @@
</span><span class="cx"> if len(action) == 1:
</span><span class="cx"> action = action[0]
</span><span class="cx"> if hasattr(self, "POST_handler_action"):
</span><ins>+ request.submethod = action
</ins><span class="cx"> result = (yield self.POST_handler_action(request, action))
</span><span class="cx"> returnValue(result)
</span><span class="cx">
</span></span></pre>
</div>
</div>
</body>
</html>