[CalendarServer-changes] [6686] CalendarServer/trunk/contrib/tools
source_changes at macosforge.org
source_changes at macosforge.org
Mon Dec 13 09:29:04 PST 2010
Revision: 6686
http://trac.macosforge.org/projects/calendarserver/changeset/6686
Author: exarkun at twistedmatrix.com
Date: 2010-12-13 09:29:00 -0800 (Mon, 13 Dec 2010)
Log Message:
-----------
Report some information about how many non-self calendar home propfinds users do
Modified Paths:
--------------
CalendarServer/trunk/contrib/tools/protocolanalysis.py
Added Paths:
-----------
CalendarServer/trunk/contrib/tools/test_protocolanalysis.py
Modified: CalendarServer/trunk/contrib/tools/protocolanalysis.py
===================================================================
--- CalendarServer/trunk/contrib/tools/protocolanalysis.py 2010-12-10 19:12:56 UTC (rev 6685)
+++ CalendarServer/trunk/contrib/tools/protocolanalysis.py 2010-12-13 17:29:00 UTC (rev 6686)
@@ -81,6 +81,21 @@
( None, "(l):120s+"),
)
+userInteractionCountBuckets = (
+ ( 0, "(a):0"),
+ ( 1, "(b):1"),
+ ( 2, "(c):2"),
+ ( 3, "(d):3"),
+ ( 4, "(e):4"),
+ ( 5, "(f):5"),
+ ( 10, "(g):6-10"),
+ ( 15, "(h):11-15"),
+ ( 20, "(i):16-20"),
+ ( 30, "(j):21-30"),
+ ( 50, "(k):31-50"),
+ (None, "(l):51+"),
+)
+
httpMethods = set((
"ACL",
"BIND",
@@ -103,6 +118,20 @@
class CalendarServerLogAnalyzer(object):
+ """
+ @ivar resolutionMinutes: The number of minutes long a statistics
+ bucket will be. For example, if this is C{5}, then all data
+ points less than 5 will be placed into the first bucket; data
+ points greater than or equal to 5 and less than 10 will be
+ placed into the second bucket, and so on.
+
+ @ivar timeBucketCount: The number of statistics buckets of length
+ C{resolutionMinutes} needed to hold one day of data.
+
+ @ivar hourlyTotals: A C{list} of length C{timeBucketCount} holding ...
+
+ """
+
class LogLine(object):
def __init__(self, userid, logDateTime, logTime, method, uri, status, bytes, referer, client, extended):
@@ -181,11 +210,12 @@
self.userCounts = collections.defaultdict(int)
self.userResponseTimes = collections.defaultdict(float)
+ self.otherUserCalendarRequests = {}
+
self.currentLine = None
self.linesRead = 0
def analyzeLogFile(self, logFilePath):
-
fpath = os.path.expanduser(logFilePath)
if fpath.endswith(".gz"):
f = GzipFile(fpath)
@@ -198,7 +228,6 @@
try:
ctr = 0
for line in f:
-
ctr += 1
if ctr <= self.linesRead:
continue
@@ -225,7 +254,6 @@
# if hourFromStart > 1:
# break
if hourFromStart > lastHourFromStart:
- print logHour
lastHourFromStart = hourFromStart
if hourFromStart < self.startHourFromStart:
continue
@@ -352,6 +380,9 @@
self.userAnalysis(adjustedMethod)
+ # Look at interactions between different users
+ self.userInteractionAnalysis(adjustedMethod)
+
except Exception:
print line
raise
@@ -656,7 +687,31 @@
responseTime = float(self.currentLine.extended.get("t", 0.0))
self.userCounts["%s:%s" % (self.currentLine.userid, self.getClientAdjustedName(),)] += 1
self.userResponseTimes["%s:%s" % (self.currentLine.userid, self.getClientAdjustedName(),)] += responseTime
-
+
+
+ def summarizeUserInteraction(self, adjustedMethod):
+ summary = {}
+ otherData = self.otherUserCalendarRequests.get(adjustedMethod, {})
+ for user, others in otherData.iteritems():
+ bucket = self.getCountBucket(len(others), userInteractionCountBuckets)
+ summary[bucket] = summary.get(bucket, 0) + 1
+ return summary
+
+
+ def userInteractionAnalysis(self, adjustedMethod):
+ """
+ If the current line is a record of one user accessing another
+ user's data, update C{self.otherUserCalendarRequests} to
+ account for it.
+ """
+ forMethod = self.otherUserCalendarRequests.setdefault(adjustedMethod, {})
+ others = forMethod.setdefault(self.currentLine.userid, set())
+ segments = self.currentLine.uri.split('/')
+ if segments[:3] == ['', 'calendars', '__uids__']:
+ if segments[3:] != [self.currentLine.userid, '']:
+ others.add(segments[3])
+
+
def printAll(self, doTabs):
self.printInfo(doTabs)
@@ -718,6 +773,9 @@
print "URI Counts"
self.printURICounts(doTabs)
+ print "User Interaction Counts"
+ self.printUserInteractionCounts(doTabs)
+
#print "User Weights (top 100)"
#self.printUserWeights(doTabs)
@@ -1159,6 +1217,20 @@
table.printTabDelimitedData() if doTabs else table.printTable()
print ""
+ def printUserInteractionCounts(self, doTabs):
+ table = tables.Table()
+ table.setDefaultColumnFormats((
+ tables.Table.ColumnFormat("%s", tables.Table.ColumnFormat.RIGHT_JUSTIFY),
+ tables.Table.ColumnFormat("%s", tables.Table.ColumnFormat.RIGHT_JUSTIFY),
+ ))
+ table.addHeader(("# users accessed", "# of users"))
+ for k, v in sorted(self.summarizeUserInteraction("PROPFIND Calendar Home").iteritems()):
+ # Chop off the "(a):" part.
+ table.addRow((k[4:], str(v)))
+ table.printTabDelimitedData() if doTabs else table.printTable()
+ print ""
+
+
class TablePrinter(object):
@classmethod
Added: CalendarServer/trunk/contrib/tools/test_protocolanalysis.py
===================================================================
--- CalendarServer/trunk/contrib/tools/test_protocolanalysis.py (rev 0)
+++ CalendarServer/trunk/contrib/tools/test_protocolanalysis.py 2010-12-13 17:29:00 UTC (rev 6686)
@@ -0,0 +1,68 @@
+##
+# Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+from twisted.python.filepath import FilePath
+from twisted.trial.unittest import TestCase
+
+from protocolanalysis import CalendarServerLogAnalyzer
+
+class UserInteractionTests(TestCase):
+ """
+ Tests for analysis of the way users interact with each other, done
+ by CalendarServerLogAnalyzer.
+ """
+ def test_propfindOtherCalendar(self):
+ """
+ L{CalendarServerLogAnalyzer}'s C{otherUserCalendarRequests}
+ attribute is populated with data about the frequency with
+ which users access a calendar belonging to a different user.
+
+ The C{"PROPFIND Calendar Home"} key is associated with a
+ C{dict} with count bucket labels as keys and counts of how
+ many users PROPFINDs on calendars belonging to a number of
+ other users which falls into that bucket.
+ """
+ format = (
+ '17.128.126.80 - %(user)s [27/Sep/2010:05:13:17 +0000] '
+ '"PROPFIND /calendars/__uids__/%(other)s/ HTTP/1.1" 207 '
+ '21274 "-" "DAVKit/4.0.3 (732); CalendarStore/4.0.3 (991); '
+ 'iCal/4.0.3 (1388); Mac OS X/10.6.4 (10F569)" i=16 t=199.1 or=2\n')
+ path = FilePath(self.mktemp())
+ path.setContent(
+ # A user accessing his own calendar
+ format % dict(user="user01", other="user01") +
+
+ # A user accessing the calendar of one other person
+ format % dict(user="user02", other="user01") +
+
+ # A user accessing the calendar of one other person twice
+ format % dict(user="user03", other="user01") +
+ format % dict(user="user03", other="user01") +
+
+ # A user accessing the calendars of two other people
+ format % dict(user="user04", other="user01") +
+ format % dict(user="user04", other="user02") +
+
+ # Another user accessing the calendars of two other people
+ format % dict(user="user05", other="user03") +
+ format % dict(user="user05", other="user04"))
+
+ analyzer = CalendarServerLogAnalyzer(startHour=22, endHour=24)
+ analyzer.analyzeLogFile(path.path)
+
+ self.assertEquals(
+ analyzer.summarizeUserInteraction("PROPFIND Calendar Home"),
+ {"(a):0": 1, "(b):1": 2, "(c):2": 2})
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20101213/da9bd44d/attachment.html>
More information about the calendarserver-changes
mailing list