# 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 _LOG_MESSAGE_FORMAT = ('%(asctime)s.%(msecs)03d %(process)d ' '%(levelname)s %(name)s [%(clouds_name)s ' '%(username)s %(project_name)s] %(message)s') _LOG_DATE_FORMAT = '%Y-%m-%d %H:%M:%S' 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 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") 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 = logging.WARNING log_file = cloud_config.config.get('log_file', None) if log_file: # setup the logging level get_log_level = cloud_config.config.get('log_level') if get_log_level: log_level = { 'error': logging.ERROR, 'info': logging.INFO, 'debug': logging.DEBUG, }.get(get_log_level, logging.WARNING) # setup the logging context log_cont = _LogContext( clouds_name=cloud_config.config.get('cloud'), project_name=cloud_config.auth.get('project_name'), username=cloud_config.auth.get('username'), ) # setup the logging handler log_handler = _setup_handler_for_logging( logging.FileHandler, log_level, file_name=log_file, context=log_cont, ) 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, context): """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 context: instance of _LogContext() :return: logging handler """ root_logger = logging.getLogger('') handler = None # Setup handler for FileHandler(--os-cloud) handler = logging.FileHandler( filename=file_name, ) formatter = _LogContextFormatter( context=context, fmt=_LOG_MESSAGE_FORMAT, datefmt=_LOG_DATE_FORMAT, ) 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 class _LogContext(object): """Helper class to represent useful information about a logging context""" def __init__(self, clouds_name=None, project_name=None, username=None): """Initialize _LogContext instance :param clouds_name: one of the cloud name in configuration file :param project_name: the project name in cloud(clouds_name) :param username: the user name in cloud(clouds_name) """ self.clouds_name = clouds_name self.project_name = project_name self.username = username def to_dict(self): return { 'clouds_name': self.clouds_name, 'project_name': self.project_name, 'username': self.username } class _LogContextFormatter(logging.Formatter): """Customize the logging format for logging handler""" def __init__(self, *args, **kwargs): self.context = kwargs.pop('context', None) logging.Formatter.__init__(self, *args, **kwargs) def format(self, record): d = self.context.to_dict() for k, v in d.items(): setattr(record, k, v) return logging.Formatter.format(self, record)