[nyx/master] Move LogEntry to log util

commit 7889e5e1b0ef095beba0017e92b74971437ea101 Author: Damian Johnson <atagar@torproject.org> Date: Sun Apr 12 13:49:21 2015 -0700 Move LogEntry to log util We made a LogEntry namedtuple in the log util for read_tor_log(). This is very similar to the LogEntry class in the panel. Just moving the class - we'll want this to make our other helpers testable too. --- nyx/log_panel.py | 62 +++++++++++++------------------------------------- nyx/util/log.py | 45 ++++++++++++++++++++++++------------ nyx/util/ui_tools.py | 2 +- 3 files changed, 48 insertions(+), 61 deletions(-) diff --git a/nyx/log_panel.py b/nyx/log_panel.py index cdaca17..75fa59d 100644 --- a/nyx/log_panel.py +++ b/nyx/log_panel.py @@ -12,15 +12,17 @@ import logging import threading import stem +import stem.response.events + from stem.control import State -from stem.response import events from stem.util import conf, log, str_tools import nyx.arguments import nyx.popups + from nyx import __version__ from nyx.util import panel, tor_controller, ui_tools -from nyx.util.log import read_tor_log +from nyx.util.log import LogEntry, read_tor_log try: # added in python 3.2 @@ -158,7 +160,7 @@ def get_daybreaks(events, ignore_time_for_cache = False): if event_day != last_day: marker_timestamp = (event_day * 86400) + TIMEZONE_OFFSET - new_listing.append(LogEntry(marker_timestamp, DAYBREAK_EVENT, '', 'white')) + new_listing.append(LogEntry(marker_timestamp, DAYBREAK_EVENT, '')) new_listing.append(entry) last_day = event_day @@ -267,34 +269,6 @@ def is_duplicate(event, event_set, get_duplicates = False): return False -class LogEntry(): - """ - Individual log file entry, having the following attributes: - timestamp - unix timestamp for when the event occurred - event_type - event type that occurred ('INFO', 'BW', 'NYX_WARN', etc) - msg - message that was logged - color - color of the log entry - """ - - def __init__(self, timestamp, event_type, msg): - self.timestamp = timestamp - self.type = event_type - self.msg = msg - self.color = CONFIG['attr.log_color'].get(event_type, 'white') - - @lru_cache() - def get_display_message(self): - """ - Provides the entry's message for the log. - - Arguments: - include_date - appends the event's date to the start of the message - """ - - entry_time = time.localtime(self.timestamp) - return '%02i:%02i:%02i [%s] %s' % (entry_time[3], entry_time[4], entry_time[5], self.type, self.msg) - - class LogPanel(panel.Panel, threading.Thread, logging.Handler): """ Listens for and displays tor, nyx, and stem events. This can prepopulate @@ -427,8 +401,8 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler): if logging_location: try: for entry in read_tor_log(logging_location, read_limit): - if entry.runlevel in set_runlevels: - self.msg_log.append(LogEntry(entry.timestamp, entry.runlevel, entry.message)) + if entry.type in set_runlevels: + self.msg_log.append(entry) except IOError as exc: log.info('Unable to read log located at %s: %s' % (logging_location, exc)) except ValueError as exc: @@ -460,9 +434,9 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler): msg = ' '.join(str(event).split(' ')[1:]) - if isinstance(event, events.BandwidthEvent): + if isinstance(event, stem.response.events.BandwidthEvent): msg = 'READ: %i, WRITTEN: %i' % (event.read, event.written) - elif isinstance(event, events.LogEvent): + elif isinstance(event, stem.response.events.LogEvent): msg = event.message self.register_event(LogEntry(event.arrived_at, event.type, msg)) @@ -478,15 +452,11 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler): if event.type not in self.logged_events: return - # strips control characters to avoid screwing up the terminal - - event.msg = ui_tools.get_printable(event.msg) - # note event in the log file if we're saving them if self.log_file: try: - self.log_file.write(event.get_display_message() + '\n') + self.log_file.write(event.display_message + '\n') self.log_file.flush() except IOError as exc: log.error('Unable to write to log file: %s' % exc.strerror) @@ -498,7 +468,7 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler): # notifies the display that it has new content - if not self.regex_filter or self.regex_filter.search(event.get_display_message()): + if not self.regex_filter or self.regex_filter.search(event.display_message): self._cond.acquire() self._cond.notifyAll() self._cond.release() @@ -679,10 +649,10 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler): try: for entry in self.msg_log: - is_visible = not self.regex_filter or self.regex_filter.search(entry.get_display_message()) + is_visible = not self.regex_filter or self.regex_filter.search(entry.display_message) if is_visible: - snapshot_file.write(entry.get_display_message() + '\n') + snapshot_file.write(entry.display_message + '\n') self.vals_lock.release() except Exception as exc: @@ -814,7 +784,7 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler): while deduplicated_log: entry, duplicate_count = deduplicated_log.pop(0) - if self.regex_filter and not self.regex_filter.search(entry.get_display_message()): + if self.regex_filter and not self.regex_filter.search(entry.display_message): continue # filter doesn't match log message - skip # checks if we should be showing a divider with the date @@ -850,11 +820,11 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler): display_queue = [] - msg_comp = entry.get_display_message().split('\n') + msg_comp = entry.display_message.split('\n') for i in range(len(msg_comp)): font = curses.A_BOLD if 'ERR' in entry.type else curses.A_NORMAL # emphasizes ERR messages - display_queue.append((msg_comp[i].strip(), (font, entry.color), i != len(msg_comp) - 1)) + display_queue.append((msg_comp[i].strip(), (font, CONFIG['attr.log_color'].get(entry.type, 'white')), i != len(msg_comp) - 1)) if duplicate_count: plural_label = 's' if duplicate_count > 1 else '' diff --git a/nyx/util/log.py b/nyx/util/log.py index d2e2eff..2d8f523 100644 --- a/nyx/util/log.py +++ b/nyx/util/log.py @@ -3,7 +3,6 @@ Logging utilities, primiarily short aliases for logging a message at various runlevels. """ -import collections import time import stem.util.log @@ -11,15 +10,40 @@ import stem.util.system import nyx.util -LogEntry = collections.namedtuple('LogEntry', [ - 'timestamp', - 'runlevel', - 'message', -]) - TOR_RUNLEVELS = ['DEBUG', 'INFO', 'NOTICE', 'WARN', 'ERR'] +class LogEntry(object): + """ + Individual tor or nyx log entry. + + **Note:** Tor doesn't include the date in its timestamps so the year + component may be inaccurate. (:trac:`15607`) + + :var int timestamp: unix timestamp for when the event occured + :var str type: event type + :var str message: event's message + :var str display_message: message annotated with our time and runlevel + """ + + def __init__(self, timestamp, type, message): + self.timestamp = timestamp + self.type = type + self.message = message + + entry_time = time.localtime(self.timestamp) + self.display_message = '%02i:%02i:%02i [%s] %s' % (entry_time[3], entry_time[4], entry_time[5], self.type, self.message) + + def __eq__(self, other): + if isinstance(other, LogEntry): + return hash(self) == hash(other) + else: + return False + + def __hash__(self): + return hash(self.display_message) + + def trace(msg, **attr): _log(stem.util.log.TRACE, msg, **attr) @@ -59,13 +83,6 @@ def _log(runlevel, message, **attr): def read_tor_log(path, read_limit = None): """ Provides logging messages from a tor log file, from newest to oldest. - LogEntry this provides have three attributes... - - * **timestamp** (int) - * **runlevel** (str) - * **message** (str) - - **Note:** The 'timestamp' has a hardcoded year of 2012 due to :trac:`15607`. :param str path: logging location to read from :param int read_limit: maximum number of lines to read from the file diff --git a/nyx/util/ui_tools.py b/nyx/util/ui_tools.py index 1123080..8d7edad 100644 --- a/nyx/util/ui_tools.py +++ b/nyx/util/ui_tools.py @@ -39,7 +39,7 @@ CONFIG = conf.config_dict('nyx', { def is_color_supported(): """ - Checks if curses presently supports rendering colors. + Checks if curses currently supports rendering colors. :returns: **True** if colors can be rendered, **False** otherwise """
participants (1)
-
atagar@torproject.org