[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] r23410: {arm} added: log cropping based on time (requested by voidzero) fi (in arm/trunk: . src src/interface)



Author: atagar
Date: 2010-10-05 16:44:47 +0000 (Tue, 05 Oct 2010)
New Revision: 23410

Modified:
   arm/trunk/TODO
   arm/trunk/src/armrc.defaults
   arm/trunk/src/interface/logPanel.py
Log:
added: log cropping based on time (requested by voidzero)
fix: cropping prepopulated events if it exceeds caching size



Modified: arm/trunk/TODO
===================================================================
--- arm/trunk/TODO	2010-10-05 10:12:02 UTC (rev 23409)
+++ arm/trunk/TODO	2010-10-05 16:44:47 UTC (rev 23410)
@@ -9,12 +9,14 @@
       progress - /init and /util are done and /interface is partly done. Known
       bugs are being fixed while refactoring.
       
-      [ ] log panel
-        - log cropping based on time (idea by voidzero)
+      [X] log panel
       [ ] conf panel
         - move torrc validation into util
         - fetch text via getinfo rather than reading directly?
             conn.get_info("config-text")
+        - improve parsing failure notice to give line number
+            just giving "[ARM-WARN] Unable to validate torrc" isn't very
+            helpful...
   * release prep
     * ask helix about steps for getting a deb and rpm included in the tor repo
     * check performance of this version vs last version (general screen refresh

Modified: arm/trunk/src/armrc.defaults
===================================================================
--- arm/trunk/src/armrc.defaults	2010-10-05 10:12:02 UTC (rev 23409)
+++ arm/trunk/src/armrc.defaults	2010-10-05 16:44:47 UTC (rev 23410)
@@ -26,6 +26,9 @@
 # showDuplicateEntries
 #   shows all log entries if true, otherwise collapses similar entries with an
 #   indicator for how much is hidden
+# entryDuration
+#   number of days log entries are kept before being dropped (if zero then
+#   they're kept until cropped due to caching limits)
 # maxLinesPerEntry
 #   max number of lines to display for a single log entry
 # prepopulate
@@ -39,6 +42,7 @@
 
 features.log.showDateDividers true
 features.log.showDuplicateEntries false
+features.log.entryDuration 7
 features.log.maxLinesPerEntry 4
 features.log.prepopulate true
 features.log.prepopulateReadLimit 5000

Modified: arm/trunk/src/interface/logPanel.py
===================================================================
--- arm/trunk/src/interface/logPanel.py	2010-10-05 10:12:02 UTC (rev 23409)
+++ arm/trunk/src/interface/logPanel.py	2010-10-05 16:44:47 UTC (rev 23410)
@@ -36,11 +36,13 @@
 RUNLEVELS = ["DEBUG", "INFO", "NOTICE", "WARN", "ERR"]
 RUNLEVEL_EVENT_COLOR = {"DEBUG": "magenta", "INFO": "blue", "NOTICE": "green", "WARN": "yellow", "ERR": "red"}
 DAYBREAK_EVENT = "DAYBREAK" # special event for marking when the date changes
+TIMEZONE_OFFSET = time.altzone if time.localtime()[8] else time.timezone
 
 ENTRY_INDENT = 2 # spaces an entry's message is indented after the first line
 DEFAULT_CONFIG = {"features.logFile": "",
                   "features.log.showDateDividers": True,
                   "features.log.showDuplicateEntries": False,
+                  "features.log.entryDuration": 7,
                   "features.log.maxLinesPerEntry": 4,
                   "features.log.prepopulate": True,
                   "features.log.prepopulateReadLimit": 5000,
@@ -70,6 +72,18 @@
 CACHED_DUPLICATES_ARGUMENTS = None # events
 CACHED_DUPLICATES_RESULT = None
 
+def daysSince(timestamp=None):
+  """
+  Provides the number of days since the epoch converted to local time (rounded
+  down).
+  
+  Arguments:
+    timestamp - unix timestamp to convert, current time if undefined
+  """
+  
+  if timestamp == None: timestamp = time.time()
+  return int((timestamp - TIMEZONE_OFFSET) / 86400)
+
 def expandEvents(eventAbbr):
   """
   Expands event abbreviations to their full names. Beside mappings provided in
@@ -280,8 +294,7 @@
   if not events: return []
   
   newListing = []
-  timezoneOffset = time.altzone if time.localtime()[8] else time.timezone
-  currentDay = int((time.time() - timezoneOffset) / 86400)
+  currentDay = daysSince()
   lastDay = currentDay
   
   if CACHED_DAYBREAKS_ARGUMENTS[0] == events and \
@@ -289,9 +302,9 @@
     return list(CACHED_DAYBREAKS_RESULT)
   
   for entry in events:
-    eventDay = int((entry.timestamp - timezoneOffset) / 86400) # days since epoch
+    eventDay = daysSince(entry.timestamp)
     if eventDay != lastDay:
-      markerTimestamp = (eventDay * 86400) + timezoneOffset
+      markerTimestamp = (eventDay * 86400) + TIMEZONE_OFFSET
       newListing.append(LogEntry(markerTimestamp, DAYBREAK_EVENT, "", "white"))
     
     newListing.append(entry)
@@ -507,8 +520,9 @@
     self._halt = False                  # terminates thread if true
     self._cond = threading.Condition()  # used for pausing/resuming the thread
     
-    # restricts concurrent write access to attributes used to draw the display:
-    # msgLog, loggedEvents, regexFilter, scroll
+    # restricts concurrent write access to attributes used to draw the display
+    # and pausing:
+    # msgLog, loggedEvents, regexFilter, scroll, _pauseBuffer
     self.valsLock = threading.RLock()
     
     # cached parameters (invalidated if arguments for them change)
@@ -558,6 +572,9 @@
     finally:
       log.LOG_LOCK.release()
     
+    # crops events that are either too old, or more numerous than the caching size
+    self._trimEvents(self.msgLog)
+    
     # leaving lastContentHeight as being too low causes initialization problems
     self.lastContentHeight = len(self.msgLog)
     
@@ -605,12 +622,14 @@
     
     cacheSize = self._config["cache.logPanel.size"]
     if self._isPaused:
+      self.valsLock.acquire()
       self._pauseBuffer.insert(0, event)
-      if len(self._pauseBuffer) > cacheSize: del self._pauseBuffer[cacheSize:]
+      self._trimEvents(self._pauseBuffer)
+      self.valsLock.release()
     else:
       self.valsLock.acquire()
       self.msgLog.insert(0, event)
-      if len(self.msgLog) > cacheSize: del self.msgLog[cacheSize:]
+      self._trimEvents(self.msgLog)
       
       # notifies the display that it has new content
       if not self.regexFilter or self.regexFilter.search(event.getDisplayMessage()):
@@ -875,12 +894,10 @@
     responsive if additions are less frequent.
     """
     
-    timezoneOffset = time.altzone if time.localtime()[8] else time.timezone
-    currentTime = time.time()
-    
     # unix time for the start of the current day (local time), used so we
     # can redraw when the date changes
-    dayStartTime = currentTime - (currentTime - timezoneOffset) % 86400
+    currentTime = time.time()
+    dayStartTime = currentTime - (currentTime - TIMEZONE_OFFSET) % 86400
     while not self._halt:
       currentTime = time.time()
       timeSinceReset = currentTime - self._lastUpdate
@@ -897,7 +914,7 @@
         if not self._halt: self._cond.wait(sleepTime)
         self._cond.release()
       else:
-        dayStartTime = currentTime - (currentTime - timezoneOffset) % 86400
+        dayStartTime = currentTime - (currentTime - TIMEZONE_OFFSET) % 86400
         self.redraw(True)
   
   def stop(self):
@@ -1009,3 +1026,30 @@
     self.valsLock.release()
     return panelLabel
   
+  def _trimEvents(self, eventListing):
+    """
+    Crops events that have either:
+    - grown beyond the cache limit
+    - outlived the configured log duration
+    
+    """
+    
+    self.valsLock.acquire()
+    cacheSize = self._config["cache.logPanel.size"]
+    if len(eventListing) > cacheSize: del eventListing[cacheSize:]
+    
+    logTTL = self._config["features.log.entryDuration"]
+    if logTTL > 0:
+      currentDay = daysSince()
+      
+      breakpoint = None # index at which to crop from
+      for i in range(len(eventListing) - 1, -1, -1):
+        daysSinceEvent = currentDay - daysSince(eventListing[i].timestamp)
+        if daysSinceEvent > logTTL: breakpoint = i # older than the ttl
+        else: break
+      
+      # removes entries older than the ttl
+      if breakpoint != None: del eventListing[breakpoint:]
+    
+    self.valsLock.release()
+