[tor-commits] [arm/master] Used a named tuple for header panel samplings

atagar at torproject.org atagar at torproject.org
Sat Oct 4 22:52:07 UTC 2014


commit e313313ce6e3378bf73e4a78f8fcfc6837592c06
Author: Damian Johnson <atagar at torproject.org>
Date:   Sat Oct 4 15:49:21 2014 -0700

    Used a named tuple for header panel samplings
    
    I keep swapping between dics, named tuples, and standalone classes for this.
    Think this is the best option I've come up with yet.
---
 arm/header_panel.py |  205 ++++++++++++++++++++++++---------------------------
 1 file changed, 98 insertions(+), 107 deletions(-)

diff --git a/arm/header_panel.py b/arm/header_panel.py
index 5dc3127..9b8ecd2 100644
--- a/arm/header_panel.py
+++ b/arm/header_panel.py
@@ -4,6 +4,7 @@ This expands the information it presents to two columns if there's room
 available.
 """
 
+import collections
 import os
 import time
 import curses
@@ -39,7 +40,7 @@ class HeaderPanel(panel.Panel, threading.Thread):
     threading.Thread.__init__(self)
     self.setDaemon(True)
 
-    self._vals = Sampling()
+    self._vals = get_sampling()
 
     self._pause_condition = threading.Condition()
     self._halt = False  # terminates thread if true
@@ -178,8 +179,10 @@ class HeaderPanel(panel.Panel, threading.Thread):
       space_left -= x - 43 - initial_x
 
       if space_left >= 7 + len(vals.version_status):
+        version_color = CONFIG['attr.version_status_colors'].get(vals.version_status, 'white')
+
         x = self.addstr(y, x, ' (')
-        x = self.addstr(y, x, vals.version_status, vals.version_color)
+        x = self.addstr(y, x, vals.version_status, version_color)
         self.addstr(y, x, ')')
 
   def _draw_ports_section(self, x, y, width, vals):
@@ -264,7 +267,7 @@ class HeaderPanel(panel.Panel, threading.Thread):
     x = self.addstr(y, x, vals.format('fingerprint: {fingerprint}', width))
     space_left -= x - initial_x
 
-    if space_left >= 30 and vals.fd_used and vals.fd_limit:
+    if space_left >= 30 and vals.fd_used and vals.fd_limit != -1:
       fd_percent = 100 * vals.fd_used / vals.fd_limit
 
       if fd_percent >= SHOW_FD_THRESHOLD:
@@ -372,81 +375,10 @@ class HeaderPanel(panel.Panel, threading.Thread):
 
   def _update(self):
     previous_height = self.get_height()
-    self._vals = Sampling(self._vals)
-
-    if previous_height != self.get_height():
-      # We're toggling between being a relay and client, causing the height
-      # of this panel to change. Redraw all content so we don't get
-      # overlapping content.
-
-      arm.controller.get_controller().redraw()
-    else:
-      self.redraw(True)  # just need to redraw ourselves
-
-
-class Sampling(object):
-  """
-  Statistical information rendered by the header panel.
-  """
-
-  def __init__(self, last_sampling = None):
-    controller = tor_controller()
-
-    self.retrieved = time.time()
-    self.is_connected = controller.is_alive()
-    self.connection_time = controller.connection_time()
-    self.last_heartbeat = time.strftime('%H:%M %m/%d/%Y', time.localtime(controller.get_latest_heartbeat()))
-
-    self.fingerprint = controller.get_info('fingerprint', 'Unknown')
-    self.nickname = controller.get_conf('Nickname', '')
-    self.newnym_wait = controller.get_newnym_wait()
-    self.exit_policy = controller.get_exit_policy(None)
-    self.flags = getattr(controller.get_network_status(default = None), 'flags', [])
-
-    self.version = str(controller.get_version('Unknown')).split()[0]
-    self.version_status = controller.get_info('status/version/current', 'Unknown')
-    self.version_color = CONFIG['attr.version_status_colors'].get(self.version_status, 'white')
-
-    or_listeners = controller.get_listeners(Listener.OR, [])
-    control_listeners = controller.get_listeners(Listener.CONTROL, [])
-    self.address = or_listeners[0][0] if (or_listeners and or_listeners[0][0] != '0.0.0.0') else controller.get_info('address', 'Unknown')
-    self.or_port = or_listeners[0][1] if or_listeners else ''
-    self.dir_port = controller.get_conf('DirPort', '0')
-    self.control_port = str(control_listeners[0][1]) if control_listeners else None
-    self.socket_path = controller.get_conf('ControlSocket', None)
-    self.is_relay = bool(self.or_port)
-
-    if controller.get_conf('HashedControlPassword', None):
-      self.auth_type = 'password'
-    elif controller.get_conf('CookieAuthentication', None) == '1':
-      self.auth_type = 'cookie'
-    else:
-      self.auth_type = 'open'
-
-    self.pid = controller.get_pid('')
-    self.start_time = system.start_time(self.pid)
-
-    fd_limit = controller.get_info('process/descriptor-limit', '-1')
-    self.fd_limit = int(fd_limit) if fd_limit.isdigit() else None
-
-    try:
-      self.fd_used = proc.file_descriptors_used(self.pid)
-    except IOError:
-      self.fd_used = None
+    self._vals = get_sampling(self._vals)
 
-    tor_resources = tracker.get_resource_tracker().get_value()
-    self.arm_total_cpu_time = sum(os.times()[:3])
-    self.tor_cpu = '%0.1f' % (100 * tor_resources.cpu_sample)
-    self.arm_cpu = '%0.1f' % (100 * self._get_cpu_percentage(last_sampling))
-    self.memory = str_tools.size_label(tor_resources.memory_bytes) if tor_resources.memory_bytes > 0 else 0
-    self.memory_percent = '%0.1f' % (100 * tor_resources.memory_percent)
-
-    uname_vals = os.uname()
-    self.hostname = uname_vals[1]
-    self.platform = '%s %s' % (uname_vals[0], uname_vals[2])  # [platform name] [version]
-
-    if self.fd_used and self.fd_limit:
-      fd_percent = 100 * self.fd_used / self.fd_limit
+    if self._vals.fd_used and self._vals.fd_limit != -1:
+      fd_percent = 100 * self._vals.fd_used / self._vals.fd_limit
 
       if fd_percent >= 90:
         log_msg = msg('panel.header.fd_used_at_ninety_percent', percentage = fd_percent)
@@ -456,36 +388,95 @@ class Sampling(object):
         log_msg = msg('panel.header.fd_used_at_sixty_percent', percentage = fd_percent)
         log.log_once('fd_used_at_sixty_percent', log.NOTICE, log_msg)
 
-  def format(self, message, crop_width = None):
-    """
-    Applies our attributes to the given string.
-    """
-
-    formatted_msg = message.format(**self.__dict__)
-
-    if crop_width:
-      formatted_msg = str_tools.crop(formatted_msg, crop_width)
-
-    return formatted_msg
-
-  def _get_cpu_percentage(self, last_sampling):
-    """
-    Determine the cpu usage of our own process since the last sampling.
-
-    :param arm.header_panel.Sampling last_sampling: sampling for which to
-      provide a CPU usage delta with
-
-    :returns: **float** representation for our cpu usage over the given period
-      of time
-    """
+    if previous_height != self.get_height():
+      # We're toggling between being a relay and client, causing the height
+      # of this panel to change. Redraw all content so we don't get
+      # overlapping content.
 
-    if last_sampling:
-      arm_cpu_delta = self.arm_total_cpu_time - last_sampling.arm_total_cpu_time
-      arm_time_delta = self.retrieved - last_sampling.retrieved
+      arm.controller.get_controller().redraw()
+    else:
+      self.redraw(True)  # just need to redraw ourselves
 
-      python_cpu_time = arm_cpu_delta / arm_time_delta
-      sys_call_cpu_time = 0.0  # TODO: add a wrapper around call() to get this
 
-      return python_cpu_time + sys_call_cpu_time
-    else:
-      return 0.0
+def get_sampling(last_sampling = None):
+  controller = tor_controller()
+  retrieved = time.time()
+
+  pid = controller.get_pid('')
+  tor_resources = tracker.get_resource_tracker().get_value()
+  arm_total_cpu_time = sum(os.times()[:3])
+
+  or_listeners = controller.get_listeners(Listener.OR, [])
+  control_listeners = controller.get_listeners(Listener.CONTROL, [])
+
+  if controller.get_conf('HashedControlPassword', None):
+    auth_type = 'password'
+  elif controller.get_conf('CookieAuthentication', None) == '1':
+    auth_type = 'cookie'
+  else:
+    auth_type = 'open'
+
+  try:
+    fd_used = proc.file_descriptors_used(pid)
+  except IOError:
+    fd_used = None
+
+  if last_sampling:
+    arm_cpu_delta = arm_total_cpu_time - last_sampling.arm_total_cpu_time
+    arm_time_delta = retrieved - last_sampling.retrieved
+
+    python_cpu_time = arm_cpu_delta / arm_time_delta
+    sys_call_cpu_time = 0.0  # TODO: add a wrapper around call() to get this
+
+    arm_cpu = python_cpu_time + sys_call_cpu_time
+  else:
+    arm_cpu = 0.0
+
+  attr = {
+    'retrieved': retrieved,
+    'is_connected': controller.is_alive(),
+    'connection_time': controller.connection_time(),
+    'last_heartbeat': time.strftime('%H:%M %m/%d/%Y', time.localtime(controller.get_latest_heartbeat())),
+
+    'fingerprint': controller.get_info('fingerprint', 'Unknown'),
+    'nickname': controller.get_conf('Nickname', ''),
+    'newnym_wait': controller.get_newnym_wait(),
+    'exit_policy': controller.get_exit_policy(None),
+    'flags': getattr(controller.get_network_status(default = None), 'flags', []),
+
+    'version': str(controller.get_version('Unknown')).split()[0],
+    'version_status': controller.get_info('status/version/current', 'Unknown'),
+
+    'address': or_listeners[0][0] if (or_listeners and or_listeners[0][0] != '0.0.0.0') else controller.get_info('address', 'Unknown'),
+    'or_port': or_listeners[0][1] if or_listeners else '',
+    'dir_port': controller.get_conf('DirPort', '0'),
+    'control_port': str(control_listeners[0][1]) if control_listeners else None,
+    'socket_path': controller.get_conf('ControlSocket', None),
+    'is_relay': bool(or_listeners),
+
+    'auth_type': auth_type,
+    'pid': pid,
+    'start_time': system.start_time(pid),
+    'fd_limit': int(controller.get_info('process/descriptor-limit', '-1')),
+    'fd_used': fd_used,
+
+    'arm_total_cpu_time': arm_total_cpu_time,
+    'tor_cpu': '%0.1f' % (100 * tor_resources.cpu_sample),
+    'arm_cpu': arm_cpu,
+    'memory': str_tools.size_label(tor_resources.memory_bytes) if tor_resources.memory_bytes > 0 else 0,
+    'memory_percent': '%0.1f' % (100 * tor_resources.memory_percent),
+
+    'hostname': os.uname()[1],
+    'platform': '%s %s' % (os.uname()[0], os.uname()[2]),  # [platform name] [version]
+  }
+
+  class Sampling(collections.namedtuple('Sampling', attr.keys())):
+    def format(self, message, crop_width = None):
+      formatted_msg = message.format(**super(Sampling, self).__dict__)
+
+      if crop_width:
+        formatted_msg = str_tools.crop(formatted_msg, crop_width)
+
+      return formatted_msg
+
+  return Sampling(**attr)



More information about the tor-commits mailing list