Redirect output to log files.
authorNeal H. Walfield <neal@walfield.org>
Mon, 22 Aug 2011 19:11:10 +0000 (21:11 +0200)
committerNeal H. Walfield <neal@walfield.org>
Tue, 23 Aug 2011 09:03:45 +0000 (11:03 +0200)
src/FeedingIt-Web.py
src/FeedingIt.py
src/debugging.py [new file with mode: 0644]
src/update_feeds.py

index 4c9c141..af3395f 100644 (file)
@@ -11,6 +11,9 @@ from threading import Thread
 from os.path import isfile, isdir, exists
 from os import mkdir, remove, stat, environ
 
+import debugging
+debugging.init(dot_directory=".feedingit", program_name="feedingit-web")
+
 CONFIGDIR = environ.get("HOME", "/home/user") + "/.feedingit"
 #CONFIGDIR = "/home/user/.feedingit/"
 
index be9eb80..a808c26 100644 (file)
@@ -46,6 +46,7 @@ from updatedbus import UpdateServerObject, get_lock
 from config import Config
 from cgi import escape
 import weakref
+import debugging
 
 from rss_sqlite import Listing
 from opml import GetOpmlData, ExportOpmlData
@@ -1484,6 +1485,7 @@ class FeedingIt:
 
 if __name__ == "__main__":
     mainthread.init ()
+    debugging.init(dot_directory=".feedingit", program_name="feedingit")
 
     gobject.signal_new("feed-closed", DisplayFeed, gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
     gobject.signal_new("article-closed", DisplayArticle, gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
diff --git a/src/debugging.py b/src/debugging.py
new file mode 100644 (file)
index 0000000..7330871
--- /dev/null
@@ -0,0 +1,113 @@
+# Copyright (c) 2011 Neal H. Walfield
+#
+# This software is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import with_statement
+import os
+import logging
+import itertools
+import sys
+import string
+import traceback
+import time
+import errno
+import glob
+
+logger = None
+original_excepthook = None
+
+def my_excepthook(exctype, value, tb):
+    """Log uncaught exceptions."""
+    logger.error(
+        "Uncaught exception: %s"
+        % (''.join(traceback.format_exception(exctype, value, tb)),))
+    original_excepthook(exctype, value, tb)
+
+def init(dot_directory, debug=False, max_logfiles=1, program_name=None):
+    if not os.path.isabs(dot_directory):
+        dot_directory = os.path.join(os.path.expanduser("~"), dot_directory)
+
+    logging_directory = os.path.join(dot_directory, "logging")
+    try:
+        os.makedirs(logging_directory)
+    except OSError, e:
+        if e.errno != errno.EEXIST:
+            raise
+
+    if program_name is None:
+        program_name = os.path.basename(sys.argv[0])
+    string.translate(program_name, string.maketrans(' .', '__'))
+
+    timestamp = time.strftime("%Y%m%d")
+
+    logfiles = glob.glob(os.path.join(logging_directory,
+                                      program_name + '-*.log'))
+    if len(logfiles) >= max_logfiles:
+        logfiles.sort()
+        for f in logfiles[:-(max_logfiles+1)]:
+            print "Purging old log file %s" % (f,)
+            try:
+                os.remove(f)
+            except OSError, e:
+                print "Removing %s: %s" % (f, str(e))
+
+    logfile = os.path.join(logging_directory,
+                           program_name + '-' + timestamp + '.log')
+
+    print "Sending output to %s" % logfile
+
+    global logger
+    logger = logging.getLogger(__name__) 
+
+    if debug:
+        level = logging.DEBUG
+    else:
+        level = logging.INFO
+
+    logging.basicConfig(
+        level=level,
+        format=('%(asctime)s (pid: ' + str(os.getpid()) + ') '
+                + '%(levelname)-8s %(message)s'),
+        filename=logfile,
+        filemode='a')
+
+    # Log uncaught exceptions.
+    global original_excepthook
+    original_excepthook = sys.excepthook
+    sys.excepthook = my_excepthook
+
+    def redirect(thing):
+        filename = os.path.join(logging_directory, program_name + '.' + thing)
+        try:
+            with open(filename, "r") as fhandle:
+                contents = fhandle.read()
+        except IOError, e:
+            if e.errno in (errno.ENOENT,):
+                fhandle = None
+                contents = ""
+            else:
+                logging.error("Reading %s: %s" % (filename, str(e)))
+                raise
+
+        logging.error("std%s of last run: %s" % (thing, contents))
+
+        if fhandle is not None:
+            os.remove(filename)
+
+        print "Redirecting std%s to %s" % (thing, filename)
+        return open(filename, "w", 0)
+            
+    sys.stderr = redirect('err')
+    sys.stdout = redirect('out')
+
index 9516594..89d208b 100644 (file)
@@ -35,6 +35,9 @@ import traceback
 from jobmanager import JobManager
 import mainthread
 
+import debugging
+debugging.init(dot_directory=".feedingit", program_name="update_feeds")
+
 CONFIGDIR="/home/user/.feedingit/"
 #DESKTOP_FILE = "/usr/share/applications/hildon-status-menu/feedingit_status.desktop"
 dbug = False
@@ -46,14 +49,6 @@ del timeout
 
 from updatedbus import UpdateServerObject
 
-debug_file = None
-def debug(*args):
-    global debug_file
-    if not debug_file:
-        debug_file = open("/home/user/.feedingit/feedingit_update.log", "a")
-
-    debug_file.write (*args)
-
 class FeedUpdate():
     def __init__(self):
         self.config = Config(self, CONFIGDIR+"config.ini")
@@ -99,4 +94,4 @@ if app_lock != None:
             JobManager().quit()
     del app_lock
 else:
-    debug("Update in progress")
+    logger.error("Update in progress")