Permalink
Browse files

More stats changes.

  • Loading branch information...
mrjoes committed Nov 24, 2011
1 parent e84ee90 commit 92d97115b8517cc70db3b79ba4f5e55a4655eabe
Showing with 262 additions and 113 deletions.
  1. +6 −0 README.rst
  2. +1 −0 doc/api.rst
  3. +1 −0 doc/index.rst
  4. +1 −1 doc/mod_router.rst
  5. +10 −0 doc/mod_stats.rst
  6. +34 −0 doc/stats.rst
  7. +15 −13 examples/stats/index.html
  8. +29 −5 examples/stats/stats.html
  9. +3 −4 examples/stats/stats.py
  10. +63 −54 tornadio2/polling.py
  11. +28 −23 tornadio2/router.py
  12. +9 −1 tornadio2/session.py
  13. +62 −12 tornadio2/stats.py
View
@@ -98,6 +98,12 @@ Multiplexed
Ping and chat demo running through one connection. You can see it in ``examples/multiplexed`` directory.
+Stats
+^^^^^
+
+TornadIO2 collects some counters that you can use to troubleshoot your application performance.
+Example in ``examples/stats`` gives an idea how you can use these stats to plot realtime graph.
+
RPC ping
^^^^^^^^
View
@@ -16,3 +16,4 @@ API
mod_server
mod_session
mod_sessioncontainer
+ mod_stats
View
@@ -21,6 +21,7 @@ Topics
events
acknowledgments
gen
+ stats
deployment
bugs
api
View
@@ -9,7 +9,7 @@
^^^^^^
.. automethod:: TornadioRouter.__init__
- .. automethod:: TornadioRouter.urls
+ .. autoattribute:: TornadioRouter.urls
.. automethod:: TornadioRouter.apply_routes
Sessions
View
@@ -0,0 +1,10 @@
+``tornadio2.stats``
+===================
+
+.. automodule:: tornadio2.stats
+
+ .. autoclass:: StatsCollector
+
+ .. automethod:: dump()
+
+ .. autoclass:: MovingAverage
View
@@ -0,0 +1,34 @@
+Statistics
+==========
+
+TornadIO2 captures some counters:
+
+================== =======================================
+Name Description
+================== =======================================
+**Sessions**
+----------------------------------------------------------
+max_sessions Maximum number of sessions
+active_sessions Number of currently active sessions
+
+**Connections**
+----------------------------------------------------------
+max_connections Maximum number of connections
+active_connections Number of currently active connections
+connections_ps Number of opened connections per second
+
+**Packets**
+----------------------------------------------------------
+packets_sent_ps Packets sent per second
+packets_recv_ps Packets received per second
+================== =======================================
+
+Stats are captured by the router object and can be accessed
+through the ``stats`` property::
+
+ MyRouter = tornadio2.TornadioRouter(MyConnection)
+
+ print MyRouter.stats.dump()
+
+For more information, check stats module API or ``stats``
+example.
View
@@ -34,21 +34,23 @@
data[0], data[1], data[2], data[3]);
}
- function sendPing()
- {
- ping.emit('ping', encodeDate(new Date()), function(clientDate, serverDate) {
- var client = decodeDate(clientDate);
- var server = decodeDate(serverDate);
- var now = new Date();
+ ping.on('connect', function() {
+ function sendPing()
+ {
+ ping.emit('ping', encodeDate(new Date()), function(clientDate, serverDate) {
+ var client = decodeDate(clientDate);
+ var server = decodeDate(serverDate);
+ var now = new Date();
- $('#ping').html('Ping: ' + (now.getTime() - client.getTime()).toString() + ' ms.<br/>' +
- 'C2S: ' + (server.getTime() - client.getTime()).toString() + ' ms.<br/>'
- );
- });
+ $('#ping').html('Ping: ' + (now.getTime() - client.getTime()).toString() + ' ms.<br/>' +
+ 'C2S: ' + (server.getTime() - client.getTime()).toString() + ' ms.<br/>'
+ );
- setTimeout(sendPing, 500);
- }
- sendPing();
+ setTimeout(sendPing, 100);
+ });
+ }
+ sendPing();
+ });
});
</script>
</head>
View
@@ -14,8 +14,11 @@
});
var graph_items = ['active_sessions',
- 'avg_packets_sent',
- 'avg_packets_recv'];
+ 'active_connections',
+ 'connections_ps',
+ 'packets_sent_ps',
+ 'packets_recv_ps'
+ ];
// Flot stuff
var data = [], totalPoints = 60;
@@ -57,6 +60,7 @@
var name = graph_items[i];
res.push({
+ label: name,
data: convertValues(name)
});
}
@@ -71,14 +75,31 @@
plot.setData(prepareGraphData());
plot.draw();
+
+ // Update table
+ var placeholder = $('#table');
+ placeholder.empty();
+
+ var table = $('<table/>');
+ for (var i in data)
+ {
+ var item = data[i];
+
+ $('<tr/>')
+ .append($('<td/>').text(i))
+ .append($('<td/>').text(item))
+ .appendTo(placeholder);
+ }
+
+ table.appendTo(placeholder);
});
setTimeout(queryStats, 1000);
}
var options = {
series: { shadowSize: 0 },
- yaxis: { min: 0, max: 100 },
+ yaxis: { min: 0, max: 200 },
xaxis: { show: false }
};
@@ -90,7 +111,10 @@
</script>
</head>
<body>
-<h3>Connection stats!</h3>
- <div id="placeholder" style="width:600px;height:300px"></div>
+ <h3>Connection stats!</h3>
+ <div>
+ <div id="placeholder" style="width:600px;height:300px;float:left;"></div>
+ <div id="table"></div>
+ </div>
</body>
</html>
View
@@ -37,7 +37,9 @@ def stats(self):
return self.session.server.stats.dump()
# Create tornadio router
-PingRouter = TornadioRouter(PingConnection)
+PingRouter = TornadioRouter(PingConnection,
+ dict(enabled_protocols=['websocket', 'xhr-polling',
+ 'jsonp-polling', 'htmlfile']))
# Create socket application
application = web.Application(
@@ -50,8 +52,5 @@ def stats(self):
)
if __name__ == "__main__":
- import logging
- logging.getLogger().setLevel(logging.DEBUG)
-
# Create and start tornadio server
SocketServer(application)
View
@@ -45,11 +45,11 @@ def _get_session(self, session_id):
# If session was not found, ignore it
if session is None:
- raise HTTPError(401)
+ raise HTTPError(401, 'Invalid session')
# If session is closed, but there are some pending messages left - make sure to send them
if session.is_closed and not session.send_queue:
- raise HTTPError(401)
+ raise HTTPError(401, 'Invalid session')
return session
@@ -66,39 +66,43 @@ def get(self, session_id):
"""Default GET handler."""
raise NotImplementedError()
- @asynchronous
def post(self, session_id):
"""Handle incoming POST request"""
+ try:
+ # Stats
+ self.server.stats.connection_opened()
- # Get session
- self.session = self._get_session(session_id)
+ # Get session
+ self.session = self._get_session(session_id)
- # Can not send messages to closed session or if preflight() failed
- if self.session.is_closed or not self.preflight():
- raise HTTPError(401)
+ # Can not send messages to closed session or if preflight() failed
+ if self.session.is_closed or not self.preflight():
+ raise HTTPError(401)
- # Grab body and decode it (socket.io always sends data in utf-8)
- data = self.request.body.decode('utf-8')
+ # Grab body and decode it (socket.io always sends data in utf-8)
+ data = self.request.body.decode('utf-8')
- # IE XDomainRequest support
- if data.startswith(u'data='):
- data = data[5:]
+ # IE XDomainRequest support
+ if data.startswith(u'data='):
+ data = data[5:]
- # Process packets one by one
- packets = proto.decode_frames(data)
+ # Process packets one by one
+ packets = proto.decode_frames(data)
- # Tracking
- self.server.stats.on_packet_recv(len(packets))
+ # Tracking
+ self.server.stats.on_packet_recv(len(packets))
- for p in packets:
- try:
- self.session.raw_message(p)
- except Exception:
- # Close session if something went wrong
- self.session.close()
+ for p in packets:
+ try:
+ self.session.raw_message(p)
+ except Exception:
+ # Close session if something went wrong
+ self.session.close()
- self.set_header('Content-Type', 'text/plain; charset=UTF-8')
- self.finish()
+ self.set_header('Content-Type', 'text/plain; charset=UTF-8')
+ self.finish()
+ finally:
+ self.server.stats.connection_closed()
def check_xsrf_cookie(self):
pass
@@ -263,45 +267,50 @@ def get(self, session_id):
super(TornadioJSONPHandler, self).get(session_id)
- @asynchronous
def post(self, session_id):
- # Get session
- self.session = self._get_session(session_id)
+ try:
+ # Stats
+ self.server.stats.connection_opened()
- # Can not send messages to closed session or if preflight() failed
- if self.session.is_closed or not self.preflight():
- raise HTTPError(401)
+ # Get session
+ self.session = self._get_session(session_id)
- # Socket.io always send data utf-8 encoded.
- data = self.request.body
+ # Can not send messages to closed session or if preflight() failed
+ if self.session.is_closed or not self.preflight():
+ raise HTTPError(401)
- # IE XDomainRequest support
- if not data.startswith('d='):
- logging.error('Malformed JSONP POST request')
- raise HTTPError(403)
+ # Socket.io always send data utf-8 encoded.
+ data = self.request.body
- # Grab data
- data = urllib.unquote_plus(data[2:]).decode('utf-8')
+ # IE XDomainRequest support
+ if not data.startswith('d='):
+ logging.error('Malformed JSONP POST request')
+ raise HTTPError(403)
- # If starts with double quote, it is json encoded (socket.io workaround)
- if data.startswith(u'"'):
- data = proto.json_load(data)
+ # Grab data
+ data = urllib.unquote_plus(data[2:]).decode('utf-8')
- # Process packets one by one
- packets = proto.decode_frames(data)
+ # If starts with double quote, it is json encoded (socket.io workaround)
+ if data.startswith(u'"'):
+ data = proto.json_load(data)
- # Tracking
- self.server.stats.on_packet_recv(len(packets))
+ # Process packets one by one
+ packets = proto.decode_frames(data)
- for p in packets:
- try:
- self.session.raw_message(p)
- except Exception:
- # Close session if something went wrong
- self.session.close()
+ # Tracking
+ self.server.stats.on_packet_recv(len(packets))
- self.set_header('Content-Type', 'text/plain; charset=UTF-8')
- self.finish()
+ for p in packets:
+ try:
+ self.session.raw_message(p)
+ except Exception:
+ # Close session if something went wrong
+ self.session.close()
+
+ self.set_header('Content-Type', 'text/plain; charset=UTF-8')
+ self.finish()
+ finally:
+ self.server.stats.connection_closed()
def send_messages(self, messages):
if self._index is None:
Oops, something went wrong.

0 comments on commit 92d9711

Please sign in to comment.