# Copyright (C) 2009 Bruno Tarquini # # This file is part of Gajim. # # Gajim 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; version 3 only. # # Gajim 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 Gajim. If not, see . import logging import os import sys import time from datetime import datetime from gajim.common import app from gajim.common import configpaths from gajim.common.i18n import _ def parseLogLevel(arg): """ Either numeric value or level name from logging module """ if arg.isdigit(): return int(arg) if arg.isupper() and hasattr(logging, arg): return getattr(logging, arg) print(_('%s is not a valid loglevel') % repr(arg), file=sys.stderr) return 0 def parseLogTarget(arg): """ [gajim.]c.x.y -> gajim.c.x.y .other_logger -> other_logger -> gajim """ arg = arg.lower() if not arg: return 'gajim' if arg.startswith('.'): return arg[1:] if arg.startswith('gajim'): return arg return 'gajim.' + arg def parseAndSetLogLevels(arg): """ [=]LOGLEVEL -> gajim=LOGLEVEL gajim=LOGLEVEL -> gajim=LOGLEVEL .other=10 -> other=10 .=10 -> c.x.y=c.z=20 -> gajim.c.x.y=20 gajim.c.z=20 gajim=10,c.x=20 -> gajim=10 gajim.c.x=20 """ for directive in arg.split(','): directive = directive.strip() if not directive: continue if '=' not in directive: directive = '=' + directive targets, level = directive.rsplit('=', 1) level = parseLogLevel(level.strip()) for target in targets.split('='): target = parseLogTarget(target.strip()) if target: logging.getLogger(target).setLevel(level) print("Logger %s level set to %d" % (target, level), file=sys.stderr) class colors: # pylint: disable=C0326 NONE = chr(27) + "[0m" BLACk = chr(27) + "[30m" RED = chr(27) + "[31m" GREEN = chr(27) + "[32m" BROWN = chr(27) + "[33m" BLUE = chr(27) + "[34m" MAGENTA = chr(27) + "[35m" CYAN = chr(27) + "[36m" LIGHT_GRAY = chr(27) + "[37m" DARK_GRAY = chr(27) + "[30;1m" BRIGHT_RED = chr(27) + "[31;1m" BRIGHT_GREEN = chr(27) + "[32;1m" YELLOW = chr(27) + "[33;1m" BRIGHT_BLUE = chr(27) + "[34;1m" PURPLE = chr(27) + "[35;1m" BRIGHT_CYAN = chr(27) + "[36;1m" WHITE = chr(27) + "[37;1m" def colorize(text, color): return color + text + colors.NONE class FancyFormatter(logging.Formatter): """ An eye-candy formatter with colors """ colors_mapping = { 'DEBUG': colors.BLUE, 'INFO': colors.GREEN, 'WARNING': colors.BROWN, 'ERROR': colors.RED, 'CRITICAL': colors.BRIGHT_RED, } def __init__(self, fmt, datefmt=None, use_color=False): logging.Formatter.__init__(self, fmt, datefmt) self.use_color = use_color def formatTime(self, record, datefmt=None): f = logging.Formatter.formatTime(self, record, datefmt) if self.use_color: f = colorize(f, colors.DARK_GRAY) return f def format(self, record): level = record.levelname record.levelname = '(%s)' % level[0] if self.use_color: c = FancyFormatter.colors_mapping.get(level, '') record.levelname = colorize(record.levelname, c) record.name = '%-25s' % colorize(record.name, colors.CYAN) else: record.name = '%-25s|' % record.name return logging.Formatter.format(self, record) def init(): """ Iinitialize the logging system """ if app.get_debug_mode(): _cleanup_debug_logs() _redirect_output() use_color = False if os.name != 'nt': use_color = sys.stderr.isatty() consoleloghandler = logging.StreamHandler() consoleloghandler.setFormatter( FancyFormatter( '%(asctime)s %(levelname)s %(name)-35s %(message)s', '%x %H:%M:%S', use_color ) ) root_log = logging.getLogger('gajim') root_log.setLevel(logging.WARNING) root_log.addHandler(consoleloghandler) root_log.propagate = False root_log = logging.getLogger('nbxmpp') root_log.setLevel(logging.WARNING) root_log.addHandler(consoleloghandler) root_log.propagate = False root_log = logging.getLogger('gnupg') root_log.setLevel(logging.WARNING) root_log.addHandler(consoleloghandler) root_log.propagate = False # GAJIM_DEBUG is set only on Windows when using Gajim-Debug.exe # Gajim-Debug.exe shows a command line prompt and we want to redirect # log output to it if app.get_debug_mode() or os.environ.get('GAJIM_DEBUG', False): set_verbose() def set_loglevels(loglevels_string): parseAndSetLogLevels(loglevels_string) def set_verbose(): parseAndSetLogLevels('gajim=DEBUG') parseAndSetLogLevels('.nbxmpp=INFO') def set_quiet(): parseAndSetLogLevels('gajim=CRITICAL') parseAndSetLogLevels('.nbxmpp=CRITICAL') def _redirect_output(): debug_folder = configpaths.get('DEBUG') date = datetime.today().strftime('%d%m%Y-%H%M%S') filename = '%s-debug.log' % date fd = open(debug_folder / filename, 'a') sys.stderr = sys.stdout = fd def _cleanup_debug_logs(): debug_folder = configpaths.get('DEBUG') debug_files = list(debug_folder.glob('*-debug.log*')) now = time.time() for file in debug_files: # Delete everything older than 3 days if file.stat().st_ctime < now - 259200: file.unlink() # tests if __name__ == '__main__': init() set_loglevels('gajim.c=DEBUG,INFO') log = logging.getLogger('gajim') log.debug('debug') log.info('info') log.warning('warn') log.error('error') log.critical('critical') log = logging.getLogger('gajim.c.x.dispatcher') log.debug('debug') log.info('info') log.warning('warn') log.error('error') log.critical('critical')