changeset 1010:73a0b7f94674

primitivus: use of new logging system: - default output is \\memory - logs can be seen with :messages command - now useless writeLog method has been removed
author Goffi <goffi@goffi.org>
date Mon, 05 May 2014 20:12:19 +0200
parents d1084f7e56a5
children 5a6354ff468c
files frontends/src/primitivus/constants.py frontends/src/primitivus/primitivus frontends/src/primitivus/profile_manager.py frontends/src/primitivus/xmlui.py src/core/constants.py src/core/log.py src/sat.tac
diffstat 7 files changed, 80 insertions(+), 43 deletions(-) [+]
line wrap: on
line diff
--- a/frontends/src/primitivus/constants.py	Mon May 05 18:58:34 2014 +0200
+++ b/frontends/src/primitivus/constants.py	Mon May 05 20:12:19 2014 +0200
@@ -79,4 +79,6 @@
                 "dnd": (u'✖', "show_dnd"),
                 "xa": (u'☄', "show_xa")
                 }
+    LOG_OPT_SECTION = APP_NAME.lower()
+    LOG_OPT_OUTPUT = ('output', constants.Const.LOG_OPT_OUTPUT_SEP + constants.Const.LOG_OPT_OUTPUT_MEMORY)
 
--- a/frontends/src/primitivus/primitivus	Mon May 05 18:58:34 2014 +0200
+++ b/frontends/src/primitivus/primitivus	Mon May 05 20:12:19 2014 +0200
@@ -19,6 +19,10 @@
 
 
 from sat.core.i18n import _
+from sat_frontends.primitivus.constants import Const as C
+from sat.core import log as logging
+logging.satConfigure(C.LOG_BACKEND_STANDARD, C)
+log = logging.getLogger(__name__)
 import urwid
 from urwid_satext import sat_widgets
 from urwid_satext.files_management import FileDialog
@@ -32,19 +36,11 @@
 from sat_frontends.primitivus.progress import Progress
 from sat_frontends.primitivus.notify import Notify
 from sat_frontends.tools.misc import InputHistory
-from sat_frontends.primitivus.constants import Const
-from sat_frontends.constants import Const as commonConst
-import logging
-from logging import debug, info, error
+from sat_frontends.constants import Const as commonConst # FIXME
 from sat.tools.jid  import JID
 from os.path import join
 
 
-### logging configuration FIXME: put this elsewhere ###
-logging.basicConfig(level=logging.CRITICAL,  #TODO: configure it to put messages in a log file
-                    format='%(message)s')
-###
-
 class ChatList(QuickChatList):
     """This class manage the list of chat windows"""
 
@@ -119,6 +115,9 @@
         if command == 'quit':
             self.app.onExit()
             raise urwid.ExitMainLoop()
+        elif command == 'messages':
+            wid = sat_widgets.GenericList(logging.memoryGet())
+            self.app.addWindow(wid)
         elif command == 'presence':
             self.app.status_bar.onPresenceClick()
         elif command in ['presence %s' % show for show in commonConst.PRESENCE.keys()]:
@@ -166,7 +165,7 @@
 
         ## main loop setup ##
         self.main_widget = ProfileManager(self)
-        self.loop = urwid.MainLoop(self.main_widget, Const.PALETTE, event_loop=urwid.GLibEventLoop(), input_filter=self.inputFilter, unhandled_input=self.keyHandler)
+        self.loop = urwid.MainLoop(self.main_widget, C.PALETTE, event_loop=urwid.GLibEventLoop(), input_filter=self.inputFilter, unhandled_input=self.keyHandler)
 
         ##misc setup##
         self.chat_wins = ChatList(self)
@@ -187,25 +186,25 @@
         self.editBar.mode = value
 
     def modeHint(self, value):
-        """Change mode if make sens (i.e.: if there is nothing in the editBar"""
+        """Change mode if make sens (i.e.: if there is nothing in the editBar)"""
         if not self.editBar.get_edit_text():
             self.mode = value
 
     def debug(self):
-        """convenient method to reset screen and launch p(u)db"""
+        """convenient method to reset screen and launch (i)p(u)db"""
+        log.info('Entered debug mode')
         try:
             import pudb
             pudb.set_trace()
-        except:
-            import os,pdb
+        except ImportError:
+            import os
             os.system('reset')
-            print 'Entered debug mode'
-            pdb.set_trace()
-
-    def writeLog(self, log, file_name='/tmp/primitivus_log'):
-        """method to write log in a temporary file, useful for debugging"""
-        with open(file_name, 'a') as f:
-            f.write(log+"\n")
+            try:
+                import ipdb
+                ipdb.set_trace()
+            except ImportError:
+                import pdb
+                pdb.set_trace()
 
     def redraw(self):
         """redraw the screen"""
@@ -296,7 +295,7 @@
         menu.addMenu(communication, _("Join room"), self.onJoinRoomRequest, 'meta j')
         #additionals menus
         #FIXME: do this in a more generic way (in quickapp)
-        add_menus = self.bridge.getMenus('', Const.NO_SECURITY_LIMIT)
+        add_menus = self.bridge.getMenus('', C.NO_SECURITY_LIMIT)
         def add_menu_cb(callback_id):
             self.launchAction(callback_id, None, profile_key = self.profile)
         for id_, type_, path, path_i18n  in add_menus:
@@ -417,7 +416,7 @@
                     no_cb=self._dialogCancelCb, no_value = (answer_cb, answer_data))
         else:
             popup = sat_widgets.Alert(unicode(title), unicode(message), ok_cb=answer_cb or self.removePopUp) #FIXME: remove unicode here when DBus Bridge will no return dbus.String anymore
-            error(_('unmanaged dialog type: %s'), type_)
+            log.error(_('unmanaged dialog type: %s'), type_)
         self.showPopUp(popup)
 
     def onNotification(self, notBar):
@@ -432,7 +431,7 @@
                 self.main_widget.footer = pile
         else:
             if not isinstance(self.main_widget.footer, urwid.Pile):
-                error(_("INTERNAL ERROR: Unexpected class for main widget's footer"))
+                log.error(_("INTERNAL ERROR: Unexpected class for main widget's footer"))
                 assert(False)
             if self.notBar.canHide():
                 #No notification left, we can hide the bar
@@ -499,13 +498,13 @@
             return
 
         if not id in self.current_action_ids:
-            debug (_('unknown id, ignoring'))
+            log.debug (_('unknown id, ignoring'))
             return
         if type_ == "SUPPRESS":
             self.current_action_ids.remove(id)
         elif type_ == "XMLUI":
             self.current_action_ids.remove(id)
-            debug (_("XML user interface received"))
+            log.debug (_("XML user interface received"))
             misc = {}
             #FIXME FIXME FIXME: must clean all this crap !
             title = _('Form')
@@ -534,7 +533,7 @@
                 del self.current_action_ids_cb[id]
                 callback(data)
         else:
-            error (_("FIXME FIXME FIXME: type [%s] not implemented") % type_)
+            log.error (_("FIXME FIXME FIXME: type [%s] not implemented") % type_)
             raise NotImplementedError
 
     ##DIALOGS CALLBACKS##
@@ -545,7 +544,7 @@
             self.bridge.joinMUC(room_jid, self.profiles[self.profile]['whoami'].node, {}, self.profile)
         else:
             message = _("'%s' is an invalid JID !") % room_jid
-            error (message)
+            log.error (message)
             self.showPopUp(sat_widgets.Alert(_("Error"), message, ok_cb=self.removePopUp))
 
     #MENU EVENTS#
@@ -561,7 +560,7 @@
 
         def failure(error):
             self.showPopUp(sat_widgets.Alert(_("Error"), _("Can't get parameters"), ok_cb=self.removePopUp))
-        self.bridge.getParamsUI(app=Const.APP_NAME, profile_key=self.profile, callback=success, errback=failure)
+        self.bridge.getParamsUI(app=C.APP_NAME, profile_key=self.profile, callback=success, errback=failure)
 
     def onExitRequest(self, menu):
         QuickApp.onExit(self)
@@ -573,7 +572,7 @@
         self.showPopUp(pop_up_widget)
 
     def onAboutRequest(self, menu):
-        self.showPopUp(sat_widgets.Alert(_("About"), Const.APP_NAME + " v" + self.bridge.getVersion(), ok_cb=self.removePopUp))
+        self.showPopUp(sat_widgets.Alert(_("About"), C.APP_NAME + " v" + self.bridge.getVersion(), ok_cb=self.removePopUp))
 
     #MISC CALLBACKS#
 
--- a/frontends/src/primitivus/profile_manager.py	Mon May 05 18:58:34 2014 +0200
+++ b/frontends/src/primitivus/profile_manager.py	Mon May 05 20:12:19 2014 +0200
@@ -19,7 +19,7 @@
 
 from sat.core.i18n import _
 import urwid
-from urwid_satext.sat_widgets import AdvancedEdit,Password,List,InputDialog,ConfirmDialog,Alert,FocusFrame
+from urwid_satext.sat_widgets import AdvancedEdit,Password,List,InputDialog,ConfirmDialog,Alert
 from sat.tools.jid import JID
 
 
--- a/frontends/src/primitivus/xmlui.py	Mon May 05 18:58:34 2014 +0200
+++ b/frontends/src/primitivus/xmlui.py	Mon May 05 20:12:19 2014 +0200
@@ -21,7 +21,8 @@
 import urwid
 import copy
 from urwid_satext import sat_widgets
-from logging import debug, info, warning, error
+from sat.core.log import getLogger
+log = getLogger(__name__)
 from xml.dom import minidom
 from sat_frontends.tools import xmlui
 
@@ -74,7 +75,7 @@
         elif style == 'blank':
             div_char = ' '
         else:
-            warning(_("Unknown div_char"))
+            log.warning(_("Unknown div_char"))
             div_char = u'─'
 
         urwid.Divider.__init__(self, div_char)
--- a/src/core/constants.py	Mon May 05 18:58:34 2014 +0200
+++ b/src/core/constants.py	Mon May 05 20:12:19 2014 +0200
@@ -79,6 +79,7 @@
     LOG_BACKEND_BASIC = 'basic'
     LOG_BASE_LOGGER = 'root'
     LOG_TWISTED_LOGGER = 'twisted'
+    LOG_OPT_SECTION = 'DEFAULT' # section of sat.conf where log options should be
     LOG_OPT_PREFIX = 'log_'
     # (option_name, default_value) tuples
     LOG_OPT_COLORS = ('colors', 'true') # true for auto colors, force to have colors even if stdout is not a tty, false for no color
@@ -91,7 +92,6 @@
     LOG_OPT_OUTPUT_MEMORY_LIMIT = 50
     LOG_OPT_OUTPUT_FILE = 'file' # file is implicit if only output
     LOG_OPT_OUTPUT = ('output', LOG_OPT_OUTPUT_SEP + LOG_OPT_OUTPUT_DEFAULT) # //default = normal output (stderr or a file with twistd), path/to/file for a file (must be the first if used), //memory for memory (options can be put in parenthesis, e.g.: //memory(500) for a 500 lines memory)
-    LOG_OPTIONS = (LOG_OPT_COLORS, LOG_OPT_LEVEL, LOG_OPT_FORMAT, LOG_OPT_LOGGER, LOG_OPT_OUTPUT)
     LOG_LVL_DEBUG = 'DEBUG'
     LOG_LVL_INFO = 'INFO'
     LOG_LVL_WARNING = 'WARNING'
@@ -115,3 +115,10 @@
     ANSI_BOLD = '\033[1m'
     ANSI_BLINK = '\033[5m'
     ANSI_BLINK_OFF = '\033[25m'
+
+    @classmethod
+    def LOG_OPTIONS(cls):
+        """Return options checked for logs"""
+        # XXX: we use a classmethod so we can use Const inheritance to change default options
+        return(cls.LOG_OPT_COLORS, cls.LOG_OPT_LEVEL, cls.LOG_OPT_FORMAT, cls.LOG_OPT_LOGGER, cls.LOG_OPT_OUTPUT)
+
--- a/src/core/log.py	Mon May 05 18:58:34 2014 +0200
+++ b/src/core/log.py	Mon May 05 20:12:19 2014 +0200
@@ -169,6 +169,18 @@
         log_record.name = dict_record['name']
         return self.filter(log_record) == 1
 
+def memoryGet(size=None):
+    """Return buffered logs
+
+    @param size: number of logs to return
+    """
+    if not C.LOG_OPT_OUTPUT_MEMORY in _handlers:
+        raise ValueError('memory output is not used')
+    if _backend == C.LOG_BACKEND_STANDARD:
+        mem_handler = _handlers[C.LOG_OPT_OUTPUT_MEMORY]
+        return (log_msg for log_msg in mem_handler.buffer[size if size is None else -size:])
+    else:
+        raise NotImplementedError
 
 def _getProfile():
     """Try to find profile value using introspection"""
@@ -509,7 +521,11 @@
 
 class ConfigureStandard(Configure):
 
-    def __init__(self, level=None, fmt=C.LOG_OPT_FORMAT[1], output=C.LOG_OPT_OUTPUT[1], logger=None, colors=False, force_colors=False):
+    def __init__(self, level=None, fmt=None, output=None, logger=None, colors=False, force_colors=False):
+        if fmt is None:
+            fmt = C.LOG_OPT_FORMAT[1]
+        if output is None:
+            output = C.LOG_OPT_OUTPUT[1]
         super(ConfigureStandard, self).__init__(level, fmt, output, logger, colors, force_colors)
 
     def preTreatment(self):
@@ -559,7 +575,7 @@
 
     def configureColors(self, colors, force_colors):
         import sys
-        self.with_color = colors & (sys.stdout.isatty() or force_colors)
+        self.formatter.with_color = colors & (sys.stdout.isatty() or force_colors)
         if not colors and force_colors:
             raise ValueError("force_colors can't be used if colors is False")
 
@@ -579,8 +595,11 @@
                     hdlr = logging.StreamHandler()
                     self._addHandler(root_logger, hdlr)
                 elif handler == C.LOG_OPT_OUTPUT_MEMORY:
-                    import logging.handlers
-                    hdlr = logging.handlers.BufferingHandler(options)
+                    from logging.handlers import BufferingHandler
+                    class SatMemoryHandler(BufferingHandler):
+                        def emit(self, record):
+                            super(SatMemoryHandler, self).emit(self.format(record))
+                    hdlr = SatMemoryHandler(options)
                     _handlers[handler] = hdlr # we keep a reference to the handler to read the buffer later
                     self._addHandler(root_logger, hdlr)
                 elif handler == C.LOG_OPT_OUTPUT_FILE:
@@ -640,23 +659,31 @@
             level = C.LOG_LVL_INFO
         options[LEVEL] = level
 
-def satConfigure(backend=C.LOG_BACKEND_TWISTED):
+def satConfigure(backend=C.LOG_BACKEND_STANDARD, const=None):
     """Configure logging system for SàT, can be used by frontends
 
     logs conf is read in SàT conf, then in environment variables. It must be done before Memory init
+    @param backend: backend to use, it can be:
+        - C.LOG_BACKEND_BASIC: print based backend
+        - C.LOG_BACKEND_TWISTED: Twisted logging backend
+        - C.LOG_BACKEND_STANDARD: standard logging backend
+    @param const: Const class to use instead of sat.core.constants.Const (mainly used to change default values)
     """
+    if const is not None:
+        global C
+        C = const
     import ConfigParser
     import os
     log_conf = {}
     config = ConfigParser.SafeConfigParser()
     config.read(C.CONFIG_FILES)
-    for opt_name, opt_default in C.LOG_OPTIONS:
+    for opt_name, opt_default in C.LOG_OPTIONS():
         try:
             log_conf[opt_name] = os.environ[''.join((C.ENV_PREFIX, C.LOG_OPT_PREFIX.upper(), opt_name.upper()))]
         except KeyError:
             try:
-                log_conf[opt_name] = config.get('DEFAULT', C.LOG_OPT_PREFIX + opt_name)
-            except ConfigParser.NoOptionError:
+                log_conf[opt_name] = config.get(C.LOG_OPT_SECTION, C.LOG_OPT_PREFIX + opt_name)
+            except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
                 log_conf[opt_name] = opt_default
 
     _parseOptions(log_conf)
--- a/src/sat.tac	Mon May 05 18:58:34 2014 +0200
+++ b/src/sat.tac	Mon May 05 20:12:19 2014 +0200
@@ -22,8 +22,9 @@
 glib2reactor.install()
 
 # XXX: We need to configure logs before any log method is used, so here is the best place.
+from sat.core.constants import Const as C
 from sat.core import log
-log.satConfigure()
+log.satConfigure(C.LOG_BACKEND_TWISTED)
 
 # XXX: SAT must be imported after log configuration, because it write stuff to logs
 from sat.core.sat_main import SAT