logging_config.py revision 420c71e4a80b41438d323f600657a0f5175c494c
1import logging, os, sys, time 2 3# set up a simple catchall configuration for use during import time. some code 4# may log messages at import time and we don't want those to get completely 5# thrown away. we'll clear this out when actual configuration takes place. 6logging.basicConfig(level=logging.DEBUG) 7 8class AllowBelowSeverity(logging.Filter): 9 """ 10 Allows only records less severe than a given level (the opposite of what 11 the normal logging level filtering does. 12 """ 13 def __init__(self, level): 14 self.level = level 15 16 17 def filter(self, record): 18 return record.levelno < self.level 19 20 21class LoggingConfig(object): 22 global_level = logging.DEBUG 23 stdout_level = logging.INFO 24 stderr_level = logging.ERROR 25 26 file_formatter = logging.Formatter( 27 fmt='%(asctime)s %(levelname)-5.5s|%(module)10.10s:%(lineno)4.4d| ' 28 '%(message)s', 29 datefmt='%m/%d %H:%M:%S') 30 31 console_formatter = logging.Formatter( 32 fmt='%(asctime)s %(levelname)-5.5s| %(message)s', 33 datefmt='%H:%M:%S') 34 35 def __init__(self, use_console=True): 36 self.logger = logging.getLogger() 37 self.global_level = logging.DEBUG 38 self.use_console = use_console 39 40 41 @classmethod 42 def get_timestamped_log_name(cls, base_name): 43 return '%s.log.%s' % (base_name, time.strftime('%Y-%m-%d-%H.%M.%S')) 44 45 46 @classmethod 47 def get_autotest_root(cls): 48 common_lib_dir = os.path.dirname(__file__) 49 return os.path.abspath(os.path.join(common_lib_dir, '..', '..')) 50 51 52 @classmethod 53 def get_server_log_dir(cls): 54 return os.path.join(cls.get_autotest_root(), 'logs') 55 56 57 def add_stream_handler(self, stream, level=logging.DEBUG): 58 handler = logging.StreamHandler(stream) 59 handler.setLevel(level) 60 handler.setFormatter(self.console_formatter) 61 self.logger.addHandler(handler) 62 return handler 63 64 65 def add_console_handlers(self): 66 stdout_handler = self.add_stream_handler(sys.stdout, 67 level=self.stdout_level) 68 # only pass records *below* STDERR_LEVEL to stdout, to avoid duplication 69 stdout_handler.addFilter(AllowBelowSeverity(self.stderr_level)) 70 71 self.add_stream_handler(sys.stderr, self.stderr_level) 72 73 74 def add_file_handler(self, file_path, level=logging.DEBUG, log_dir=None): 75 if log_dir: 76 file_path = os.path.join(log_dir, file_path) 77 handler = logging.FileHandler(file_path) 78 handler.setLevel(level) 79 handler.setFormatter(self.file_formatter) 80 self.logger.addHandler(handler) 81 return handler 82 83 84 def _add_file_handlers_for_all_levels(self, log_dir, log_name): 85 for level in (logging.DEBUG, logging.INFO, logging.WARNING, 86 logging.ERROR): 87 file_name = '%s.%s' % (log_name, logging.getLevelName(level)) 88 self.add_file_handler(file_name, level=level, log_dir=log_dir) 89 90 91 def add_debug_file_handlers(self, log_dir, log_name=None): 92 raise NotImplementedError 93 94 95 def _clear_all_handlers(self): 96 for handler in list(self.logger.handlers): 97 self.logger.removeHandler(handler) 98 # Attempt to close the handler. If it's already closed a KeyError 99 # will be generated. http://bugs.python.org/issue8581 100 try: 101 handler.close() 102 except KeyError: 103 pass 104 105 106 def configure_logging(self, use_console=True, verbose=False): 107 self._clear_all_handlers() # see comment at top of file 108 self.logger.setLevel(self.global_level) 109 110 if verbose: 111 self.stdout_level = logging.DEBUG 112 if use_console: 113 self.add_console_handlers() 114 115 116class TestingConfig(LoggingConfig): 117 def add_stream_handler(self, *args, **kwargs): 118 pass 119 120 121 def add_file_handler(self, *args, **kwargs): 122 pass 123 124 125 def configure_logging(self, **kwargs): 126 pass 127