1# Copyright (C) 2009 Bruno Tarquini <btarquini AT gmail.com> 2# 3# This file is part of Gajim. 4# 5# Gajim is free software; you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published 7# by the Free Software Foundation; version 3 only. 8# 9# Gajim is distributed in the hope that it will be useful, 10# but WITHOUT ANY WARRANTY; without even the implied warranty of 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12# GNU General Public License for more details. 13# 14# You should have received a copy of the GNU General Public License 15# along with Gajim. If not, see <http://www.gnu.org/licenses/>. 16 17import logging 18import os 19import sys 20import time 21from datetime import datetime 22 23from gajim.common import app 24from gajim.common import configpaths 25from gajim.common.i18n import _ 26 27def parseLogLevel(arg): 28 """ 29 Either numeric value or level name from logging module 30 """ 31 if arg.isdigit(): 32 return int(arg) 33 if arg.isupper() and hasattr(logging, arg): 34 return getattr(logging, arg) 35 print(_('%s is not a valid loglevel') % repr(arg), file=sys.stderr) 36 return 0 37 38def parseLogTarget(arg): 39 """ 40 [gajim.]c.x.y -> gajim.c.x.y 41 .other_logger -> other_logger 42 <None> -> gajim 43 """ 44 arg = arg.lower() 45 if not arg: 46 return 'gajim' 47 if arg.startswith('.'): 48 return arg[1:] 49 if arg.startswith('gajim'): 50 return arg 51 return 'gajim.' + arg 52 53def parseAndSetLogLevels(arg): 54 """ 55 [=]LOGLEVEL -> gajim=LOGLEVEL 56 gajim=LOGLEVEL -> gajim=LOGLEVEL 57 .other=10 -> other=10 58 .=10 -> <nothing> 59 c.x.y=c.z=20 -> gajim.c.x.y=20 60 gajim.c.z=20 61 gajim=10,c.x=20 -> gajim=10 62 gajim.c.x=20 63 """ 64 for directive in arg.split(','): 65 directive = directive.strip() 66 if not directive: 67 continue 68 if '=' not in directive: 69 directive = '=' + directive 70 targets, level = directive.rsplit('=', 1) 71 level = parseLogLevel(level.strip()) 72 for target in targets.split('='): 73 target = parseLogTarget(target.strip()) 74 if target: 75 logging.getLogger(target).setLevel(level) 76 print("Logger %s level set to %d" % (target, level), 77 file=sys.stderr) 78 79 80class colors: 81 # pylint: disable=C0326 82 NONE = chr(27) + "[0m" 83 BLACk = chr(27) + "[30m" 84 RED = chr(27) + "[31m" 85 GREEN = chr(27) + "[32m" 86 BROWN = chr(27) + "[33m" 87 BLUE = chr(27) + "[34m" 88 MAGENTA = chr(27) + "[35m" 89 CYAN = chr(27) + "[36m" 90 LIGHT_GRAY = chr(27) + "[37m" 91 DARK_GRAY = chr(27) + "[30;1m" 92 BRIGHT_RED = chr(27) + "[31;1m" 93 BRIGHT_GREEN = chr(27) + "[32;1m" 94 YELLOW = chr(27) + "[33;1m" 95 BRIGHT_BLUE = chr(27) + "[34;1m" 96 PURPLE = chr(27) + "[35;1m" 97 BRIGHT_CYAN = chr(27) + "[36;1m" 98 WHITE = chr(27) + "[37;1m" 99 100def colorize(text, color): 101 return color + text + colors.NONE 102 103class FancyFormatter(logging.Formatter): 104 """ 105 An eye-candy formatter with colors 106 """ 107 colors_mapping = { 108 'DEBUG': colors.BLUE, 109 'INFO': colors.GREEN, 110 'WARNING': colors.BROWN, 111 'ERROR': colors.RED, 112 'CRITICAL': colors.BRIGHT_RED, 113 } 114 115 def __init__(self, fmt, datefmt=None, use_color=False): 116 logging.Formatter.__init__(self, fmt, datefmt) 117 self.use_color = use_color 118 119 def formatTime(self, record, datefmt=None): 120 f = logging.Formatter.formatTime(self, record, datefmt) 121 if self.use_color: 122 f = colorize(f, colors.DARK_GRAY) 123 return f 124 125 def format(self, record): 126 level = record.levelname 127 record.levelname = '(%s)' % level[0] 128 129 if self.use_color: 130 c = FancyFormatter.colors_mapping.get(level, '') 131 record.levelname = colorize(record.levelname, c) 132 record.name = '%-25s' % colorize(record.name, colors.CYAN) 133 else: 134 record.name = '%-25s|' % record.name 135 136 return logging.Formatter.format(self, record) 137 138 139def init(): 140 """ 141 Iinitialize the logging system 142 """ 143 144 if app.get_debug_mode(): 145 _cleanup_debug_logs() 146 _redirect_output() 147 148 use_color = False 149 if os.name != 'nt': 150 use_color = sys.stderr.isatty() 151 152 consoleloghandler = logging.StreamHandler() 153 consoleloghandler.setFormatter( 154 FancyFormatter( 155 '%(asctime)s %(levelname)s %(name)-35s %(message)s', 156 '%x %H:%M:%S', 157 use_color 158 ) 159 ) 160 161 root_log = logging.getLogger('gajim') 162 root_log.setLevel(logging.WARNING) 163 root_log.addHandler(consoleloghandler) 164 root_log.propagate = False 165 166 root_log = logging.getLogger('nbxmpp') 167 root_log.setLevel(logging.WARNING) 168 root_log.addHandler(consoleloghandler) 169 root_log.propagate = False 170 171 root_log = logging.getLogger('gnupg') 172 root_log.setLevel(logging.WARNING) 173 root_log.addHandler(consoleloghandler) 174 root_log.propagate = False 175 176 # GAJIM_DEBUG is set only on Windows when using Gajim-Debug.exe 177 # Gajim-Debug.exe shows a command line prompt and we want to redirect 178 # log output to it 179 if app.get_debug_mode() or os.environ.get('GAJIM_DEBUG', False): 180 set_verbose() 181 182def set_loglevels(loglevels_string): 183 parseAndSetLogLevels(loglevels_string) 184 185def set_verbose(): 186 parseAndSetLogLevels('gajim=DEBUG') 187 parseAndSetLogLevels('.nbxmpp=INFO') 188 189def set_quiet(): 190 parseAndSetLogLevels('gajim=CRITICAL') 191 parseAndSetLogLevels('.nbxmpp=CRITICAL') 192 193 194def _redirect_output(): 195 debug_folder = configpaths.get('DEBUG') 196 date = datetime.today().strftime('%d%m%Y-%H%M%S') 197 filename = '%s-debug.log' % date 198 fd = open(debug_folder / filename, 'a') 199 sys.stderr = sys.stdout = fd 200 201 202def _cleanup_debug_logs(): 203 debug_folder = configpaths.get('DEBUG') 204 debug_files = list(debug_folder.glob('*-debug.log*')) 205 now = time.time() 206 for file in debug_files: 207 # Delete everything older than 3 days 208 if file.stat().st_ctime < now - 259200: 209 file.unlink() 210 211 212 213# tests 214if __name__ == '__main__': 215 init() 216 217 set_loglevels('gajim.c=DEBUG,INFO') 218 219 log = logging.getLogger('gajim') 220 log.debug('debug') 221 log.info('info') 222 log.warning('warn') 223 log.error('error') 224 log.critical('critical') 225 226 log = logging.getLogger('gajim.c.x.dispatcher') 227 log.debug('debug') 228 log.info('info') 229 log.warning('warn') 230 log.error('error') 231 log.critical('critical') 232