2 """Store statistics for the Apt-P2P downloader."""
4 from datetime import datetime, timedelta
5 from StringIO import StringIO
7 from util import byte_format
10 """Store the statistics for the Khashmir DHT.
12 @ivar startTime: the time the program was started
13 @ivar reachable: whether we can be contacted by other nodes
14 @type table: L{ktable.KTable}
15 @ivar table: the routing table for the DHT
16 @ivar lastTableUpdate: the last time an update of the table stats was done
17 @ivar nodes: the number of nodes connected
18 @ivar users: the estimated number of total users in the DHT
20 @ivar store: the database for the DHT
21 @ivar lastDBUpdate: the last time an update of the database stats was done
22 @ivar keys: the number of distinct keys in the database
23 @ivar values: the number of values in the database
24 @ivar downPackets: the number of packets received
25 @ivar upPackets: the number of packets sent
26 @ivar downBytes: the number of bytes received
27 @ivar upBytes: the number of bytes sent
28 @ivar actions: a dictionary of the actions and their statistics, keys are
29 the action name, values are a list of 5 elements for the number of
30 times the action was sent, responded to, failed, received, and
34 def __init__(self, db):
35 """Initialize the statistics.
38 @param store: the database for the Apt-P2P downloader
42 self.lastDBUpdate = datetime.now()
43 self.hashes, self.files = self.db.dbStats()
51 stats = self.db.getStats()
52 self.mirrorAllDown = long(stats.get('mirror_down', 0L))
53 self.peerAllDown = long(stats.get('peer_down', 0L))
54 self.peerAllUp = long(stats.get('peer_up', 0L))
57 """Save the persistent statistics to the DB."""
58 stats = {'mirror_down': self.mirrorAllDown,
59 'peer_down': self.peerAllDown,
60 'peer_up': self.peerAllUp,
62 self.db.saveStats(stats)
65 """Collect some statistics about the database.
67 @rtype: (C{int}, C{int})
68 @return: the number of keys and values in the database
70 if datetime.now() - self.lastDBUpdate > timedelta(minutes = 1):
71 self.lastDBUpdate = datetime.now()
72 self.hashes, self.files = self.db.keyStats()
73 return (self.hashes, self.files)
75 def formatHTML(self, contactAddress):
76 """Gather statistics for the DHT and format them for display in a browser.
78 @param contactAddress: the external IP address in use
80 @return: the stats, formatted for display in the body of an HTML page
85 out.write('<h2>Downloader Statistics</h2>\n')
86 out.write("<table border='0' cellspacing='20px'>\n<tr>\n")
90 out.write("<table border='1' cellpadding='4px'>\n")
91 out.write("<tr><th><h3>General</h3></th><th>Value</th></tr>\n")
92 out.write("<tr title='Contact address for this peer'><td>Contact</td><td>" + str(contactAdress) + '</td></tr>\n')
93 out.write("</table>\n")
94 out.write('</td><td>\n')
97 out.write("<table border='1' cellpadding='4px'>\n")
98 out.write("<tr><th><h3>Database</h3></th><th>Value</th></tr>\n")
99 out.write("<tr title='Number of distinct files in the database'><td>Distinct Files</td><td>" + str(self.hashes) + '</td></tr>\n')
100 out.write("<tr title='Total number of files being shared'><td>Total Files</td><td>" + str(self.files) + '</td></tr>\n')
101 out.write("</table>\n")
102 out.write("</td></tr><tr><td colspan='3'>\n")
105 out.write("<table border='1' cellpadding='4px'>\n")
106 out.write("<tr><th><h3>Transport</h3></th><th>Mirror Downloads</th><th>Peer Downloads</th><th>Peer Uploads</th></tr>\n")
107 out.write("<tr><td title='Since the program was last restarted'>This Session</td>")
108 out.write("<td title='Amount downloaded from mirrors'>" + byte_format(self.mirrorDown) + '</td>')
109 out.write("<td title='Amount downloaded from peers'>" + byte_format(self.peerDown) + '</td>')
110 out.write("<td title='Amount uploaded to peers'>" + byte_format(self.peerUp) + '</td></tr>')
111 out.write("<tr><td title='Since the program was last restarted'>Session Ratio</td>")
112 out.write("<td title='Percent of download from mirrors'>%0.2f%%</td>" %
113 (float(self.mirrorDown) / float(self.mirrorDown + self.peerDown), ))
114 out.write("<td title='Percent of download from peers'>%0.2f%%</td>" %
115 (float(self.peerDown) / float(self.mirrorDown + self.peerDown), ))
116 out.write("<td title='Percent uploaded to peers compared with downloaded from peers'>%0.2f%%</td></tr>" %
117 (float(self.peerUp) / float(self.peerDown), ))
118 out.write("<tr><td title='Since the program was installed'>All-Time</td>")
119 out.write("<td title='Amount downloaded from mirrors'>" + byte_format(self.mirrorAllDown) + '</td>')
120 out.write("<td title='Amount downloaded from peers'>" + byte_format(self.peerAllDown) + '</td>')
121 out.write("<td title='Amount uploaded to peers'>" + byte_format(self.peerAllUp) + '</td></tr>')
122 out.write("<tr><td title='Since the program was installed'>All-Time Ratio</td>")
123 out.write("<td title='Percent of download from mirrors'>%0.2f%%</td>" %
124 (float(self.mirrorAllDown) / float(self.mirrorAllDown + self.peerAllDown), ))
125 out.write("<td title='Percent of download from peers'>%0.2f%%</td>" %
126 (float(self.peerAllDown) / float(self.mirrorAllDown + self.peerAllDown), ))
127 out.write("<td title='Percent uploaded to peers compared with downloaded from peers'>%0.2f%%</td></tr>" %
128 (float(self.peerAllUp) / float(self.peerAllDown), ))
129 out.write("</table>\n")
130 out.write("</td></tr>\n")
131 out.write("</table>\n")
133 return out.getvalue()
136 def sentBytes(self, bytes):
137 """Record that some bytes were sent.
139 @param bytes: the number of bytes sent
142 self.peerAllUp += bytes
144 def receivedBytes(self, bytes, mirror = False):
145 """Record that some bytes were received.
147 @param bytes: the number of bytes received
148 @param mirror: whether the bytes were sent to a mirror
151 self.mirrorDown += bytes
152 self.mirrorAllDown += bytes
154 self.peerDown += bytes
155 self.peerAllDown += bytes