[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [stem/master] Add timestamp to CIRC_BW and STREAM_BW events
commit 975bc0645e5a79ceeac31f4f2acdc289fc463480
Author: Damian Johnson <atagar@xxxxxxxxxxxxxx>
Date: Fri Sep 15 12:01:00 2017 -0700
Add timestamp to CIRC_BW and STREAM_BW events
Supporting new attributes...
https://gitweb.torproject.org/torspec.git/commit/?id=00b9daf
---
docs/change_log.rst | 7 ++++---
stem/response/events.py | 46 +++++++++++++++++++++++++++++++-------------
stem/util/str_tools.py | 2 +-
test/unit/response/events.py | 19 +++++++++++++++++-
test/unit/util/str_tools.py | 1 +
5 files changed, 57 insertions(+), 18 deletions(-)
diff --git a/docs/change_log.rst b/docs/change_log.rst
index dafdb471..60457e48 100644
--- a/docs/change_log.rst
+++ b/docs/change_log.rst
@@ -55,6 +55,7 @@ The following are only available within Stem's `git repository
* Tor change caused :func:`~stem.control.Controller.list_ephemeral_hidden_services` to provide empty strings if unset (:trac:`21329`)
* Better error message when :func:`~stem.control.Controller.set_conf` fails due to an option being immutable
* :func:`~stem.control.Controller.is_geoip_unavailable` now determines if database is available right away
+ * Added the time attribute to :class:`~stem.response.events.StreamBwEvent` and :class:`~stem.response.events.CircuitBandwidthEvent` (:spec:`00b9daf`)
* Deprecated :func:`~stem.control.Controller.is_geoip_unavailable`, this is now available via getinfo instead (:trac:`23237`, :spec:`dc973f8`)
* Deprecated :class:`~stem.respose.events.AuthDirNewDescEvent` (:trac:`22377`, :spec:`6e887ba`)
* Caching manual information as sqlite rather than stem.util.conf, making :func:`stem.manual.Manual.from_cache` about ~8x faster
@@ -119,7 +120,7 @@ and much more.
* Added :func:`~stem.control.Controller.reconnect` to the :class:`~stem.control.Controller`
* Added :func:`~stem.control.Controller.is_set` to the :class:`~stem.control.Controller`
* Added :func:`~stem.control.Controller.is_user_traffic_allowed` to the :class:`~stem.control.Controller`
- * Added the replica attribute to the :class:`~stem.response.events.HSDescEvent` (:spec:`4989e73`)
+ * Added the replica attribute to :class:`~stem.response.events.HSDescEvent` (:spec:`4989e73`)
* Added the NoEdConsensus :data:`~stem.Flag` (:spec:`dc99160`)
* Recognize listeners with IPv6 addresses in :func:`~stem.control.Controller.get_listeners`
* :func:`~stem.process.launch_tor` could leave a lingering process during an unexpected exception (:trac:`17946`)
@@ -255,7 +256,7 @@ brings see `Nathan Willis' LWN article <http://lwn.net/Articles/632914/>`_.
* Added :func:`~stem.control.BaseController.connection_time` to the :class:`~stem.control.BaseController`
* Changed :func:`~stem.control.Controller.get_microdescriptor`, :func:`~stem.control.Controller.get_server_descriptor`, and :func:`~stem.control.Controller.get_network_status` to get our own descriptor if no fingerprint or nickname is provided.
* Added :class:`~stem.exit_policy.ExitPolicy` methods for more easily handling 'private' policies (the `default prefix <https://www.torproject.org/docs/tor-manual.html.en#ExitPolicyRejectPrivate>`_) and the defaultly appended suffix. This includes :func:`~stem.exit_policy.ExitPolicy.has_private`, :func:`~stem.exit_policy.ExitPolicy.strip_private`, :func:`~stem.exit_policy.ExitPolicy.has_default`, and :func:`~stem.exit_policy.ExitPolicy.strip_default` :class:`~stem.exit_policy.ExitPolicy` methods in addition to :func:`~stem.exit_policy.ExitPolicyRule.is_private` and :func:`~stem.exit_policy.ExitPolicyRule.is_default` for the :class:`~stem.exit_policy.ExitPolicyRule`. (:trac:`10107`)
- * Added the reason attribute to the :class:`~stem.response.events.HSDescEvent` (:spec:`7908c8d`)
+ * Added the reason attribute to :class:`~stem.response.events.HSDescEvent` (:spec:`7908c8d`)
* :func:`~stem.process.launch_tor_with_config` could cause a "Too many open files" OSError if called too many times (:trac:`13141`)
* The :func:`~stem.control.Controller.get_exit_policy` method errored if tor couldn't determine our external address
* The Controller's methods for retrieving descriptors could raise unexpected ValueErrors if tor didn't have any descriptors available
@@ -305,7 +306,7 @@ among numerous other improvements and fixes.
* Added :func:`~stem.control.Controller.is_newnym_available` and :func:`~stem.control.Controller.get_newnym_wait` methods to the :class:`~stem.control.Controller`
* Added :func:`~stem.control.Controller.get_ports` and :func:`~stem.control.Controller.get_listeners` methods to the :class:`~stem.control.Controller`
* Added :func:`~stem.control.Controller.drop_guards` (:trac:`10032`, :spec:`7c6c7fc`)
- * Added the id attribute to the :class:`~stem.response.events.ORConnEvent` (:spec:`6f2919a`)
+ * Added the id attribute to :class:`~stem.response.events.ORConnEvent` (:spec:`6f2919a`)
* Added `support for CONN_BW events <api/response.html#stem.response.events.ConnectionBandwidthEvent>`_ (:spec:`6f2919a`)
* Added `support for CIRC_BW events <api/response.html#stem.response.events.CircuitBandwidthEvent>`_ (:spec:`6f2919a`)
* Added `support for CELL_STATS events <api/response.html#stem.response.events.CellStatsEvent>`_ (:spec:`6f2919a`)
diff --git a/stem/response/events.py b/stem/response/events.py
index 45e4677b..8392250b 100644
--- a/stem/response/events.py
+++ b/stem/response/events.py
@@ -125,6 +125,25 @@ class Event(stem.response.ControlMessage):
for controller_attr_name, attr_name in self._KEYWORD_ARGS.items():
setattr(self, attr_name, self.keyword_args.get(controller_attr_name))
+ def _iso_timestamp(self, timestamp):
+ """
+ Parses an iso timestamp (ISOTime2Frac in the control-spec).
+
+ :param str timestamp: timestamp to parse
+
+ :returns: **datetime** with the parsed timestamp
+
+ :raises: :class:`stem.ProtocolError` if timestamp is malformed
+ """
+
+ if timestamp is None:
+ return None
+
+ try:
+ return str_tools._parse_iso_timestamp(timestamp)
+ except ValueError as exc:
+ raise stem.ProtocolError('Unable to parse timestamp (%s): %s' % (exc, self))
+
# method overwritten by our subclasses for special handling that they do
def _parse(self):
pass
@@ -369,16 +388,11 @@ class CircuitEvent(Event):
def _parse(self):
self.path = tuple(stem.control._parse_circ_path(self.path))
+ self.created = self._iso_timestamp(self.created)
if self.build_flags is not None:
self.build_flags = tuple(self.build_flags.split(','))
- if self.created is not None:
- try:
- self.created = str_tools._parse_iso_timestamp(self.created)
- except ValueError as exc:
- raise stem.ProtocolError('Unable to parse create date (%s): %s' % (exc, self))
-
if not tor_tools.is_valid_circuit_id(self.id):
raise stem.ProtocolError("Circuit IDs must be one to sixteen alphanumeric characters, got '%s': %s" % (self.id, self))
@@ -468,16 +482,11 @@ class CircMinorEvent(Event):
def _parse(self):
self.path = tuple(stem.control._parse_circ_path(self.path))
+ self.created = self._iso_timestamp(self.created)
if self.build_flags is not None:
self.build_flags = tuple(self.build_flags.split(','))
- if self.created is not None:
- try:
- self.created = str_tools._parse_iso_timestamp(self.created)
- except ValueError as exc:
- raise stem.ProtocolError('Unable to parse create date (%s): %s' % (exc, self))
-
if not tor_tools.is_valid_circuit_id(self.id):
raise stem.ProtocolError("Circuit IDs must be one to sixteen alphanumeric characters, got '%s': %s" % (self.id, self))
@@ -1055,12 +1064,16 @@ class StreamBwEvent(Event):
The STREAM_BW event was introduced in tor version 0.1.2.8-beta.
+ .. versionchanged:: 1.6.0
+ Added the time attribute.
+
:var str id: stream identifier
:var long written: bytes sent by the application
:var long read: bytes received by the application
+ :var datetime time: time when the measurement was recorded
"""
- _POSITIONAL_ARGS = ('id', 'written', 'read')
+ _POSITIONAL_ARGS = ('id', 'written', 'read', 'time')
_VERSION_ADDED = stem.version.Requirement.EVENT_STREAM_BW
def _parse(self):
@@ -1075,6 +1088,7 @@ class StreamBwEvent(Event):
self.read = int_type(self.read)
self.written = int_type(self.written)
+ self.time = self._iso_timestamp(self.time)
class TransportLaunchedEvent(Event):
@@ -1166,15 +1180,20 @@ class CircuitBandwidthEvent(Event):
.. versionadded:: 1.2.0
+ .. versionchanged:: 1.6.0
+ Added the time attribute.
+
:var str id: circuit identifier
:var long read: bytes received by tor that second
:var long written: bytes sent by tor that second
+ :var datetime time: time when the measurement was recorded
"""
_KEYWORD_ARGS = {
'ID': 'id',
'READ': 'read',
'WRITTEN': 'written',
+ 'TIME': 'time',
}
_VERSION_ADDED = stem.version.Requirement.EVENT_CIRC_BW
@@ -1193,6 +1212,7 @@ class CircuitBandwidthEvent(Event):
self.read = int_type(self.read)
self.written = int_type(self.written)
+ self.time = self._iso_timestamp(self.time)
class CellStatsEvent(Event):
diff --git a/stem/util/str_tools.py b/stem/util/str_tools.py
index 14f8a7cf..bc0446fa 100644
--- a/stem/util/str_tools.py
+++ b/stem/util/str_tools.py
@@ -537,7 +537,7 @@ def _parse_iso_timestamp(entry):
if len(microseconds) != 6 or not microseconds.isdigit():
raise ValueError("timestamp's microseconds should be six digits")
- if timestamp_str[10] == 'T':
+ if len(timestamp_str) > 10 and timestamp_str[10] == 'T':
timestamp_str = timestamp_str[:10] + ' ' + timestamp_str[11:]
else:
raise ValueError("timestamp didn't contain delimeter 'T' between date and time")
diff --git a/test/unit/response/events.py b/test/unit/response/events.py
index ae7fd606..87f3e329 100644
--- a/test/unit/response/events.py
+++ b/test/unit/response/events.py
@@ -487,8 +487,10 @@ CONN_BW_BAD_WRITTEN_VALUE = '650 CONN_BW ID=11 TYPE=DIR READ=272 WRITTEN=817.7'
CONN_BW_BAD_MISSING_ID = '650 CONN_BW TYPE=DIR READ=272 WRITTEN=817'
CIRC_BW = '650 CIRC_BW ID=11 READ=272 WRITTEN=817'
+CIRC_BW_WITH_TIMESTAMP = '650 CIRC_BW ID=11 READ=272 WRITTEN=817 TIME=2012-12-06T13:51:11.433755'
CIRC_BW_BAD_WRITTEN_VALUE = '650 CIRC_BW ID=11 READ=272 WRITTEN=817.7'
CIRC_BW_BAD_MISSING_ID = '650 CIRC_BW READ=272 WRITTEN=817'
+CIRC_BW_MALFORMED_TIMESTAMP = '650 CIRC_BW ID=11 READ=272 WRITTEN=817 TIME=boom'
CELL_STATS_1 = '650 CELL_STATS ID=14 \
OutboundQueue=19403 OutboundConn=15 \
@@ -1457,11 +1459,19 @@ class TestEvents(unittest.TestCase):
self.assertEqual('2', event.id)
self.assertEqual(15, event.written)
self.assertEqual(25, event.read)
+ self.assertEqual(None, event.time)
event = _get_event('650 STREAM_BW Stream02 0 0')
self.assertEqual('Stream02', event.id)
self.assertEqual(0, event.written)
self.assertEqual(0, event.read)
+ self.assertEqual(None, event.time)
+
+ event = _get_event('650 STREAM_BW Stream02 0 0 2012-12-06T13:51:11.433755')
+ self.assertEqual('Stream02', event.id)
+ self.assertEqual(0, event.written)
+ self.assertEqual(0, event.read)
+ self.assertEqual(datetime.datetime(2012, 12, 6, 13, 51, 11, 433755), event.time)
self.assertRaises(ProtocolError, _get_event, '650 STREAM_BW')
self.assertRaises(ProtocolError, _get_event, '650 STREAM_BW 2')
@@ -1501,15 +1511,22 @@ class TestEvents(unittest.TestCase):
def test_circ_bw_event(self):
event = _get_event(CIRC_BW)
-
self.assertTrue(isinstance(event, stem.response.events.CircuitBandwidthEvent))
self.assertEqual(CIRC_BW.lstrip('650 '), str(event))
self.assertEqual('11', event.id)
self.assertEqual(272, event.read)
self.assertEqual(817, event.written)
+ self.assertEqual(None, event.time)
+
+ event = _get_event(CIRC_BW_WITH_TIMESTAMP)
+ self.assertEqual('11', event.id)
+ self.assertEqual(272, event.read)
+ self.assertEqual(817, event.written)
+ self.assertEqual(datetime.datetime(2012, 12, 6, 13, 51, 11, 433755), event.time)
self.assertRaises(ProtocolError, _get_event, CIRC_BW_BAD_WRITTEN_VALUE)
self.assertRaises(ProtocolError, _get_event, CIRC_BW_BAD_MISSING_ID)
+ self.assertRaises(ProtocolError, _get_event, CIRC_BW_MALFORMED_TIMESTAMP)
def test_cell_stats_event(self):
event = _get_event(CELL_STATS_1)
diff --git a/test/unit/util/str_tools.py b/test/unit/util/str_tools.py
index 979f0896..ee270717 100644
--- a/test/unit/util/str_tools.py
+++ b/test/unit/util/str_tools.py
@@ -180,6 +180,7 @@ class TestStrTools(unittest.TestCase):
invalid_input = [
None,
32,
+ 'boom',
'hello world',
'2012-11-08T16:48:41.42025', # too few microsecond digits
'2012-11-08T16:48:41.4202511', # too many microsecond digits
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits