[CalendarServer-changes] [13609] CalendarServer/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Thu Jun 5 13:05:39 PDT 2014
Revision: 13609
http://trac.calendarserver.org//changeset/13609
Author: sagen at apple.com
Date: 2014-06-05 13:05:39 -0700 (Thu, 05 Jun 2014)
Log Message:
-----------
Adds dashboard support for directory service stats
Modified Paths:
--------------
CalendarServer/trunk/calendarserver/dashboard_service.py
CalendarServer/trunk/calendarserver/tools/dashboard.py
CalendarServer/trunk/txdav/dps/client.py
CalendarServer/trunk/txdav/dps/commands.py
CalendarServer/trunk/txdav/dps/server.py
CalendarServer/trunk/txdav/who/augment.py
CalendarServer/trunk/txdav/who/directory.py
Modified: CalendarServer/trunk/calendarserver/dashboard_service.py
===================================================================
--- CalendarServer/trunk/calendarserver/dashboard_service.py 2014-06-04 22:51:50 UTC (rev 13608)
+++ CalendarServer/trunk/calendarserver/dashboard_service.py 2014-06-05 20:05:39 UTC (rev 13609)
@@ -28,6 +28,7 @@
a server admin or developer would like to keep an eye on.
"""
+
class DashboardProtocol (LineReceiver):
"""
A protocol that receives a line containing a JSON object representing a request,
@@ -153,7 +154,21 @@
return succeed({"workers": loads, "level": level})
+ def data_directory(self):
+ """
+ Return a summary of directory service calls.
+ @return: the JSON result.
+ @rtype: L{str}
+ """
+ directory = self.factory.store.directoryService()
+ if hasattr(directory, "stats"):
+ return succeed(directory.stats())
+ else:
+ return succeed({})
+
+
+
class DashboardServer(Factory):
protocol = DashboardProtocol
Modified: CalendarServer/trunk/calendarserver/tools/dashboard.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/dashboard.py 2014-06-04 22:51:50 UTC (rev 13608)
+++ CalendarServer/trunk/calendarserver/tools/dashboard.py 2014-06-05 20:05:39 UTC (rev 13609)
@@ -738,10 +738,12 @@
s = " {:<12}{:>8}{:>16}".format(
"Total:",
- sum([
- record["unacknowledged"] + record["acknowledged"]
- for record in records
- ]),
+ sum(
+ [
+ record["unacknowledged"] + record["acknowledged"]
+ for record in records
+ ]
+ ),
sum([record["total"] for record in records]),
)
if self.usesCurses:
@@ -919,11 +921,103 @@
self.lastResult = records
+class DirectoryStatsWindow(BaseWindow):
+ """
+ Displays the status of the server's directory service calls
+ """
+
+ help = "display directory service stats"
+ clientItem = "directory"
+ FORMAT_WIDTH = 89
+
+
+ def makeWindow(self, top=0, left=0):
+ nlines = len(defaultIfNone(self.readItem("directory"), {}))
+ self.rowCount = nlines
+ self._createWindow(
+ "Directory Service", self.rowCount + 6, ncols=self.FORMAT_WIDTH,
+ begin_y=top, begin_x=left
+ )
+ return self
+
+
+ def update(self):
+ records = defaultIfNone(self.clientData(), {})
+ if len(records) != self.rowCount:
+ self.needsReset = True
+ return
+
+ 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}{:>15}{:>15}{:>15} ".format(
+ "Method", "Calls", "Total", "Average"
+ )
+ s2 = " {:<40}{:>15}{:>15}{:>15} ".format(
+ "", "", "(sec)", "(sec)"
+ )
+ if self.usesCurses:
+ self.window.addstr(y, x, s1, curses.A_REVERSE)
+ self.window.addstr(y + 1, x, s2, curses.A_REVERSE)
+ else:
+ print(s1)
+ print(s2)
+ y += 2
+
+ overallCount = 0
+ overallTimeSpent = 0.0
+
+ for methodName, (count, timeSpent) in sorted(records.items(), key=lambda x: x[0]):
+ overallCount += count
+ overallTimeSpent += timeSpent
+
+ s = " {:<40}{:>15d}{:>15.1f}{:>15.5f} ".format(
+ methodName,
+ count,
+ timeSpent,
+ timeSpent / count,
+ )
+ try:
+ if self.usesCurses:
+ self.window.addstr(y, x, s)
+ else:
+ print(s)
+ except curses.error:
+ pass
+ y += 1
+
+
+ s = " {:<40}{:>15d}{:>15.1f}{:>15.5f} ".format(
+ "Total:",
+ overallCount,
+ overallTimeSpent,
+ safeDivision(overallTimeSpent, overallCount, 1.0)
+ )
+ if self.usesCurses:
+ self.window.hline(y, x, "-", self.FORMAT_WIDTH - 2)
+ y += 1
+ self.window.addstr(y, x, s)
+ else:
+ print(s)
+ y += 1
+
+ if self.usesCurses:
+ self.window.refresh()
+
+
+
Dashboard.registerWindow(SystemWindow, "s")
Dashboard.registerWindow(RequestStatsWindow, "r")
Dashboard.registerWindow(JobsWindow, "j")
Dashboard.registerWindow(AssignmentsWindow, "w")
Dashboard.registerWindow(HTTPSlotsWindow, "c")
+Dashboard.registerWindow(DirectoryStatsWindow, "d")
Dashboard.registerWindow(HelpWindow, "h")
Modified: CalendarServer/trunk/txdav/dps/client.py
===================================================================
--- CalendarServer/trunk/txdav/dps/client.py 2014-06-04 22:51:50 UTC (rev 13608)
+++ CalendarServer/trunk/txdav/dps/client.py 2014-06-05 20:05:39 UTC (rev 13609)
@@ -39,7 +39,7 @@
RecordsMatchingTokensCommand, RecordsMatchingFieldsCommand,
MembersCommand, GroupsCommand, SetMembersCommand,
VerifyPlaintextPasswordCommand, VerifyHTTPDigestCommand,
- WikiAccessForUID, ContinuationCommand
+ WikiAccessForUIDCommand, ContinuationCommand
)
from txdav.who.directory import (
CalendarDirectoryRecordMixin, CalendarDirectoryServiceMixin
@@ -401,7 +401,7 @@
def accessForRecord(self, record):
log.debug("DPS Client accessForRecord")
return self.service._call(
- WikiAccessForUID,
+ WikiAccessForUIDCommand,
self._convertAccess,
wikiUID=self.uid.encode("utf-8"),
uid=record.uid.encode("utf-8")
Modified: CalendarServer/trunk/txdav/dps/commands.py
===================================================================
--- CalendarServer/trunk/txdav/dps/commands.py 2014-06-04 22:51:50 UTC (rev 13608)
+++ CalendarServer/trunk/txdav/dps/commands.py 2014-06-05 20:05:39 UTC (rev 13609)
@@ -191,7 +191,7 @@
-class WikiAccessForUID(amp.Command):
+class WikiAccessForUIDCommand(amp.Command):
arguments = [
('wikiUID', amp.String()),
('uid', amp.String()),
Modified: CalendarServer/trunk/txdav/dps/server.py
===================================================================
--- CalendarServer/trunk/txdav/dps/server.py 2014-06-04 22:51:50 UTC (rev 13608)
+++ CalendarServer/trunk/txdav/dps/server.py 2014-06-05 20:05:39 UTC (rev 13609)
@@ -36,7 +36,7 @@
RecordsMatchingTokensCommand, RecordsMatchingFieldsCommand,
MembersCommand, GroupsCommand, SetMembersCommand,
VerifyPlaintextPasswordCommand, VerifyHTTPDigestCommand,
- WikiAccessForUID, ContinuationCommand
+ WikiAccessForUIDCommand, ContinuationCommand
# UpdateRecordsCommand, RemoveRecordsCommand
)
from txdav.who.util import directoryFromConfig
@@ -430,7 +430,7 @@
returnValue(response)
- @WikiAccessForUID.responder
+ @WikiAccessForUIDCommand.responder
@inlineCallbacks
def wikiAccessForUID(self, wikiUID, uid):
wikiUID = wikiUID.decode("utf-8")
Modified: CalendarServer/trunk/txdav/who/augment.py
===================================================================
--- CalendarServer/trunk/txdav/who/augment.py 2014-06-04 22:51:50 UTC (rev 13608)
+++ CalendarServer/trunk/txdav/who/augment.py 2014-06-05 20:05:39 UTC (rev 13609)
@@ -23,6 +23,8 @@
"AugmentedDirectoryService",
]
+import time
+
from zope.interface import implementer
from twisted.internet.defer import inlineCallbacks, returnValue
@@ -47,6 +49,47 @@
+def timed(f):
+ """
+ A decorator which keeps track of the wrapped function's call count and
+ total duration
+ """
+
+ def recordTiming(result, key, startTime):
+ """
+ Figures out how much time to add to the total time spent within the
+ method identified by key and stores that in the timings dict.
+
+ @param result: the result of the wrapped method
+ @param timings: the dictionary to store timings in
+ @type timings: C{dict}
+ @param key: the method name
+ @type key: C{str}
+ @param startTime: the start time of the call in seconds
+ @type startTime: C{float}
+ """
+ timings = AugmentedDirectoryService._timings
+ if key not in timings:
+ timings[key] = (0, 0.0)
+ count, timeSpent = timings[key]
+ count += 1
+ duration = (time.time() - startTime)
+ timeSpent += duration
+ timings[key] = (count, timeSpent)
+ return result
+
+
+ def timingWrapper(self, *args, **kwds):
+ """
+ Records the start time of the call and the method's name
+ """
+ d = f(self, *args, **kwds)
+ d.addBoth(recordTiming, f.func_name, time.time())
+ return d
+
+ return timingWrapper
+
+
@implementer(IDirectoryService, IStoreDirectoryService)
class AugmentedDirectoryService(
BaseDirectoryService, CalendarDirectoryServiceMixin
@@ -63,7 +106,9 @@
FieldName,
))
+ _timings = {}
+
def __init__(self, directory, store, augmentDB):
BaseDirectoryService.__init__(self, directory.realmName)
self._directory = directory
@@ -71,6 +116,10 @@
self._augmentDB = augmentDB
+ def stats(self):
+ return self._timings
+
+
@property
def recordType(self):
# Defer to the directory service we're augmenting
@@ -104,6 +153,7 @@
returnValue(augmented)
+ @timed
@inlineCallbacks
def recordWithUID(self, uid):
# MOVE2WHO, REMOVE THIS:
@@ -116,6 +166,7 @@
returnValue(record)
+ @timed
@inlineCallbacks
def recordWithGUID(self, guid):
record = yield self._directory.recordWithGUID(guid)
@@ -123,6 +174,7 @@
returnValue(record)
+ @timed
@inlineCallbacks
def recordsWithRecordType(self, recordType):
records = yield self._directory.recordsWithRecordType(recordType)
@@ -133,6 +185,7 @@
returnValue(augmented)
+ @timed
@inlineCallbacks
def recordWithShortName(self, recordType, shortName):
# MOVE2WHO, REMOVE THIS:
@@ -147,6 +200,7 @@
returnValue(record)
+ @timed
@inlineCallbacks
def recordsWithEmailAddress(self, emailAddress):
# MOVE2WHO, REMOVE THIS:
@@ -162,6 +216,28 @@
returnValue(augmented)
+ @timed
+ def recordWithCalendarUserAddress(self, *args, **kwds):
+ return CalendarDirectoryServiceMixin.recordWithCalendarUserAddress(
+ self, *args, **kwds
+ )
+
+
+ @timed
+ def recordsMatchingTokens(self, *args, **kwds):
+ return CalendarDirectoryServiceMixin.recordsMatchingTokens(
+ self, *args, **kwds
+ )
+
+
+ @timed
+ def recordsMatchingFields(self, *args, **kwds):
+ return CalendarDirectoryServiceMixin.recordsMatchingFields(
+ self, *args, **kwds
+ )
+
+
+ @timed
@inlineCallbacks
def updateRecords(self, records, create=False):
"""
@@ -364,6 +440,7 @@
self._baseRecord = baseRecord
+ @timed
@inlineCallbacks
def members(self):
augmented = []
@@ -375,6 +452,7 @@
returnValue(augmented)
+ @timed
@inlineCallbacks
def groups(self):
augmented = []
@@ -397,13 +475,16 @@
returnValue(augmented)
+ @timed
def verifyPlaintextPassword(self, password):
return self._baseRecord.verifyPlaintextPassword(password)
+ @timed
def verifyHTTPDigest(self, *args):
return self._baseRecord.verifyHTTPDigest(*args)
+ @timed
def accessForRecord(self, record):
return self._baseRecord.accessForRecord(record)
Modified: CalendarServer/trunk/txdav/who/directory.py
===================================================================
--- CalendarServer/trunk/txdav/who/directory.py 2014-06-04 22:51:50 UTC (rev 13608)
+++ CalendarServer/trunk/txdav/who/directory.py 2014-06-05 20:05:39 UTC (rev 13609)
@@ -459,7 +459,7 @@
return candidate
# fall back to using the first one
- return sortedCuas[0] if sortedCuas else None # groups may not have cua
+ return sortedCuas[0] if sortedCuas else None # groups may not have cua
def enabledAsOrganizer(self):
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140605/56138d98/attachment-0001.html>
More information about the calendarserver-changes
mailing list