[tor-commits] [metrics-tasks/master] task-6329: Add tor-relay-stats.py as posted on tor-relays@ on 2012-07-12
karsten at torproject.org
karsten at torproject.org
Sun Jul 15 08:17:02 UTC 2012
commit 8417025094b60f41b28d64d1b62a801a618c9bca
Author: delber <delber at riseup.net>
Date: Sat Jul 14 11:59:41 2012 +0000
task-6329: Add tor-relay-stats.py as posted on tor-relays@ on 2012-07-12
---
task-6329/tor-relays-stats.py | 125 +++++++++++++++++++++++++++++++++++++++++
1 files changed, 125 insertions(+), 0 deletions(-)
diff --git a/task-6329/tor-relays-stats.py b/task-6329/tor-relays-stats.py
new file mode 100755
index 0000000..0aa4854
--- /dev/null
+++ b/task-6329/tor-relays-stats.py
@@ -0,0 +1,125 @@
+#!/usr/bin/env python
+#
+# tor-relay-stats.py: extract some statistics about relays
+#
+# This script expect to have a file called 'details.json' in the
+# current directory. In order to retrieve the needed data, one
+# can issue the following command:
+#
+# curl -o details.json https://onionoo.torproject.org/details
+#
+#
+# Author: delber at riseup.net
+#
+# This program is free software. It comes without any warranty, to
+# the extent permitted by applicable law. You can redistribute it
+# and/or modify it under the terms of the Do What The Fuck You Want
+# To Public License, Version 2, as published by Sam Hocevar. See
+# http://sam.zoy.org/wtfpl/COPYING for more details.
+
+import json
+import operator
+import sys
+
+class RelayStats(object):
+ def __init__(self):
+ self._data = None
+
+ @property
+ def data(self):
+ if not self._data:
+ self._data = json.load(file('details.json'))
+ return self._data
+
+ def get_total_consensus_weight(self, relays=None):
+ if relays is None:
+ relays = self.get_relays()
+ total_consensus_weight = 0
+ for relay in relays:
+ total_consensus_weight += relay['consensus_weight']
+ return total_consensus_weight
+
+ def get_relays(self, flags=[], countries=''):
+ relays = []
+ for relay in self.data['relays']:
+ if not relay['running']:
+ continue
+ if set(flags) & set(relay['flags']) != set(flags):
+ continue
+ if countries and not relay.get('country', '') in countries:
+ continue
+ relays.append(relay)
+ return relays
+
+ def output_countries(self, flags=''):
+ flags = flags.split()
+ relays = self.get_relays(flags)
+ countries = {}
+ for relay in relays:
+ country = relay.get('country', None)
+ if country not in countries:
+ countries[country] = 0
+ countries[country] += relay['consensus_weight']
+
+ total_consensus_weight = self.get_total_consensus_weight(relays)
+ for country, weight in sorted(countries.iteritems(), key=operator.itemgetter(1)):
+ print "%3.2f%% %s" % (weight * 100.0 / total_consensus_weight, country)
+
+ def output_as_sets(self, flags='', countries=''):
+ flags = flags.split()
+ relays = self.get_relays(flags, countries)
+ as_sets = {}
+ for relay in relays:
+ as_set = relay.get('as_name', 'Unknown')
+ if as_set not in as_sets:
+ as_sets[as_set] = 0
+ as_sets[as_set] += relay['consensus_weight']
+
+ total_consensus_weight = self.get_total_consensus_weight(relays)
+ for as_set, weight in sorted(as_sets.iteritems(), key=operator.itemgetter(1)):
+ print "%3.4f%% %s" % (weight * 100.0 / total_consensus_weight, as_set)
+
+ def output_top(self, count='10', flags='', countries=''):
+ count = int(count)
+ flags = flags.split()
+ relays = self.get_relays(flags, countries)
+ top = sorted(relays, key=operator.itemgetter('consensus_weight'))
+ total_consensus_weight = self.get_total_consensus_weight()
+ for relay in top[-count:]:
+
+ print "%3.4f%% %-20s %s" % (relay['consensus_weight'] * 100.0 / total_consensus_weight, relay['nickname'], relay['fingerprint'])
+
+OUTPUTS = {
+ 'countries': 'output_countries',
+ 'as-sets': 'output_as_sets',
+ 'top': 'output_top',
+}
+
+def usage():
+ print >>sys.stderr, """Usage: %(progname)s <output> [args ...]
+
+Where <output> is one of:
+ - countries [FLAGS]
+ relative percentage of the consensus in each countries
+ - as-sets [FLAGS] [COUNTRIES]
+ relative percentage of the consensus in each AS sets
+ - top [COUNT] [FLAGS] [COUNTRIES]
+ top relays according their place in the whole consensus
+
+Examples:
+
+ - To get the top five exit nodes in France:
+ %(progname)s top 5 Exit fr
+ - To get weights of each AS of all relays in Germany:
+ %(progname)s as-sets Running de
+""" % { 'progname': sys.argv[0] }
+ sys.exit(1)
+
+if '__main__' == __name__:
+ if len(sys.argv) == 1:
+ usage()
+ func = OUTPUTS.get(sys.argv[1], None)
+ if not func:
+ usage()
+ stats = RelayStats()
+ getattr(stats, func)(*sys.argv[2:])
More information about the tor-commits
mailing list