use 'backends' for usage-recording
This commit is contained in:
parent
5ed572187b
commit
53864f57f0
|
@ -67,11 +67,105 @@ class TestClient(object):
|
||||||
print("disconnect_partner: {}".format(id(self._partner)))
|
print("disconnect_partner: {}".format(id(self._partner)))
|
||||||
|
|
||||||
|
|
||||||
|
class IUsageWriter(Interface):
|
||||||
|
"""
|
||||||
|
Records actual usage statistics in some way
|
||||||
|
"""
|
||||||
|
|
||||||
|
def record_usage(started=None, total_time=None, waiting_time=None, total_bytes=None, mood=None):
|
||||||
|
"""
|
||||||
|
:param int started: timestemp when this connection began
|
||||||
|
|
||||||
|
:param float total_time: total seconds this connection lasted
|
||||||
|
|
||||||
|
:param float waiting_time: None or the total seconds one side
|
||||||
|
waited for the other
|
||||||
|
|
||||||
|
:param int total_bytes: the total bytes sent. In case the
|
||||||
|
connection was concluded successfully, only one side will
|
||||||
|
record the total bytes (but count both).
|
||||||
|
|
||||||
|
:param str mood: the 'mood' of the connection
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@implementer(IUsageWriter)
|
||||||
|
class MemoryUsageRecorder:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.events = []
|
||||||
|
|
||||||
|
def record_usage(self, started=None, total_time=None, waiting_time=None, total_bytes=None, mood=None):
|
||||||
|
"""
|
||||||
|
IUsageWriter.
|
||||||
|
"""
|
||||||
|
data = {
|
||||||
|
"started": started,
|
||||||
|
"total_time": total_time,
|
||||||
|
"waiting_time": waiting_time,
|
||||||
|
"total_bytes": total_bytes,
|
||||||
|
"mood": mood,
|
||||||
|
}
|
||||||
|
self.events.append(data)
|
||||||
|
|
||||||
|
|
||||||
|
@implementer(IUsageWriter)
|
||||||
|
class LogFileUsageRecorder:
|
||||||
|
|
||||||
|
def __init__(self, writable_file):
|
||||||
|
self._file = writable_file
|
||||||
|
|
||||||
|
def record_usage(self, started=None, total_time=None, waiting_time=None, total_bytes=None, mood=None):
|
||||||
|
"""
|
||||||
|
IUsageWriter.
|
||||||
|
"""
|
||||||
|
data = {
|
||||||
|
"started": started,
|
||||||
|
"total_time": total_time,
|
||||||
|
"waiting_time": waiting_time,
|
||||||
|
"total_bytes": total_bytes,
|
||||||
|
"mood": mood,
|
||||||
|
}
|
||||||
|
self._file.write(json.dumps(data))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@implementer(IUsageWriter)
|
||||||
|
class DatabaseUsageRecorder:
|
||||||
|
|
||||||
|
def __init__(self, _db):
|
||||||
|
self._db = db
|
||||||
|
|
||||||
|
def record_usage(self, started=None, total_time=None, waiting_time=None, total_bytes=None, mood=None):
|
||||||
|
"""
|
||||||
|
IUsageWriter.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class UsageRecorder(object):
|
class UsageRecorder(object):
|
||||||
"""
|
"""
|
||||||
Tracks usage statistics of connections
|
Tracks usage statistics of connections
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._backends = set()
|
||||||
|
|
||||||
|
def add_backend(self, backend):
|
||||||
|
"""
|
||||||
|
Add a new backend.
|
||||||
|
|
||||||
|
:param IUsageWriter backend: the backend to add
|
||||||
|
"""
|
||||||
|
self._backends.add(backend)
|
||||||
|
|
||||||
|
def remove_backend(self, backend):
|
||||||
|
"""
|
||||||
|
Remove an existing backend
|
||||||
|
|
||||||
|
:param IUsageWriter backend: the backend to remove
|
||||||
|
"""
|
||||||
|
self._backends.remove(backend)
|
||||||
|
|
||||||
def record(self, started, buddy_started, result, bytes_sent, buddy_bytes):
|
def record(self, started, buddy_started, result, bytes_sent, buddy_bytes):
|
||||||
"""
|
"""
|
||||||
:param int started: timestamp when our connection started
|
:param int started: timestamp when our connection started
|
||||||
|
@ -102,7 +196,7 @@ class UsageRecorder(object):
|
||||||
# probably want like "backends" here or something? original
|
# probably want like "backends" here or something? original
|
||||||
# code logs some JSON (maybe) and writes to a database (maybe)
|
# code logs some JSON (maybe) and writes to a database (maybe)
|
||||||
# and tests record in memory.
|
# and tests record in memory.
|
||||||
self.json_record({
|
self._notify_backends({
|
||||||
"started": started,
|
"started": started,
|
||||||
"total_time": total_time,
|
"total_time": total_time,
|
||||||
"waiting_time": waiting_time,
|
"waiting_time": waiting_time,
|
||||||
|
@ -110,8 +204,12 @@ class UsageRecorder(object):
|
||||||
"mood": result,
|
"mood": result,
|
||||||
})
|
})
|
||||||
|
|
||||||
def json_record(self, data):
|
def _notify_backends(self, data):
|
||||||
pass
|
"""
|
||||||
|
Internal helper. Tell every backend we have about a new usage.
|
||||||
|
"""
|
||||||
|
for backend in self._backends:
|
||||||
|
backend.record_usage(**data)
|
||||||
|
|
||||||
|
|
||||||
class ActiveConnections(object):
|
class ActiveConnections(object):
|
||||||
|
|
|
@ -3,6 +3,7 @@ from binascii import hexlify
|
||||||
from twisted.trial import unittest
|
from twisted.trial import unittest
|
||||||
from .common import ServerBase
|
from .common import ServerBase
|
||||||
from .. import transit_server
|
from .. import transit_server
|
||||||
|
from ..server_state import MemoryUsageRecorder
|
||||||
|
|
||||||
def handshake(token, side=None):
|
def handshake(token, side=None):
|
||||||
hs = b"please relay " + hexlify(token)
|
hs = b"please relay " + hexlify(token)
|
||||||
|
@ -341,8 +342,8 @@ class Usage(ServerBase, unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(Usage, self).setUp()
|
super(Usage, self).setUp()
|
||||||
self._usage = []
|
self._usage = MemoryUsageRecorder()
|
||||||
self._transit_server.usage.json_record = self._usage.append
|
self._transit_server.usage.add_backend(self._usage)
|
||||||
|
|
||||||
def test_empty(self):
|
def test_empty(self):
|
||||||
p1 = self.new_protocol()
|
p1 = self.new_protocol()
|
||||||
|
@ -351,8 +352,8 @@ class Usage(ServerBase, unittest.TestCase):
|
||||||
self.flush()
|
self.flush()
|
||||||
|
|
||||||
# that will log the "empty" usage event
|
# that will log the "empty" usage event
|
||||||
self.assertEqual(len(self._usage), 1, self._usage)
|
self.assertEqual(len(self._usage.events), 1, self._usage)
|
||||||
self.assertEqual(self._usage[0]["mood"], "empty", self._usage)
|
self.assertEqual(self._usage.events[0]["mood"], "empty", self._usage)
|
||||||
|
|
||||||
def test_short(self):
|
def test_short(self):
|
||||||
p1 = self.new_protocol()
|
p1 = self.new_protocol()
|
||||||
|
@ -362,8 +363,8 @@ class Usage(ServerBase, unittest.TestCase):
|
||||||
self.flush()
|
self.flush()
|
||||||
|
|
||||||
# that will log the "empty" usage event
|
# that will log the "empty" usage event
|
||||||
self.assertEqual(len(self._usage), 1, self._usage)
|
self.assertEqual(len(self._usage.events), 1, self._usage)
|
||||||
self.assertEqual("empty", self._usage[0]["mood"])
|
self.assertEqual("empty", self._usage.events[0]["mood"])
|
||||||
|
|
||||||
def test_errory(self):
|
def test_errory(self):
|
||||||
p1 = self.new_protocol()
|
p1 = self.new_protocol()
|
||||||
|
@ -372,8 +373,8 @@ class Usage(ServerBase, unittest.TestCase):
|
||||||
self.flush()
|
self.flush()
|
||||||
# that will log the "errory" usage event, then drop the connection
|
# that will log the "errory" usage event, then drop the connection
|
||||||
p1.disconnect()
|
p1.disconnect()
|
||||||
self.assertEqual(len(self._usage), 1, self._usage)
|
self.assertEqual(len(self._usage.events), 1, self._usage)
|
||||||
self.assertEqual(self._usage[0]["mood"], "errory", self._usage)
|
self.assertEqual(self._usage.events[0]["mood"], "errory", self._usage)
|
||||||
|
|
||||||
def test_lonely(self):
|
def test_lonely(self):
|
||||||
p1 = self.new_protocol()
|
p1 = self.new_protocol()
|
||||||
|
@ -386,9 +387,9 @@ class Usage(ServerBase, unittest.TestCase):
|
||||||
p1.disconnect()
|
p1.disconnect()
|
||||||
self.flush()
|
self.flush()
|
||||||
|
|
||||||
self.assertEqual(len(self._usage), 1, self._usage)
|
self.assertEqual(len(self._usage.events), 1, self._usage)
|
||||||
self.assertEqual(self._usage[0]["mood"], "lonely", self._usage)
|
self.assertEqual(self._usage.events[0]["mood"], "lonely", self._usage)
|
||||||
self.assertIdentical(self._usage[0]["waiting_time"], None)
|
self.assertIdentical(self._usage.events[0]["waiting_time"], None)
|
||||||
|
|
||||||
def test_one_happy_one_jilted(self):
|
def test_one_happy_one_jilted(self):
|
||||||
p1 = self.new_protocol()
|
p1 = self.new_protocol()
|
||||||
|
@ -402,7 +403,7 @@ class Usage(ServerBase, unittest.TestCase):
|
||||||
p2.send(handshake(token1, side=side2))
|
p2.send(handshake(token1, side=side2))
|
||||||
self.flush()
|
self.flush()
|
||||||
|
|
||||||
self.assertEqual(self._usage, []) # no events yet
|
self.assertEqual(self._usage.events, []) # no events yet
|
||||||
|
|
||||||
p1.send(b"\x00" * 13)
|
p1.send(b"\x00" * 13)
|
||||||
self.flush()
|
self.flush()
|
||||||
|
@ -412,10 +413,10 @@ class Usage(ServerBase, unittest.TestCase):
|
||||||
p1.disconnect()
|
p1.disconnect()
|
||||||
self.flush()
|
self.flush()
|
||||||
|
|
||||||
self.assertEqual(len(self._usage), 1, self._usage)
|
self.assertEqual(len(self._usage.events), 1, self._usage)
|
||||||
self.assertEqual(self._usage[0]["mood"], "happy", self._usage)
|
self.assertEqual(self._usage.events[0]["mood"], "happy", self._usage)
|
||||||
self.assertEqual(self._usage[0]["total_bytes"], 20)
|
self.assertEqual(self._usage.events[0]["total_bytes"], 20)
|
||||||
self.assertNotIdentical(self._usage[0]["waiting_time"], None)
|
self.assertNotIdentical(self._usage.events[0]["waiting_time"], None)
|
||||||
|
|
||||||
def test_redundant(self):
|
def test_redundant(self):
|
||||||
p1a = self.new_protocol()
|
p1a = self.new_protocol()
|
||||||
|
@ -438,18 +439,18 @@ class Usage(ServerBase, unittest.TestCase):
|
||||||
p1c.disconnect()
|
p1c.disconnect()
|
||||||
self.flush()
|
self.flush()
|
||||||
|
|
||||||
self.assertEqual(len(self._usage), 1, self._usage)
|
self.assertEqual(len(self._usage.events), 1, self._usage)
|
||||||
self.assertEqual(self._usage[0]["mood"], "lonely")
|
self.assertEqual(self._usage.events[0]["mood"], "lonely")
|
||||||
|
|
||||||
p2.send(handshake(token1, side=side2))
|
p2.send(handshake(token1, side=side2))
|
||||||
self.flush()
|
self.flush()
|
||||||
self.assertEqual(len(self._transit_server.pending_requests._requests), 0)
|
self.assertEqual(len(self._transit_server.pending_requests._requests), 0)
|
||||||
self.assertEqual(len(self._usage), 2, self._usage)
|
self.assertEqual(len(self._usage.events), 2, self._usage)
|
||||||
self.assertEqual(self._usage[1]["mood"], "redundant")
|
self.assertEqual(self._usage.events[1]["mood"], "redundant")
|
||||||
|
|
||||||
# one of the these is unecessary, but probably harmless
|
# one of the these is unecessary, but probably harmless
|
||||||
p1a.disconnect()
|
p1a.disconnect()
|
||||||
p1b.disconnect()
|
p1b.disconnect()
|
||||||
self.flush()
|
self.flush()
|
||||||
self.assertEqual(len(self._usage), 3, self._usage)
|
self.assertEqual(len(self._usage.events), 3, self._usage)
|
||||||
self.assertEqual(self._usage[2]["mood"], "happy")
|
self.assertEqual(self._usage.events[2]["mood"], "happy")
|
||||||
|
|
Loading…
Reference in New Issue
Block a user