From 39989cc985f809adc74fa975d857fae1610fcf40 Mon Sep 17 00:00:00 2001 From: Goffi Date: Mon, 5 May 2014 20:12:19 +0200 Subject: [PATCH] primitivus: use of new logging system: - default output is \\memory - logs can be seen with :messages command - now useless writeLog method has been removed --- frontends/src/primitivus/constants.py | 2 + frontends/src/primitivus/primitivus | 59 ++++++++++----------- frontends/src/primitivus/profile_manager.py | 2 +- frontends/src/primitivus/xmlui.py | 5 +- src/core/constants.py | 9 +++- src/core/log.py | 43 ++++++++++++--- src/sat.tac | 3 +- 7 files changed, 80 insertions(+), 43 deletions(-) diff --git a/frontends/src/primitivus/constants.py b/frontends/src/primitivus/constants.py index c34e6e96..15eccff5 100644 --- a/frontends/src/primitivus/constants.py +++ b/frontends/src/primitivus/constants.py @@ -79,4 +79,6 @@ class Const(constants.Const): "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) diff --git a/frontends/src/primitivus/primitivus b/frontends/src/primitivus/primitivus index 6d811639..33217c31 100755 --- a/frontends/src/primitivus/primitivus +++ b/frontends/src/primitivus/primitivus @@ -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.xmlui import XMLUI 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 @@ class EditBar(sat_widgets.ModalEdit): 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 @@ class PrimitivusApp(QuickApp, InputHistory): ## 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 @@ class PrimitivusApp(QuickApp, InputHistory): 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 @@ class PrimitivusApp(QuickApp, InputHistory): 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 @@ class PrimitivusApp(QuickApp, InputHistory): 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 @@ class PrimitivusApp(QuickApp, InputHistory): 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 @@ class PrimitivusApp(QuickApp, InputHistory): 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 @@ class PrimitivusApp(QuickApp, InputHistory): 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 @@ class PrimitivusApp(QuickApp, InputHistory): 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 @@ class PrimitivusApp(QuickApp, InputHistory): 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 @@ class PrimitivusApp(QuickApp, InputHistory): 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# diff --git a/frontends/src/primitivus/profile_manager.py b/frontends/src/primitivus/profile_manager.py index 3f7dfbd8..45990f1b 100644 --- a/frontends/src/primitivus/profile_manager.py +++ b/frontends/src/primitivus/profile_manager.py @@ -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 diff --git a/frontends/src/primitivus/xmlui.py b/frontends/src/primitivus/xmlui.py index d755f67d..1f0f1b1f 100644 --- a/frontends/src/primitivus/xmlui.py +++ b/frontends/src/primitivus/xmlui.py @@ -21,7 +21,8 @@ from sat.core.i18n import _ 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 @@ class PrimitivusDividerWidget(xmlui.DividerWidget, urwid.Divider): elif style == 'blank': div_char = ' ' else: - warning(_("Unknown div_char")) + log.warning(_("Unknown div_char")) div_char = u'─' urwid.Divider.__init__(self, div_char) diff --git a/src/core/constants.py b/src/core/constants.py index 392513ee..10aee0d2 100644 --- a/src/core/constants.py +++ b/src/core/constants.py @@ -79,6 +79,7 @@ class Const(object): 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 @@ class Const(object): 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 @@ class Const(object): 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) + diff --git a/src/core/log.py b/src/core/log.py index f1ff98b2..6f67709e 100644 --- a/src/core/log.py +++ b/src/core/log.py @@ -169,6 +169,18 @@ class FilterName(object): 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 ConfigureTwisted(ConfigureBasic): 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 @@ class ConfigureStandard(Configure): 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 @@ class ConfigureStandard(Configure): 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 @@ def _parseOptions(options): 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) diff --git a/src/sat.tac b/src/sat.tac index b40b21e3..80f7a662 100644 --- a/src/sat.tac +++ b/src/sat.tac @@ -22,8 +22,9 @@ from twisted.internet import glib2reactor 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