[CalendarServer-changes] [15117] CalendarServer/trunk/contrib/tools/readStats.py

source_changes at macosforge.org source_changes at macosforge.org
Thu Sep 10 09:15:53 PDT 2015


Revision: 15117
          http://trac.calendarserver.org//changeset/15117
Author:   cdaboo at apple.com
Date:     2015-09-10 09:15:53 -0700 (Thu, 10 Sep 2015)
Log Message:
-----------
Add ability to generate terminal/bell sounds when certain values exceed a threshold.

Modified Paths:
--------------
    CalendarServer/trunk/contrib/tools/readStats.py

Modified: CalendarServer/trunk/contrib/tools/readStats.py
===================================================================
--- CalendarServer/trunk/contrib/tools/readStats.py	2015-09-10 16:07:24 UTC (rev 15116)
+++ CalendarServer/trunk/contrib/tools/readStats.py	2015-09-10 16:15:53 UTC (rev 15117)
@@ -35,7 +35,9 @@
     return value * factor / total if total else 0
 
 
+SummaryValues = collections.namedtuple("SummaryValues", ("requests", "response", "slots", "cpu", "errors"))
 
+
 def readSock(sockname, useTCP):
     try:
         s = socket.socket(socket.AF_INET if useTCP else socket.AF_UNIX, socket.SOCK_STREAM)
@@ -69,16 +71,18 @@
             printFailedStats(stats[0]["Failed"])
         else:
             try:
-                printStat(stats[0], multimode[0], showMethods, topUsers, showAgents)
+                summary = printStat(stats[0], multimode[0], showMethods, topUsers, showAgents)
             except KeyError, e:
                 printFailedStats("Unable to find key '%s' in statistics from server socket" % (e,))
                 sys.exit(1)
 
     else:
-        printMultipleStats(stats, multimode, showMethods, topUsers, showAgents)
+        summary = printMultipleStats(stats, multimode, showMethods, topUsers, showAgents)
 
+    return summary
 
 
+
 def printStat(stats, index, showMethods, topUsers, showAgents):
 
     print("- " * 40)
@@ -99,7 +103,7 @@
         print("Current CPU: Unavailable")
         print("Current Memory Used: Unavailable")
     print
-    printRequestSummary(stats)
+    summary = printRequestSummary(stats)
     printHistogramSummary(stats[index], index)
     if showMethods:
         printMethodCounts(stats[index])
@@ -108,8 +112,10 @@
     if showAgents:
         printAgentCounts(stats[index])
 
+    return summary
 
 
+
 def printMultipleStats(stats, multimode, showMethods, topUsers, showAgents):
 
     labels = serverLabels(stats)
@@ -135,7 +141,7 @@
             cpus.append(-1)
             memories.append(-1)
 
-    printMultiRequestSummary(stats, cpus, memories, times, labels, multimode)
+    summary = printMultiRequestSummary(stats, cpus, memories, times, labels, multimode)
     printMultiHistogramSummary(stats, multimode[0])
     if showMethods:
         printMultiMethodCounts(stats, multimode[0])
@@ -144,8 +150,10 @@
     if showAgents:
         printMultiAgentCounts(stats, multimode[0])
 
+    return summary
 
 
+
 def serverLabels(stats):
     servers = [stat["server"] for stat in stats]
     if isinstance(servers[0], tuple):
@@ -220,8 +228,17 @@
     table.printTable(os=os)
     print(os.getvalue())
 
+    stat = stats["1m"]
+    return SummaryValues(
+        requests=safeDivision(float(stat["requests"]), seconds),
+        response=safeDivision(stat["t"], stat["requests"]),
+        slots=safeDivision(float(stat["slots"]), stat["requests"]),
+        cpu=safeDivision(stat["cpu"], stat["requests"]),
+        errors=stat["500"],
+    )
 
 
+
 def printMultiRequestSummary(stats, cpus, memories, times, labels, index):
 
     key, seconds = index
@@ -285,8 +302,16 @@
     table.printTable(os=os)
     print(os.getvalue())
 
+    return SummaryValues(
+        requests=totals[2],
+        response=totals[3],
+        slots=totals[6],
+        cpu=totals[7],
+        errors=totals[10],
+    )
 
 
+
 def printHistogramSummary(stat, index):
 
     print("%s average response histogram" % (index,))
@@ -484,6 +509,32 @@
 
 
 
+def alert(summary, alerts):
+
+    alert = []
+    for attr, description in (
+        ("requests", "Request count",),
+        ("response", "Response time",),
+        ("slots", "Slot count",),
+        ("cpu", "CPU time",),
+        ("errors", "Error count",),
+    ):
+        threshold = getattr(alerts, attr)
+        value = getattr(summary, attr)
+        if threshold is not None and value > threshold:
+            if isinstance(value, float):
+                value = "{:.1f}".format(value)
+            alert.append("{} threshold exceeded: {}".format(description, value))
+
+    if alert:
+        for _ignore in range(10):
+            print('\a', end='')
+            sys.stdout.flush()
+            time.sleep(0.15)
+        print("\n".join(alert))
+
+
+
 def usage(error_msg=None):
     if error_msg:
         print(error_msg)
@@ -503,6 +554,17 @@
     --agents      Include details about HTTP User-Agent usage
     --dump FILE   File to dump JSON data to
 
+    --alert-requests N     Generate an alert if the overall request
+                            count exceeds a threshold [INT]
+    --alert-response N     Generate an alert if the overall average
+                            response time exceeds a threshold [INT]
+    --alert-slots N        Generate an alert if the overall slot
+                            count exceeds a threshold [FLOAT]
+    --alert-cpu N          Generate an alert if the overall average
+                            cpu percent use exceeds a threshold [INT]
+    --alert-errors N       Generate an alert if the overall error
+                            count exceeds a threshold [INT]
+
 Description:
     This utility will print a summary of statistics read from a
     server continuously with the specified delay.
@@ -524,11 +586,21 @@
     topUsers = 0
     showAgents = False
     dumpFile = None
+    alerts = SummaryValues(
+        requests=None,
+        response=None,
+        slots=None,
+        cpu=None,
+        errors=None,
+    )
 
     multimodes = (("current", 60,), ("1m", 60,), ("5m", 5 * 60,), ("1h", 60 * 60,),)
     multimode = multimodes[2]
 
-    options, args = getopt.getopt(sys.argv[1:], "hs:t:", ["tcp=", "0", "1", "5", "60", "methods", "users=", "agents", "dump="])
+    options, args = getopt.getopt(sys.argv[1:], "hs:t:", [
+        "tcp=", "0", "1", "5", "60", "methods", "users=", "agents", "dump=",
+        "alert-requests=", "alert-response=", "alert-slots=", "alert-cpu=", "alert-errors=",
+    ])
 
     for option, value in options:
         if option == "-h":
@@ -556,14 +628,26 @@
             showAgents = True
         elif option == "--dump":
             dumpFile = value
+        elif option == "--alert-requests":
+            alerts = alerts._replace(requests=int(value))
+        elif option == "--alert-response":
+            alerts = alerts._replace(response=int(value))
+        elif option == "--alert-slots":
+            alerts = alerts._replace(slots=float(value))
+        elif option == "--alert-cpu":
+            alerts = alerts._replace(cpu=int(value))
+        elif option == "--alert-errors":
+            alerts = alerts._replace(errors=int(value))
 
     while True:
+        now = time.time()
         stats = [readSock(server, useTCP) for server in servers]
-        printStats(stats, multimode, showMethods, topUsers, showAgents, dumpFile)
+        summary = printStats(stats, multimode, showMethods, topUsers, showAgents, dumpFile)
         if dumpFile is not None:
             stats = dict([("{}:{}".format(*servers[ctr]), stat) for ctr, stat in enumerate(stats)])
             stats["timestamp"] = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S")
             with open(dumpFile, "a") as f:
                 f.write(json.dumps(stats))
                 f.write("\n")
-        time.sleep(delay)
+        alert(summary, alerts)
+        time.sleep(delay - (time.time() - now))
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20150910/ae9c5158/attachment.html>


More information about the calendarserver-changes mailing list