# Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. # """Context and Formatter""" import logging import warnings def log_level_from_options(options): # if --debug, --quiet or --verbose is not specified, # the default logging level is warning log_level = logging.WARNING if options.verbose_level == 0: # --quiet log_level = logging.ERROR elif options.verbose_level == 2: # One --verbose log_level = logging.INFO elif options.verbose_level >= 3: # Two or more --verbose log_level = logging.DEBUG return log_level def log_level_from_config(config): # Check the command line option verbose_level = config.get('verbose_level') if config.get('debug', False): verbose_level = 3 if verbose_level == 0: verbose_level = 'error' elif verbose_level == 1: # If a command line option has not been specified, check the # configuration file verbose_level = config.get('log_level', 'warning') elif verbose_level == 2: verbose_level = 'info' else: verbose_level = 'debug' log_level = { 'critical': logging.CRITICAL, 'error': logging.ERROR, 'warning': logging.WARNING, 'info': logging.INFO, 'debug': logging.DEBUG, }.get(verbose_level, logging.WARNING) return log_level def set_warning_filter(log_level): if log_level == logging.ERROR: warnings.simplefilter("ignore") elif log_level == logging.WARNING: warnings.simplefilter("ignore") elif log_level == logging.INFO: warnings.simplefilter("once") class _FileFormatter(logging.Formatter): """Customize the logging format for logging handler""" _LOG_MESSAGE_BEGIN = ( '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s ') _LOG_MESSAGE_CONTEXT = '[%(cloud)s %(username)s %(project)s] ' _LOG_MESSAGE_END = '%(message)s' _LOG_DATE_FORMAT = '%Y-%m-%d %H:%M:%S' def __init__(self, options=None, config=None, **kwargs): context = {} if options: context = { 'cloud': getattr(options, 'cloud', ''), 'project': getattr(options, 'os_project_name', ''), 'username': getattr(options, 'username', ''), } elif config: context = { 'cloud': config.config.get('cloud', ''), 'project': config.auth.get('project_name', ''), 'username': config.auth.get('username', ''), } if context: self.fmt = (self._LOG_MESSAGE_BEGIN + (self._LOG_MESSAGE_CONTEXT % context) + self._LOG_MESSAGE_END) else: self.fmt = self._LOG_MESSAGE_BEGIN + self._LOG_MESSAGE_END logging.Formatter.__init__(self, self.fmt, self._LOG_DATE_FORMAT) def setup_handler_logging_level(handler_type, level): """Setup of the handler for set the logging level :param handler_type: type of logging handler :param level: logging level :return: None """ # Set the handler logging level of FileHandler(--log-file) # and StreamHandler for h in logging.getLogger('').handlers: if type(h) is handler_type: h.setLevel(level) def setup_logging(shell, cloud_config): """Get one cloud configuration from configuration file and setup logging :param shell: instance of openstackclient shell :param cloud_config: instance of the cloud specified by --os-cloud in the configuration file :return: None """ log_level = log_level_from_config(cloud_config.config) set_warning_filter(log_level) log_file = cloud_config.config.get('log_file', None) if log_file: # setup the logging context formatter = _FileFormatter(config=cloud_config) # setup the logging handler log_handler = _setup_handler_for_logging( logging.FileHandler, log_level, file_name=log_file, formatter=formatter, ) if log_level == logging.DEBUG: # DEBUG only. # setup the operation_log shell.enable_operation_logging = True shell.operation_log.setLevel(logging.DEBUG) shell.operation_log.addHandler(log_handler) def _setup_handler_for_logging(handler_type, level, file_name, formatter): """Setup of the handler Setup of the handler for addition of the logging handler, changes of the logging format, change of the logging level, :param handler_type: type of logging handler :param level: logging level :param file_name: name of log-file :param formatter: instance of logging.Formatter :return: logging handler """ root_logger = logging.getLogger('') handler = None # Setup handler for FileHandler(--os-cloud) handler = logging.FileHandler( filename=file_name, ) handler.setFormatter(formatter) handler.setLevel(level) # If both `--log-file` and `--os-cloud` are specified, # the log is output to each file. root_logger.addHandler(handler) return handler