From 793ec8514be49f836ae0559ad1396504470130c1 Mon Sep 17 00:00:00 2001 From: Aleksey Lim Date: Thu, 14 Nov 2013 09:58:07 +0000 Subject: Rename "resolution" parameter to "records" in stats API call --- diff --git a/sugar_network/node/routes.py b/sugar_network/node/routes.py index 57c1dff..7b36b12 100644 --- a/sugar_network/node/routes.py +++ b/sugar_network/node/routes.py @@ -35,7 +35,7 @@ from sugar_network.toolkit.bundle import Bundle from sugar_network.toolkit import pylru, http, coroutine, exception, enforce -_MAX_STATS_LENGTH = 100 +_MAX_STAT_RECORDS = 128 _AUTH_POOL_SIZE = 1024 _logger = logging.getLogger('node.routes') @@ -85,40 +85,27 @@ class NodeRoutes(model.VolumeRoutes, model.FrontRoutes): return {'guid': self._guid, 'resources': documents} @route('GET', cmd='stats', arguments={ - 'start': int, 'end': int, 'resolution': int, 'source': list}, + 'start': int, 'end': int, 'records': int, 'source': list}, mime_type='application/json') - def stats(self, start, end, resolution, source): - if not source: + def stats(self, start, end, records, source): + if not source or records <= 0 or start > end: return {} enforce(self._stats is not None, 'Node stats is disabled') - enforce(start < end, "Argument 'start' should be less than 'end'") - enforce(resolution > 0, "Argument 'resolution' should be more than 0") - min_resolution = (end - start) / _MAX_STATS_LENGTH - if resolution < min_resolution: - _logger.debug('Resulution is too short, use %s instead', - min_resolution) - resolution = min_resolution + if records > _MAX_STAT_RECORDS: + _logger.debug('Decrease %d stats records number to %d', + records, _MAX_STAT_RECORDS) + records = _MAX_STAT_RECORDS + resolution = (end - start) / records - dbs = {} + stats = {} for i in source: enforce('.' in i, 'Misnamed source') db_name, ds_name = i.split('.', 1) - dbs.setdefault(db_name, []).append(ds_name) - result = {} + stats.setdefault(db_name, []).append(ds_name) - for rdb in self._stats.rrd: - if rdb.name not in dbs: - continue - info = result[rdb.name] = [] - for ts, ds_values in rdb.get(start, end, resolution): - values = {} - for name in dbs[rdb.name]: - values[name] = ds_values.get(name) - info.append((ts, values)) - - return result + return self._stats.report(stats, start, end, resolution) @route('POST', ['user'], mime_type='application/json') def register(self, request): diff --git a/sugar_network/node/stats_node.py b/sugar_network/node/stats_node.py index ec54fc3..19dd82e 100644 --- a/sugar_network/node/stats_node.py +++ b/sugar_network/node/stats_node.py @@ -40,6 +40,8 @@ stats_node_rras = Option( ], type_cast=Option.list_cast, type_repr=Option.list_repr) +_MAX_FRAME = 64 + _logger = logging.getLogger('node.stats_node') @@ -47,31 +49,40 @@ class Sniffer(object): def __init__(self, volume): path = join(node.stats_root.value, 'node') - _logger.info('Start collecting node stats in %r', path) + _logger.info('Collect node stats in %r', path) self._volume = volume - self.rrd = Rrd(path, stats_node_step.value, stats_node_rras.value) + self._rrd = Rrd(path, stats_node_step.value, stats_node_rras.value) self._stats = {} - for cls in (_UserStats, _ContextStats, _ImplementationStats, - _ReportStats, _ReviewStats, _FeedbackStats, _SolutionStats, - _ArtifactStats, _CommentStats): - self._stats[cls.RESOURCE] = cls(self._stats, volume) + for name, cls in _STATS.items(): + self._stats[name] = cls(self._stats, volume) def log(self, request): - if request.cmd: + if request.cmd or request.resource in _STATS: return - stats = self._stats.get(request.resource) - if stats is not None: - stats.log(request) + self._stats[request.resource].log(request) def commit(self, timestamp=None): - _logger.heartbeat('Commit node stats') + _logger.trace('Commit node stats') for resource, stats in self._stats.items(): values = stats.commit() if values is not None: - self.rrd[resource].put(values, timestamp=timestamp) + self._rrd[resource].put(values, timestamp=timestamp) + + def report(self, dbs, start, end, resolution): + result = {} + for rdb in self._rrd: + if rdb.name not in dbs: + continue + info = result[rdb.name] = [] + for ts, ds_values in rdb.get(start, end, resolution): + values = {} + for name in dbs[rdb.name]: + values[name] = ds_values.get(name) + info.append((ts, values)) + return result class _ObjectStats(object): @@ -339,3 +350,15 @@ class _CommentStats(_Stats): if request.content.get(owner): self._stats[owner].commented += 1 break + + +_STATS = {_UserStats.RESOURCE: _UserStats, + _ContextStats.RESOURCE: _ContextStats, + _ImplementationStats.RESOURCE: _ImplementationStats, + _ReportStats.RESOURCE: _ReportStats, + _ReviewStats.RESOURCE: _ReviewStats, + _FeedbackStats.RESOURCE: _FeedbackStats, + _SolutionStats.RESOURCE: _SolutionStats, + _ArtifactStats.RESOURCE: _ArtifactStats, + _CommentStats.RESOURCE: _CommentStats, + } diff --git a/tests/units/node/node.py b/tests/units/node/node.py index e019df4..b989ef1 100755 --- a/tests/units/node/node.py +++ b/tests/units/node/node.py @@ -124,7 +124,7 @@ class NodeTest(tests.Test): (ts + 3, {'total': 3.0}), ], }, - cp.stats(ts, ts + 3, 1, ['user.total'])) + cp.stats(ts, ts + 3, 4, ['user.total'])) self.assertEqual({ 'user': [ @@ -134,7 +134,7 @@ class NodeTest(tests.Test): (ts + 12, {'total': 11.0}), ], }, - cp.stats(ts, ts + 12, 3, ['user.total'])) + cp.stats(ts, ts + 12, 4, ['user.total'])) def test_HandleDeletes(self): volume = db.Volume('db', model.RESOURCES) -- cgit v0.9.1