commit c3729a065931ff13898a8e98807c801bd33e5b99 Author: Damian Johnson atagar@torproject.org Date: Sun Nov 9 18:19:22 2014 -0800
Switching graph intervals back to an enum
This isn't a revert, but rather moving the interval back into the panel in a way that'll make this easier to maintain. This lets us do all config validation in the conf_handler(). That's what it's there for. ;) --- arm/config/attributes.cfg | 9 ---- arm/graph_panel.py | 108 ++++++++++++++++++++------------------------- arm/menu/actions.py | 6 +-- 3 files changed, 51 insertions(+), 72 deletions(-)
diff --git a/arm/config/attributes.cfg b/arm/config/attributes.cfg index 7452a71..b592e11 100644 --- a/arm/config/attributes.cfg +++ b/arm/config/attributes.cfg @@ -27,15 +27,6 @@ attr.hibernate_color awake => green attr.hibernate_color soft => yellow attr.hibernate_color hard => red
-attr.graph.intervals each second => 1 -attr.graph.intervals 5 seconds => 5 -attr.graph.intervals 30 seconds => 30 -attr.graph.intervals minutely => 60 -attr.graph.intervals 15 minute => 900 -attr.graph.intervals 30 minute => 1800 -attr.graph.intervals hourly => 3600 -attr.graph.intervals daily => 86400 - attr.graph.title bandwidth => Bandwidth attr.graph.title connections => Connection Count attr.graph.title resources => System Resources diff --git a/arm/graph_panel.py b/arm/graph_panel.py index 5af3fb0..0210b2e 100644 --- a/arm/graph_panel.py +++ b/arm/graph_panel.py @@ -27,8 +27,20 @@ from stem.control import Listener from stem.util import conf, enum, log, str_tools, system
GraphStat = enum.Enum(('BANDWIDTH', 'bandwidth'), ('CONNECTIONS', 'connections'), ('SYSTEM_RESOURCES', 'resources')) +Interval = enum.Enum(('EACH_SECOND', 'each second'), ('FIVE_SECONDS', '5 seconds'), ('THIRTY_SECONDS', '30 seconds'), ('MINUTELY', 'minutely'), ('FIFTEEN_MINUTE', '15 minute'), ('THIRTY_MINUTE', '30 minute'), ('HOURLY', 'hourly'), ('DAILY', 'daily')) Bounds = enum.Enum(('GLOBAL_MAX', 'global_max'), ('LOCAL_MAX', 'local_max'), ('TIGHT', 'tight'))
+INTERVAL_SECONDS = { + Interval.EACH_SECOND: 1, + Interval.FIVE_SECONDS: 5, + Interval.THIRTY_SECONDS: 30, + Interval.MINUTELY: 60, + Interval.FIFTEEN_MINUTE: 900, + Interval.THIRTY_MINUTE: 1800, + Interval.HOURLY: 3600, + Interval.DAILY: 86400, +} + PRIMARY_COLOR, SECONDARY_COLOR = 'green', 'cyan'
ACCOUNTING_RATE = 5 @@ -42,20 +54,31 @@ def conf_handler(key, value): return max(1, value) elif key == 'features.graph.max_width': return max(1, value) + elif key == 'features.graph.type': + if value != 'none' and value not in GraphStat: + log.warn("'%s' isn't a valid graph type, options are: none, %s" % (CONFIG['features.graph.type'], ', '.join(GraphStat))) + return CONFIG['features.graph.type'] # keep the default + elif key == 'features.graph.interval': + if value not in Interval: + log.warn("'%s' isn't a valid graphing interval, options are: %s" % (value, ', '.join(Interval))) + return CONFIG['features.graph.interval'] # keep the default + elif key == 'features.graph.bound': + if value not in Bounds: + log.warn("'%s' isn't a valid graph bounds, options are: %s" % (value, ', '.join(Bounds))) + return CONFIG['features.graph.bound'] # keep the default
CONFIG = conf.config_dict('arm', { 'attr.hibernate_color': {}, - 'attr.graph.intervals': {}, 'attr.graph.title': {}, 'attr.graph.header.primary': {}, 'attr.graph.header.secondary': {}, 'features.graph.height': 7, - 'features.graph.interval': 'each second', + 'features.graph.type': GraphStat.BANDWIDTH, + 'features.graph.interval': Interval.EACH_SECOND, 'features.graph.bound': Bounds.LOCAL_MAX, 'features.graph.max_width': 150, 'features.graph.showIntermediateBounds': True, - 'features.graph.type': 'bandwidth', 'features.panels.show.connection': True, 'features.graph.bw.prepopulate': True, 'features.graph.bw.transferInBytes': False, @@ -70,6 +93,8 @@ class Stat(object):
:var int latest_value: last value we recorded :var int total: sum of all values we've recorded + :var int tick: number of events we've processed + :var float start_time: unix timestamp for when we started :var dict values: mapping of intervals to an array of samplings from newest to oldest :var dict max_value: mapping of intervals to the maximum value it has had """ @@ -88,17 +113,20 @@ class Stat(object): self.total = 0 self.tick = 0 self.start_time = time.time() - self.values = dict([(i, CONFIG['features.graph.max_width'] * [0]) for i in CONFIG['attr.graph.intervals']]) - self.max_value = dict([(i, 0) for i in CONFIG['attr.graph.intervals']]) - self._in_process_value = dict([(i, 0) for i in CONFIG['attr.graph.intervals']]) + self.values = dict([(i, CONFIG['features.graph.max_width'] * [0]) for i in Interval]) + self.max_value = dict([(i, 0) for i in Interval]) + self._in_process_value = dict([(i, 0) for i in Interval]) + + def average(self): + return self.total / max(1, self.tick)
def update(self, new_value): self.latest_value = new_value self.total += new_value self.tick += 1
- for interval in CONFIG['attr.graph.intervals']: - interval_seconds = int(CONFIG['attr.graph.intervals'][interval]) + for interval in Interval: + interval_seconds = INTERVAL_SECONDS[interval] self._in_process_value[interval] += new_value
if self.tick % interval_seconds == 0: @@ -147,7 +175,7 @@ class GraphCategory(object): :returns: **str** with our y-axis label """
- return '' + return str(value)
def bandwidth_event(self, event): """ @@ -188,8 +216,6 @@ class BandwidthStats(GraphCategory): return str_tools.size_label(value, is_bytes = CONFIG['features.graph.bw.transferInBytes'])
def bandwidth_event(self, event): - # scales units from B to KB for graphing - self.primary.update(event.read) self.secondary.update(event.written)
@@ -244,9 +270,6 @@ class ConnectionStats(GraphCategory): Tracks number of inbound and outbound connections. """
- def y_axis_label(self, value, is_primary): - return str(value) - def bandwidth_event(self, event): inbound_count, outbound_count = 0, 0
@@ -266,11 +289,8 @@ class ConnectionStats(GraphCategory): self.primary.update(inbound_count) self.secondary.update(outbound_count)
- avg = self.primary.total / max(1, self.primary.tick) - self.primary_header_stats = [str(self.primary.latest_value), ', avg: %s' % avg] - - avg = self.secondary.total / max(1, self.secondary.tick) - self.secondary_header_stats = [str(self.secondary.latest_value), ', avg: %s' % avg] + self.primary_header_stats = [str(self.primary.latest_value), ', avg: %s' % self.primary.average()] + self.secondary_header_stats = [str(self.secondary.latest_value), ', avg: %s' % self.secondary.average()]
class ResourceStats(GraphCategory): @@ -279,18 +299,15 @@ class ResourceStats(GraphCategory): """
def y_axis_label(self, value, is_primary): - return "%i%%" % value if is_primary else str_tools.size_label(value) + return '%i%%' % value if is_primary else str_tools.size_label(value)
def bandwidth_event(self, event): resources = arm.util.tracker.get_resource_tracker().get_value() self.primary.update(resources.cpu_sample * 100) # decimal percentage to whole numbers self.secondary.update(resources.memory_bytes)
- avg = self.primary.total / max(1, self.primary.tick) - self.primary_header_stats = ['%0.1f%%' % self.primary.latest_value, ', avg: %0.1f%%' % avg] - - avg = self.secondary.total / max(1, self.secondary.tick) - self.secondary_header_stats = [str_tools.size_label(self.secondary.latest_value, 1), ', avg: %s' % str_tools.size_label(avg, 1)] + self.primary_header_stats = ['%0.1f%%' % self.primary.latest_value, ', avg: %0.1f%%' % self.primary.average()] + self.secondary_header_stats = [str_tools.size_label(self.secondary.latest_value, 1), ', avg: %s' % str_tools.size_label(self.secondary.average(), 1)]
class GraphPanel(panel.Panel): @@ -302,20 +319,11 @@ class GraphPanel(panel.Panel): def __init__(self, stdscr): panel.Panel.__init__(self, stdscr, 'graph', 0)
- if CONFIG['features.graph.interval'] in CONFIG['attr.graph.intervals']: - self.update_interval = CONFIG['features.graph.interval'] - else: - self.update_interval = 'each second' - log.warn("'%s' isn't a valid graphing interval, options are: %s" % (CONFIG['features.graph.interval'], ', '.join(CONFIG['attr.graph.intervals']))) - - if CONFIG['features.graph.bound'] in Bounds: - self.bounds = CONFIG['features.graph.bound'] - else: - self.bounds = Bounds.LOCAL_MAX - log.warn("'%s' isn't a valid graph bounds, options are: %s" % (CONFIG['features.graph.bound'], ', '.join(Bounds))) + self.current_display = None if CONFIG['features.graph.type'] == 'none' else CONFIG['features.graph.type'] + self.update_interval = CONFIG['features.graph.interval'] + self.bounds = CONFIG['features.graph.bound']
self.graph_height = max(1, CONFIG['features.graph.height']) - self.current_display = None # label of the stats currently being displayed self._accounting_stats = None self._last_redraw = 0
@@ -330,13 +338,6 @@ class GraphPanel(panel.Panel): self.set_pause_attr('stats') self.set_pause_attr('_accounting_stats')
- if CONFIG['features.graph.type'] == 'none': - self.set_stats(None) - elif CONFIG['features.graph.type'] in GraphStat: - self.set_stats(CONFIG['features.graph.type']) - else: - log.warn("'%s' isn't a graph type." % CONFIG['features.graph.type']) - # prepopulates bandwidth values from state file
controller = tor_controller() @@ -369,7 +370,7 @@ class GraphPanel(panel.Panel):
arm.controller.get_controller().redraw()
- update_rate = int(CONFIG['attr.graph.intervals'][self.update_interval]) + update_rate = INTERVAL_SECONDS[self.update_interval]
if time.time() - self._last_redraw > update_rate: self.redraw(True) @@ -510,11 +511,10 @@ class GraphPanel(panel.Panel): elif key.match('i'): # provides menu to pick graph panel update interval
- options = CONFIG['attr.graph.intervals'].keys() - selection = arm.popups.show_menu('Update Interval:', options, CONFIG['attr.graph.intervals'].keys().index(self.update_interval)) + selection = arm.popups.show_menu('Update Interval:', list(Interval), list(Interval).index(self.update_interval))
if selection != -1: - self.update_interval = CONFIG['attr.graph.intervals'].keys()[selection] + self.update_interval = list(Interval)[selection] else: return False
@@ -632,7 +632,7 @@ class GraphPanel(panel.Panel):
# bottom labeling of x-axis
- interval_sec = int(CONFIG['attr.graph.intervals'][self.update_interval]) # seconds per labeling + interval_sec = INTERVAL_SECONDS[self.update_interval]
interval_spacing = 10 if graph_column >= WIDE_LABELING_GRAPH_COL else 5 units_label, decimal_precision = None, 0 @@ -746,16 +746,6 @@ def prepopulate_from_state(stat): bw_read_entries = bw_read_entries[len(bw_read_entries) - entry_count:] bw_write_entries = bw_write_entries[len(bw_write_entries) - entry_count:]
- # gets index for 15-minute interval - - interval_index = 0 - - for interval_rate in CONFIG['attr.graph.intervals'].values(): - if int(interval_rate) == 900: - break - else: - interval_index += 1 - # fills the graphing parameters with state information
for i in range(entry_count): diff --git a/arm/menu/actions.py b/arm/menu/actions.py index 28e4e16..3f70e66 100644 --- a/arm/menu/actions.py +++ b/arm/menu/actions.py @@ -19,7 +19,6 @@ from stem.util import conf, str_tools
CONFIG = conf.config_dict('arm', { 'features.log.showDuplicateEntries': False, - 'attr.graph.intervals': {}, })
@@ -168,9 +167,8 @@ def make_graph_menu(graph_panel): interval_menu = arm.menu.item.Submenu("Interval") interval_group = arm.menu.item.SelectionGroup(graph_panel.set_update_interval, graph_panel.get_update_interval())
- for interval in CONFIG['attr.graph.intervals']: - label = str_tools._to_camel_case(interval, divider = " ") - interval_menu.add(arm.menu.item.SelectionMenuItem(label, interval_group, interval)) + for interval in arm.graph_panel.Interval: + interval_menu.add(arm.menu.item.SelectionMenuItem(interval, interval_group, interval))
graph_menu.add(interval_menu)
tor-commits@lists.torproject.org