[Twisted-Python] Per-connection and per-protocol stats

Itamar Shtull-Trauring twisted at itamarst.org
Sun Jan 13 04:40:37 EST 2002


As I mentioned before in the metrics message, I want to have for each 
protocol events stats, per server and per server connection. This is the 
code I currently use (comments on the hits per second algorithm and in 
general are welcome.) I also have a web Resource for this so I can view 
stats with a nice interface.


======================================
"""Event monitoring support"""

import operator

from twisted.python import threadable, delay


class ProtocolMonitor:
     """Monitor a server that serves connections.

     Accepts a list of event names which the protocol can then log with
     log_event.
     """

     def __init__(self, name, eventNames):
         self.name = name
         self.eventNames = eventNames
         self.connections = {}
         self.eventcounters = EventCounters(eventNames)

     def install(self):
         """Make sure reset() is run every 0.1 seconds."""
         from twisted.internet import main
         self.looper = delay.Delayed()
         self.looper.ticktime = 0.1
         self.looper.loop(self.reset, 1)
         main.addDelayed(self.looper)

     def uninstall(self):
         """Uninstall Delayed."""
         from twisted.internet import main
         main.removeDelayed(self.looper)
         del self.looper

     def reset(self):
         """Runs once a second, resets all EventCounters."""
         for e in self.connections.values():
             e.reset()
         self.eventcounters.reset()

     def log_connectionOpened(self, conn):
         self.connections[conn] = EventCounters(self.eventNames)

     def log_connectionClosed(self, conn):
         del self.connections[conn]

     def log_event(self, conn, name):
         """First parameter should be a Protocol, second an event"""
         assert name in self.eventNames
         self.eventcounters.increment(name)
         if self.connections.has_key(conn):
             self.connections[conn].increment(name)

     synchronized = ["log_connectionOpened", "log_connectionClosed", 
"log_event", "reset"]


class EventCounters:
     """Stores a number of event counters, and how many a second.

     Algorithm for determining how many events a second:

     Divide each second into 10 (N) equal parts. Make an 11 (N+1) items long
     list L containing how many events in each part of the second, plus the
     last part of the previous second.

         L = [0] * 11

     When a new event is added, increment last item in list:

         L[-1] += 1

     Every 0.1 (1.0/N) seconds, remove first item in L and append 0:

         del L[0]; L.append(0)

     To calculate how many events in the past second, sum up last 10 (N)
     parts of L and 0.5 of the first item in L. This gives us how many hits
     in the past 0.95 to 1.05 seconds (1-1.0/2N to 1+1.0/2N seconds),
     depending on when we run this function:

         (0.5 * L[0]) + reduce(operator.add, L[1:])

     """

     def __init__(self, eventNames, ):
         self.eventNames = eventNames
         self.counters = {}
         self.secondCounters = {}
         for name in eventNames:
             self.counters[name] = 0
             self.secondCounters[name] = [0] * 10

     def increment(self, name):
         self.counters[name] += 1
         self.secondCounters[name][-1] += 1

     def reset(self):
         """Should be called every 0.1 seconds."""
         for name in self.eventNames:
             del self.secondCounters[name][0]
             self.secondCounters[name].append(0)

     def getInfo(self):
         """Return a dictionary.

         The key is an event name and the value a tuple:
         (counters, counters per second)."""
         result = {}
         for name in self.eventNames:
             l = self.secondCounters[name]
             perSecond = (0.5 * l[0]) + reduce(operator.add, l[1:])
             result[name] = (self.counters[name], perSecond)
         return result

     synchronized = ["increment", "reset", "getInfo"]


threadable.synchronize(ProtocolMonitor)
threadable.synchronize(EventCounters)





More information about the Twisted-Python mailing list