[tor-commits] [nyx/master] Finish rewriting the log panel

atagar at torproject.org atagar at torproject.org
Tue May 5 05:42:06 UTC 2015


commit 454803d2516cf53c91a9f0068003761168fcbcf7
Author: Damian Johnson <atagar at torproject.org>
Date:   Mon May 4 22:35:38 2015 -0700

    Finish rewriting the log panel
    
    Not completely perfect, but damn close. Happy enough with it to finally merge. :P
---
 nyx/graph_panel.py  |    3 +--
 nyx/header_panel.py |    5 ++--
 nyx/log_panel.py    |   74 ++++++++++++++++++++-------------------------------
 3 files changed, 32 insertions(+), 50 deletions(-)

diff --git a/nyx/graph_panel.py b/nyx/graph_panel.py
index 3cc60bd..cf43492 100644
--- a/nyx/graph_panel.py
+++ b/nyx/graph_panel.py
@@ -20,10 +20,9 @@ import nyx.controller
 import nyx.popups
 import nyx.util.tracker
 
-from nyx.util import join, msg, panel, tor_controller
-
 from stem.control import EventType, Listener
 from stem.util import conf, enum, log, str_tools, system
+from nyx.util import join, msg, panel, tor_controller
 
 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'))
diff --git a/nyx/header_panel.py b/nyx/header_panel.py
index df63174..4eb0a84 100644
--- a/nyx/header_panel.py
+++ b/nyx/header_panel.py
@@ -10,14 +10,13 @@ import time
 import curses
 import threading
 
+import stem
+
 import nyx.controller
 import nyx.popups
 
-import stem
-
 from stem.control import Listener
 from stem.util import conf, log, proc, str_tools, system
-
 from nyx.util import msg, tor_controller, panel, tracker
 
 MIN_DUAL_COL_WIDTH = 141  # minimum width where we'll show two columns
diff --git a/nyx/log_panel.py b/nyx/log_panel.py
index 300af83..626a42f 100644
--- a/nyx/log_panel.py
+++ b/nyx/log_panel.py
@@ -9,15 +9,13 @@ import time
 import curses
 import threading
 
-import stem
 import stem.response.events
 
-from stem.util import conf, log, str_tools
-
 import nyx.arguments
 import nyx.popups
 import nyx.util.log
 
+from stem.util import conf, log, str_tools
 from nyx.util import join, panel, tor_controller, ui_tools
 
 
@@ -45,6 +43,8 @@ CONFIG = conf.config_dict('nyx', {
   'attr.log_color': {},
 }, conf_handler)
 
+TIMEZONE_OFFSET = time.altzone if time.localtime()[8] else time.timezone
+
 # The height of the drawn content is estimated based on the last time we redrew
 # the panel. It's chiefly used for scrolling and the bar indicating its
 # position. Letting the estimate be too inaccurate results in a display bug, so
@@ -55,14 +55,14 @@ CONTENT_HEIGHT_REDRAW_THRESHOLD = 3
 # Log buffer so we start collecting stem/nyx events when imported. This is used
 # to make our LogPanel when curses initializes.
 
-stem_logger = stem.util.log.get_logger()
+stem_logger = log.get_logger()
 NYX_LOGGER = log.LogBuffer(log.Runlevel.DEBUG, yield_records = True)
 stem_logger.addHandler(NYX_LOGGER)
 
 
 class LogPanel(panel.Panel, threading.Thread):
   """
-  Listens for and displays tor, nyx, and stem events. This can prepopulate
+  Listens for and displays tor, nyx, and stem events. This prepopulates
   from tor's log file if it exists.
   """
 
@@ -71,19 +71,16 @@ class LogPanel(panel.Panel, threading.Thread):
     threading.Thread.__init__(self)
     self.setDaemon(True)
 
+    self._logged_events = nyx.util.log.LogGroup(CONFIG['cache.log_panel.size'], group_by_day = True)
     self._logged_event_types = nyx.util.log.listen_for_events(self._register_tor_event, logged_events)
-    self._logged_events = nyx.util.log.LogGroup(CONFIG['cache.log_panel.size'])
     self._log_file = nyx.util.log.LogFileOutput(CONFIG['features.logFile'])
     self._filter = nyx.util.log.LogFilters(initial_filters = CONFIG['features.log.regex'])
 
     self.set_pause_attr('_logged_events')
 
-    self._last_content_height = 0  # height of the rendered content when last drawn
-    self._scroll = 0
-
     self._halt = False  # terminates thread if true
-    self._pause_condition = threading.Condition()
     self._lock = threading.RLock()
+    self._pause_condition = threading.Condition()
     self._has_new_event = False
 
     # fetches past tor events from log file, if available
@@ -101,24 +98,22 @@ class LogPanel(panel.Panel, threading.Thread):
         except ValueError as exc:
           log.info(str(exc))
 
-    # stop logging to NYX_LOGGER, adding its event backlog and future ones
+    self._last_content_height = len(self._logged_events)  # height of the rendered content when last drawn
+    self._scroll = 0
+
+    # merge NYX_LOGGER into us, and listen for its future events
 
     for event in NYX_LOGGER:
       self._register_nyx_event(event)
 
     NYX_LOGGER.emit = self._register_nyx_event
 
-    # leaving last_content_height as being too low causes initialization problems
-
-    self._last_content_height = len(self._logged_events)
-
   def set_duplicate_visability(self, is_visible):
     """
     Sets if duplicate log entries are collaped or expanded.
 
-    Arguments:
-      is_visible - if true all log entries are shown, otherwise they're
-                   deduplicated
+    :param bool is_visible: if **True** all log entries are shown, otherwise
+      they're deduplicated
     """
 
     nyx_config = conf.get_config('nyx')
@@ -166,10 +161,10 @@ class LogPanel(panel.Panel, threading.Thread):
         user_input = nyx.popups.input_prompt('Events to log: ')
 
         if user_input:
-          user_input = user_input.replace(' ', '')  # strips spaces
-          event_types = nyx.arguments.expand_events(user_input)
-
           try:
+            user_input = user_input.replace(' ', '')  # strip spaces
+            event_types = nyx.arguments.expand_events(user_input)
+
             if event_types != self._logged_event_types:
               with self._lock:
                 self._logged_event_types = nyx.util.log.listen_for_events(self._register_tor_event, event_types)
@@ -191,7 +186,7 @@ class LogPanel(panel.Panel, threading.Thread):
         self.save_snapshot(path_input)
         nyx.popups.show_msg('Saved: %s' % path_input, 2)
       except IOError as exc:
-        nyx.popups.show_msg('Unable to save snapshot: %s' % exc.strerror, 2)
+        nyx.popups.show_msg('Unable to save snapshot: %s' % exc, 2)
 
   def clear(self):
     """
@@ -199,17 +194,17 @@ class LogPanel(panel.Panel, threading.Thread):
     """
 
     with self._lock:
-      self._logged_events = nyx.util.log.LogGroup(CONFIG['cache.log_panel.size'])
+      self._logged_events = nyx.util.log.LogGroup(CONFIG['cache.log_panel.size'], group_by_day = True)
       self.redraw(True)
 
   def save_snapshot(self, path):
     """
     Saves the log events currently being displayed to the given path. This
-    takes filers into account. This overwrites the file if it already exists,
-    and raises an IOError if there's a problem.
+    takes filers into account. This overwrites the file if it already exists.
+
+    :param str path: path where to save the log snapshot
 
-    Arguments:
-      path - path where to save the log snapshot
+    :raises: **IOError** if unsuccessful
     """
 
     path = os.path.abspath(os.path.expanduser(path))
@@ -227,10 +222,8 @@ class LogPanel(panel.Panel, threading.Thread):
     with self._lock:
       with open(path, 'w') as snapshot_file:
         try:
-          for entry in reversed(self._logged_events):
-            is_visible = self._filter.match(entry.display_message)
-
-            if is_visible:
+          for entry in reversed(list(self._logged_events)):
+            if self._filter.match(entry.display_message):
               snapshot_file.write(entry.display_message + '\n')
         except Exception as exc:
           raise IOError("unable to write to '%s': %s" % (path, exc))
@@ -255,19 +248,10 @@ class LogPanel(panel.Panel, threading.Thread):
       if key_press.match('c'):
         self.clear()
     elif key.match('f'):
-      # Provides menu to pick regular expression filters or adding new ones:
-      # for syntax see: http://docs.python.org/library/re.html#regular-expression-syntax
-
-      options = ['None'] + self._filter.latest_selections() + ['New...']
-      old_selection = 0 if not self._filter.selection() else 1
-
-      # does all activity under a curses lock to prevent redraws when adding
-      # new filters
-
       with panel.CURSES_LOCK:
-        selection = nyx.popups.show_menu('Log Filter:', options, old_selection)
-
-        # applies new setting
+        initial_selection = 1 if self._filter.selection() else 0
+        options = ['None'] + self._filter.latest_selections() + ['New...']
+        selection = nyx.popups.show_menu('Log Filter:', options, initial_selection)
 
         if selection == 0:
           self._filter.select(None)
@@ -430,10 +414,10 @@ class LogPanel(panel.Panel, threading.Thread):
     responsive if additions are less frequent.
     """
 
-    last_ran, last_day = -1, nyx.util.log.days_since(time.time())
+    last_ran, last_day = -1, int((time.time() - TIMEZONE_OFFSET) / 86400)
 
     while not self._halt:
-      current_day = nyx.util.log.days_since(time.time())
+      current_day = int((time.time() - TIMEZONE_OFFSET) / 86400)
       time_since_reset = time.time() - last_ran
       max_log_update_rate = CONFIG['features.log.maxRefreshRate'] / 1000.0
 





More information about the tor-commits mailing list