From e1dba4abeb61b390f8ff6922c46aa191c845a6c5 Mon Sep 17 00:00:00 2001 From: Corbin Simpson Date: Fri, 26 Feb 2016 11:14:31 -0800 Subject: [PATCH] stats: Dump a JSON file next to the pickle file. Extremely useful for interoperating with non-Python (e.g. Monte) tooling. --- docs/stats.rst | 11 ++++++----- src/allmydata/stats.py | 13 +++++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/docs/stats.rst b/docs/stats.rst index c6d5abf7c..711b50dfd 100644 --- a/docs/stats.rst +++ b/docs/stats.rst @@ -310,13 +310,14 @@ given port. The portnum file is actually a "strports specification string", as described in :doc:`configuration`. Once running, the stats gatherer will create a standard python "pickle" file -in $BASEDIR/stats.pickle . Once a minute, the gatherer will pull stats +in ``$BASEDIR/stats.pickle``, and a standard JSON file in +``$BASEDIR/stats.json``. Once a minute, the gatherer will pull stats information from every connected node and write them into the pickle. The pickle will contain a dictionary, in which node identifiers (known as "tubid" -strings) are the keys, and the values are a dict with 'timestamp', -'nickname', and 'stats' keys. d[tubid][stats] will contain the stats -dictionary as made available at http://localhost:3456/statistics?t=json . The -pickle file will only contain the most recent update from each node. +strings) are the keys, and the values are a dict with 'timestamp', 'nickname', +and 'stats' keys. d[tubid][stats] will contain the stats dictionary as made +available at http://localhost:3456/statistics?t=json . The pickle file will +only contain the most recent update from each node. Other tools can be built to examine these stats and render them into something useful. For example, a tool could sum the diff --git a/src/allmydata/stats.py b/src/allmydata/stats.py index 4e9fd8cf3..114ff612f 100644 --- a/src/allmydata/stats.py +++ b/src/allmydata/stats.py @@ -1,4 +1,5 @@ +import json import os import pickle import pprint @@ -247,6 +248,7 @@ class PickleStatsGatherer(StdOutStatsGatherer): self.verbose = verbose StatsGatherer.__init__(self, basedir) self.picklefile = os.path.join(basedir, "stats.pickle") + self.jsonfile = os.path.join(basedir, "stats.json") if os.path.exists(self.picklefile): f = open(self.picklefile, 'rb') @@ -267,6 +269,7 @@ class PickleStatsGatherer(StdOutStatsGatherer): s['nickname'] = nickname s['stats'] = stats self.dump_pickle() + self.dump_json() def dump_pickle(self): tmp = "%s.tmp" % (self.picklefile,) @@ -277,6 +280,16 @@ class PickleStatsGatherer(StdOutStatsGatherer): os.unlink(self.picklefile) os.rename(tmp, self.picklefile) + def dump_json(self): + # Same logic as pickle, but using JSON instead. + tmp = "%s.tmp" % (self.jsonfile,) + f = open(tmp, 'wb') + json.dump(self.gathered_stats, f) + f.close() + if os.path.exists(self.jsonfile): + os.unlink(self.jsonfile) + os.rename(tmp, self.jsonfile) + class StatsGathererService(service.MultiService): furl_file = "stats_gatherer.furl"