|  | """ Convenience package to get a pre-configured logging object. | 
        
          |  |  | 
        
          |  | In your code, import this package then simply use the logging functions: | 
        
          |  |  | 
        
          |  | logger.debug(message) | 
        
          |  | logger.info(message) | 
        
          |  | logger.warning(message) | 
        
          |  | logger.error(message) | 
        
          |  |  | 
        
          |  | There is also a debug-level function for dumping data | 
        
          |  |  | 
        
          |  | logger.dump(data) | 
        
          |  |  | 
        
          |  | The default log level is INFO | 
        
          |  |  | 
        
          |  | This can be adjusted by providing an environment variable | 
        
          |  | CUSTOM_LOG_LEVEL | 
        
          |  |  | 
        
          |  | or in-code by calling logger.setLevel() | 
        
          |  |  | 
        
          |  | !! Logging To A File: | 
        
          |  |  | 
        
          |  | Upon importing fcilog , immediately use logger.setLogFile(filename) | 
        
          |  | This can only be done once, subsequent attempts will raise a | 
        
          |  | logger.LoggerConfigException | 
        
          |  |  | 
        
          |  | +++ | 
        
          |  |  | 
        
          |  | Copyright: (C) Tai Kedzierski | 
        
          |  |  | 
        
          |  | License: MIT License (see https://mit-license.org/) | 
        
          |  |  | 
        
          |  | You are free to include, adapt and distribute your changes, | 
        
          |  | provided you retain this copyright notice. | 
        
          |  |  | 
        
          |  | """ | 
        
          |  |  | 
        
          |  | import os | 
        
          |  | import logging | 
        
          |  | import pprint | 
        
          |  |  | 
        
          |  | DEBUG = logging.DEBUG | 
        
          |  | INFO = logging.INFO | 
        
          |  | WARNING = logging.WARNING | 
        
          |  | ERROR = logging.ERROR | 
        
          |  |  | 
        
          |  | __custom_logger = None | 
        
          |  | __custom_logger_handler = None | 
        
          |  | __pretty = pprint.PrettyPrinter(indent=2) | 
        
          |  |  | 
        
          |  | __log_file_name = None | 
        
          |  |  | 
        
          |  | def setLogFile(filename): | 
        
          |  | # TODO | 
        
          |  | # Using logging.basicConfig() in its base form, only | 
        
          |  | #   one attempt at setting the file will have sane effects. | 
        
          |  | # This code prvents multiple calls to reconfigure file, | 
        
          |  | #   but ideally should just switch file | 
        
          |  |  | 
        
          |  | global __log_file_name | 
        
          |  |  | 
        
          |  | if __custom_logger is None: | 
        
          |  | __log_file_name = filename | 
        
          |  | __createLogger(filename) | 
        
          |  | return | 
        
          |  |  | 
        
          |  | if __log_file_name: | 
        
          |  | raise LoggerConfigException("Logging is already being written to '{fname}'.".format(fname=__log_file_name) ) | 
        
          |  | else: | 
        
          |  | raise LoggerConfigException("Logging has already started and can no longer be directed to a file.") | 
        
          |  |  | 
        
          |  | def setLevel(level): | 
        
          |  | """ Activate a new logging level | 
        
          |  | """ | 
        
          |  | _ = __getLogger() | 
        
          |  |  | 
        
          |  | __custom_logger.setLevel(level) | 
        
          |  | __custom_logger_handler.setLevel(level) | 
        
          |  |  | 
        
          |  | def dump(data): | 
        
          |  | logger = __getLogger() | 
        
          |  | logger.debug(__pretty.pformat(data)) | 
        
          |  |  | 
        
          |  | def debug(message): | 
        
          |  | __getLogger().debug(message) | 
        
          |  |  | 
        
          |  | def info(message): | 
        
          |  | __getLogger().info(message) | 
        
          |  |  | 
        
          |  | def warning(message): | 
        
          |  | __getLogger().warning(message) | 
        
          |  |  | 
        
          |  | def error(message): | 
        
          |  | __getLogger().error(message) | 
        
          |  |  | 
        
          |  | def __getLogger(): | 
        
          |  | if __custom_logger == None: | 
        
          |  | __createLogger() | 
        
          |  |  | 
        
          |  | return __custom_logger | 
        
          |  |  | 
        
          |  | def __createLogger(filename=None): | 
        
          |  | global __custom_logger | 
        
          |  | global __custom_logger_handler | 
        
          |  |  | 
        
          |  | format_string = '%(asctime)s | %(message)s' | 
        
          |  |  | 
        
          |  | if filename: | 
        
          |  | logging.basicConfig(filename=filename, format=format_string) | 
        
          |  |  | 
        
          |  | level = __get_string_log_level(os.getenv("CUSTOM_LOG_LEVEL", "INFO")) | 
        
          |  |  | 
        
          |  | __custom_logger = logging.getLogger("custom_log") | 
        
          |  | __custom_logger_handler = logging.StreamHandler() | 
        
          |  | setLevel(level) # MUST be called after setting the __custom_logger* variables, else infinite recursion! | 
        
          |  |  | 
        
          |  | formatter = logging.Formatter(format_string) | 
        
          |  | __custom_logger_handler.setFormatter(formatter) | 
        
          |  |  | 
        
          |  | __custom_logger.addHandler(__custom_logger_handler) | 
        
          |  |  | 
        
          |  |  | 
        
          |  | def __get_string_log_level(level): | 
        
          |  | if level == "DEBUG": | 
        
          |  | return DEBUG | 
        
          |  | elif level == "INFO": | 
        
          |  | return INFO | 
        
          |  | elif level == "WARNING": | 
        
          |  | return WARNING | 
        
          |  | elif level == "ERROR": | 
        
          |  | return ERROR | 
        
          |  | else: | 
        
          |  | raise ValueError("'{level}' is not a recognised log level".format(level=level)) | 
        
          |  |  | 
        
          |  |  | 
        
          |  | class LoggerConfigException(Exception): | 
        
          |  |  | 
        
          |  | def __init__(self, message): | 
        
          |  | Exception.__init__(self, message) |