X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=apt_p2p_Khashmir%2Fstats.py;h=5ed7e6d42622b5193d40df4b75da4480ffd7b9ad;hb=aafdc40ed1f4b5355bdf23365dc9d48f74cc8761;hp=aeb979efea6cbbeb3d375cc21ff5de587ece23c6;hpb=146f1044e3661716ec4689d3ea7e6ab4ab38ae77;p=quix0rs-apt-p2p.git diff --git a/apt_p2p_Khashmir/stats.py b/apt_p2p_Khashmir/stats.py index aeb979e..5ed7e6d 100644 --- a/apt_p2p_Khashmir/stats.py +++ b/apt_p2p_Khashmir/stats.py @@ -2,14 +2,14 @@ """Store statistics for the Khashmir DHT.""" from datetime import datetime, timedelta -from copy import deepcopy +from StringIO import StringIO + +from ktable import K +from util import byte_format class StatsLogger: """Store the statistics for the Khashmir DHT. - @ivar _StatsTemplate: a template for returning all the statistics - @type config: C{dictionary} - @ivar config: the configuration parameters for the DHT @ivar startTime: the time the program was started @ivar reachable: whether we can be contacted by other nodes @type table: L{ktable.KTable} @@ -32,87 +32,16 @@ class StatsLogger: generated an error """ - _StatsTemplate = [{'name': 'uptime', - 'group': 'General', - 'desc': 'Up time', - 'tip': 'The elapsed time since the program started', - 'value': None, - }, - {'name': 'reachable', - 'group': 'General', - 'desc': 'Reachable', - 'tip': 'Whether other nodes can contact us (not NATted or firewalled)', - 'value': None, - }, - {'name': 'nodes', - 'group': 'Routing Table', - 'desc': 'Number of nodes', - 'tip': 'The number of nodes we are connected to', - 'value': None, - }, - {'name': 'users', - 'group': 'Routing Table', - 'desc': 'Total number of users', - 'tip': 'The estimated total number of users in the DHT', - 'value': None, - }, - {'name': 'keys', - 'group': 'Database', - 'desc': 'Keys', - 'tip': 'The number of distinct keys in the database', - 'value': None, - }, - {'name': 'values', - 'group': 'Database', - 'desc': 'Values', - 'tip': 'The total number of values in the database', - 'value': None, - }, - {'name': 'downPackets', - 'group': 'Transport', - 'desc': 'Downloaded packets', - 'tip': 'The number of received packets', - 'value': None, - }, - {'name': 'upPackets', - 'group': 'Transport', - 'desc': 'Uploaded packets', - 'tip': 'The number of sent packets', - 'value': None, - }, - {'name': 'downBytes', - 'group': 'Transport', - 'desc': 'Downloaded bytes', - 'tip': 'The number of bytes received by the DHT', - 'value': None, - }, - {'name': 'upBytes', - 'group': 'Transport', - 'desc': 'Uploaded bytes', - 'tip': 'The number of bytes sent by the DHT', - 'value': None, - }, - {'name': 'actions', - 'group': 'Actions', - 'desc': 'Actions', - 'tip': 'The number of requests for each action', - 'value': None, - }, - ] - - def __init__(self, table, store, config): + def __init__(self, table, store): """Initialize the statistics. @type table: L{ktable.KTable} @param table: the routing table for the DHT @type store: L{db.DB} @param store: the database for the DHT - @type config: C{dictionary} - @param config: the configuration parameters for the DHT """ # General - self.config = config - self.startTime = datetime.now() + self.startTime = datetime.now().replace(microsecond=0) self.reachable = False # Routing Table @@ -144,7 +73,7 @@ class StatsLogger: if datetime.now() - self.lastTableUpdate > timedelta(seconds = 15): self.lastTableUpdate = datetime.now() self.nodes = reduce(lambda a, b: a + len(b.l), self.table.buckets, 0) - self.users = self.config['K'] * (2**(len(self.table.buckets) - 1)) + self.users = K * (2**(len(self.table.buckets) - 1)) return (self.nodes, self.users) def dbStats(self): @@ -158,26 +87,93 @@ class StatsLogger: self.keys, self.values = self.store.keyStats() return (self.keys, self.values) - def gather(self): - """Gather all the statistics for the DHT. + def formatHTML(self): + """Gather statistics for the DHT and format them for display in a browser. - @rtype: C{list} of C{dictionary} - @return: each dictionary has keys describing the statistic: - name, group, desc, tip, and value + @rtype: C{string} + @return: the stats, formatted for display in the body of an HTML page """ self.tableStats() self.dbStats() - stats = self._StatsTemplate[:] - for stat in stats: - val = getattr(self, stat['name'], None) - if stat['name'] == 'uptime': - stat['value'] = datetime.now() - self.startTime - elif stat['name'] == 'actions': - stat['value'] = deepcopy(self.actions) - elif val is not None: - stat['value'] = val - - return stats + elapsed = datetime.now().replace(microsecond=0) - self.startTime + out = StringIO() + out.write('

DHT Statistics

\n') + out.write("\n\n") + out.write('\n") + out.write("
\n') + + # General + out.write("\n") + out.write("\n") + out.write("\n') + out.write("\n') + out.write("

General

Value
Up time" + str(elapsed) + '
Reachable" + str(self.reachable) + '
\n") + out.write('
\n') + + # Routing + out.write("\n") + out.write("\n") + out.write("\n') + out.write("\n') + out.write("

Routing Table

Value
Number of nodes" + str(self.nodes) + '
Total number of users" + str(self.users) + '
\n") + out.write('
\n') + + # Database + out.write("\n") + out.write("\n") + out.write("\n') + out.write("\n') + out.write("

Database

Value
Keys" + str(self.keys) + '
Values" + str(self.values) + '
\n") + out.write("
\n") + + # Transport + out.write("\n") + out.write("\n") + out.write("") + out.write('') + out.write('') + out.write('\n') + out.write("") + out.write('') + out.write('') + out.write('\n') + out.write("

Transport

PacketsBytesSpeed
Downloaded' + str(self.downPackets) + '' + byte_format(self.downBytes) + '' + byte_format(self.downBytes / (elapsed.days*86400.0 + elapsed.seconds)) + '/sec
Uploaded' + str(self.upPackets) + '' + byte_format(self.upBytes) + '' + byte_format(self.upBytes / (elapsed.days*86400.0 + elapsed.seconds)) + '/sec
\n") + out.write("
\n") + + # Actions + out.write("\n") + out.write("") + out.write("") + out.write("\n") + actions = self.actions.keys() + actions.sort() + for action in actions: + out.write("") + for i in xrange(7): + out.write("") + for i in xrange(3): + count = self.actions[action][i+2] + if count > 0: + total_delay = self.actions[action][i+7] + avg_delay = total_delay / count + avg_delay_sec = avg_delay.days*86400.0 + avg_delay.seconds + avg_delay.microseconds/1000000.0 + else: + avg_delay_sec = 0.0 + out.write("" % avg_delay_sec) + out.write('\n') + out.write("

Actions

StartedSentSuccessfulFailedCompletedReceivedErrorSuccessful DelayFailed DelayTotal Delay
" + action + "" + str(self.actions[action][i]) + "%0.2f
\n") + out.write("
\n") + + return out.getvalue() + + #{ Called by the action + def startedAction(self, action): + """Record that an action was started. + + @param action: the name of the action + """ + act = self.actions.setdefault(action, [0, 0, 0, 0, 0, 0, 0, timedelta(), timedelta(), timedelta()]) + act[0] += 1 #{ Called by the transport def sentAction(self, action): @@ -185,47 +181,61 @@ class StatsLogger: @param action: the name of the action """ - act = self.actions.setdefault(action, [0, 0, 0, 0, 0]) - act[0] += 1 + act = self.actions.setdefault(action, [0, 0, 0, 0, 0, 0, 0, timedelta(), timedelta(), timedelta()]) + act[1] += 1 - def responseAction(self, response, action): + def responseAction(self, response, action, start): """Record that a response to an action was received. @param response: the response @param action: the name of the action + @param start: the time the action was started @return: the response (for use in deferreds) """ - act = self.actions.setdefault(action, [0, 0, 0, 0, 0]) - act[1] += 1 + act = self.actions.setdefault(action, [0, 0, 0, 0, 0, 0, 0, timedelta(), timedelta(), timedelta()]) + act[2] += 1 + act[7] += datetime.now() - start return response - def failedAction(self, response, action): + def failedAction(self, response, action, start): """Record that a failed response to an action was received. @param response: the response @param action: the name of the action + @param start: the time the action was started @return: the response (for use in deferreds) """ - act = self.actions.setdefault(action, [0, 0, 0, 0, 0]) - act[2] += 1 + act = self.actions.setdefault(action, [0, 0, 0, 0, 0, 0, 0, timedelta(), timedelta(), timedelta()]) + act[3] += 1 + act[8] += datetime.now() - start return response + def completedAction(self, action, start): + """Record that an action was completed. + + @param action: the name of the action + @param start: the time the action was started + """ + act = self.actions.setdefault(action, [0, 0, 0, 0, 0, 0, 0, timedelta(), timedelta(), timedelta()]) + act[4] += 1 + act[9] += datetime.now() - start + def receivedAction(self, action): """Record that an action was received. @param action: the name of the action """ self.reachable = True - act = self.actions.setdefault(action, [0, 0, 0, 0, 0]) - act[3] += 1 + act = self.actions.setdefault(action, [0, 0, 0, 0, 0, 0, 0, timedelta(), timedelta(), timedelta()]) + act[5] += 1 def errorAction(self, action): """Record that a received action resulted in an error. @param action: the name of the action """ - act = self.actions.setdefault(action, [0, 0, 0, 0, 0]) - act[4] += 1 + act = self.actions.setdefault(action, [0, 0, 0, 0, 0, 0, 0, timedelta(), timedelta(), timedelta()]) + act[6] += 1 def sentBytes(self, bytes): """Record that a single packet of some bytes was sent.