From 05800c47227ce7c6918296c33fe0b9a774d14cda Mon Sep 17 00:00:00 2001 From: Terry Howe Date: Fri, 30 Oct 2015 17:38:42 +0900 Subject: Rename context.py to logs.py At one point this file contained the context for logging, but the reason for its existence is now for logging. Implements: blueprint logging-migration Change-Id: I4ba42bbef97b09d31236ac8c01b6fb23827b8bee --- openstackclient/common/context.py | 170 ---------------------- openstackclient/common/logs.py | 170 ++++++++++++++++++++++ openstackclient/shell.py | 6 +- openstackclient/tests/common/test_context.py | 202 --------------------------- openstackclient/tests/common/test_logs.py | 202 +++++++++++++++++++++++++++ 5 files changed, 374 insertions(+), 376 deletions(-) delete mode 100644 openstackclient/common/context.py create mode 100644 openstackclient/common/logs.py delete mode 100644 openstackclient/tests/common/test_context.py create mode 100644 openstackclient/tests/common/test_logs.py (limited to 'openstackclient') diff --git a/openstackclient/common/context.py b/openstackclient/common/context.py deleted file mode 100644 index 6d1aec13..00000000 --- a/openstackclient/common/context.py +++ /dev/null @@ -1,170 +0,0 @@ -# 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. -# - -"""Application logging""" - -import logging -import sys -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) - - -class LogConfigurator(object): - - _CONSOLE_MESSAGE_FORMAT = '%(message)s' - - def __init__(self, options): - self.root_logger = logging.getLogger('') - self.root_logger.setLevel(logging.DEBUG) - - # Force verbose_level 3 on --debug - self.dump_trace = False - if options.debug: - options.verbose_level = 3 - self.dump_trace = True - - # Always send higher-level messages to the console via stderr - self.console_logger = logging.StreamHandler(sys.stderr) - log_level = log_level_from_options(options) - self.console_logger.setLevel(log_level) - formatter = logging.Formatter(self._CONSOLE_MESSAGE_FORMAT) - self.console_logger.setFormatter(formatter) - self.root_logger.addHandler(self.console_logger) - - # Set the warning filter now - set_warning_filter(log_level) - - # Set up logging to a file - self.file_logger = None - log_file = options.log_file - if log_file: - self.file_logger = logging.FileHandler(filename=log_file) - self.file_logger.setFormatter(_FileFormatter(options=options)) - self.file_logger.setLevel(log_level) - self.root_logger.addHandler(self.file_logger) - - # Requests logs some stuff at INFO that we don't want - # unless we have DEBUG - requests_log = logging.getLogger("requests") - - # Other modules we don't want DEBUG output for - cliff_log = logging.getLogger('cliff') - stevedore_log = logging.getLogger('stevedore') - iso8601_log = logging.getLogger("iso8601") - - if options.debug: - # --debug forces traceback - requests_log.setLevel(logging.DEBUG) - else: - requests_log.setLevel(logging.ERROR) - - cliff_log.setLevel(logging.ERROR) - stevedore_log.setLevel(logging.ERROR) - iso8601_log.setLevel(logging.ERROR) - - def configure(self, cloud_config): - log_level = log_level_from_config(cloud_config.config) - set_warning_filter(log_level) - self.dump_trace = cloud_config.config.get('debug', self.dump_trace) - self.console_logger.setLevel(log_level) - - log_file = cloud_config.config.get('log_file', None) - if log_file: - if not self.file_logger: - self.file_logger = logging.FileHandler(filename=log_file) - formatter = _FileFormatter(cloud_config=cloud_config) - self.file_logger.setFormatter(formatter) - self.file_logger.setFormatter(_FileFormatter(config=cloud_config)) - self.file_logger.setLevel(log_level) - self.root_logger.addHandler(self.file_logger) diff --git a/openstackclient/common/logs.py b/openstackclient/common/logs.py new file mode 100644 index 00000000..6d1aec13 --- /dev/null +++ b/openstackclient/common/logs.py @@ -0,0 +1,170 @@ +# 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. +# + +"""Application logging""" + +import logging +import sys +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) + + +class LogConfigurator(object): + + _CONSOLE_MESSAGE_FORMAT = '%(message)s' + + def __init__(self, options): + self.root_logger = logging.getLogger('') + self.root_logger.setLevel(logging.DEBUG) + + # Force verbose_level 3 on --debug + self.dump_trace = False + if options.debug: + options.verbose_level = 3 + self.dump_trace = True + + # Always send higher-level messages to the console via stderr + self.console_logger = logging.StreamHandler(sys.stderr) + log_level = log_level_from_options(options) + self.console_logger.setLevel(log_level) + formatter = logging.Formatter(self._CONSOLE_MESSAGE_FORMAT) + self.console_logger.setFormatter(formatter) + self.root_logger.addHandler(self.console_logger) + + # Set the warning filter now + set_warning_filter(log_level) + + # Set up logging to a file + self.file_logger = None + log_file = options.log_file + if log_file: + self.file_logger = logging.FileHandler(filename=log_file) + self.file_logger.setFormatter(_FileFormatter(options=options)) + self.file_logger.setLevel(log_level) + self.root_logger.addHandler(self.file_logger) + + # Requests logs some stuff at INFO that we don't want + # unless we have DEBUG + requests_log = logging.getLogger("requests") + + # Other modules we don't want DEBUG output for + cliff_log = logging.getLogger('cliff') + stevedore_log = logging.getLogger('stevedore') + iso8601_log = logging.getLogger("iso8601") + + if options.debug: + # --debug forces traceback + requests_log.setLevel(logging.DEBUG) + else: + requests_log.setLevel(logging.ERROR) + + cliff_log.setLevel(logging.ERROR) + stevedore_log.setLevel(logging.ERROR) + iso8601_log.setLevel(logging.ERROR) + + def configure(self, cloud_config): + log_level = log_level_from_config(cloud_config.config) + set_warning_filter(log_level) + self.dump_trace = cloud_config.config.get('debug', self.dump_trace) + self.console_logger.setLevel(log_level) + + log_file = cloud_config.config.get('log_file', None) + if log_file: + if not self.file_logger: + self.file_logger = logging.FileHandler(filename=log_file) + formatter = _FileFormatter(cloud_config=cloud_config) + self.file_logger.setFormatter(formatter) + self.file_logger.setFormatter(_FileFormatter(config=cloud_config)) + self.file_logger.setLevel(log_level) + self.root_logger.addHandler(self.file_logger) diff --git a/openstackclient/shell.py b/openstackclient/shell.py index f7704efc..deb35b3c 100644 --- a/openstackclient/shell.py +++ b/openstackclient/shell.py @@ -29,8 +29,8 @@ from cliff import help import openstackclient from openstackclient.common import clientmanager from openstackclient.common import commandmanager -from openstackclient.common import context from openstackclient.common import exceptions as exc +from openstackclient.common import logs from openstackclient.common import timing from openstackclient.common import utils @@ -98,7 +98,7 @@ class OpenStackShell(app.App): def configure_logging(self): """Configure logging for the app.""" - self.log_configurator = context.LogConfigurator(self.options) + self.log_configurator = logs.LogConfigurator(self.options) self.dump_stack_trace = self.log_configurator.dump_trace def run(self, argv): @@ -240,8 +240,6 @@ class OpenStackShell(app.App): cloud=self.options.cloud, argparse=self.options, ) - if self.options.debug is not None: - self.options.debug = False self.log_configurator.configure(self.cloud) self.dump_stack_trace = self.log_configurator.dump_trace diff --git a/openstackclient/tests/common/test_context.py b/openstackclient/tests/common/test_context.py deleted file mode 100644 index 55e42851..00000000 --- a/openstackclient/tests/common/test_context.py +++ /dev/null @@ -1,202 +0,0 @@ -# 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. -# - -import logging -import mock - -from openstackclient.common import context -from openstackclient.tests import utils - - -class TestContext(utils.TestCase): - - def test_log_level_from_options(self): - opts = mock.Mock() - opts.verbose_level = 0 - self.assertEqual(logging.ERROR, context.log_level_from_options(opts)) - opts.verbose_level = 1 - self.assertEqual(logging.WARNING, context.log_level_from_options(opts)) - opts.verbose_level = 2 - self.assertEqual(logging.INFO, context.log_level_from_options(opts)) - opts.verbose_level = 3 - self.assertEqual(logging.DEBUG, context.log_level_from_options(opts)) - - def test_log_level_from_config(self): - cfg = {'verbose_level': 0} - self.assertEqual(logging.ERROR, context.log_level_from_config(cfg)) - cfg = {'verbose_level': 1} - self.assertEqual(logging.WARNING, context.log_level_from_config(cfg)) - cfg = {'verbose_level': 2} - self.assertEqual(logging.INFO, context.log_level_from_config(cfg)) - cfg = {'verbose_level': 3} - self.assertEqual(logging.DEBUG, context.log_level_from_config(cfg)) - cfg = {'verbose_level': 1, 'log_level': 'critical'} - self.assertEqual(logging.CRITICAL, context.log_level_from_config(cfg)) - cfg = {'verbose_level': 1, 'log_level': 'error'} - self.assertEqual(logging.ERROR, context.log_level_from_config(cfg)) - cfg = {'verbose_level': 1, 'log_level': 'warning'} - self.assertEqual(logging.WARNING, context.log_level_from_config(cfg)) - cfg = {'verbose_level': 1, 'log_level': 'info'} - self.assertEqual(logging.INFO, context.log_level_from_config(cfg)) - cfg = {'verbose_level': 1, 'log_level': 'debug'} - self.assertEqual(logging.DEBUG, context.log_level_from_config(cfg)) - cfg = {'verbose_level': 1, 'log_level': 'bogus'} - self.assertEqual(logging.WARNING, context.log_level_from_config(cfg)) - cfg = {'verbose_level': 1, 'log_level': 'info', 'debug': True} - self.assertEqual(logging.DEBUG, context.log_level_from_config(cfg)) - - @mock.patch('warnings.simplefilter') - def test_set_warning_filter(self, simplefilter): - context.set_warning_filter(logging.ERROR) - simplefilter.assert_called_with("ignore") - context.set_warning_filter(logging.WARNING) - simplefilter.assert_called_with("ignore") - context.set_warning_filter(logging.INFO) - simplefilter.assert_called_with("once") - - -class TestFileFormatter(utils.TestCase): - def test_nothing(self): - formatter = context._FileFormatter() - self.assertEqual(('%(asctime)s.%(msecs)03d %(process)d %(levelname)s ' - '%(name)s %(message)s'), formatter.fmt) - - def test_options(self): - class Opts(object): - cloud = 'cloudy' - os_project_name = 'projecty' - username = 'usernamey' - options = Opts() - formatter = context._FileFormatter(options=options) - self.assertEqual(('%(asctime)s.%(msecs)03d %(process)d %(levelname)s ' - '%(name)s [cloudy usernamey projecty] %(message)s'), - formatter.fmt) - - def test_config(self): - config = mock.Mock() - config.config = {'cloud': 'cloudy'} - config.auth = {'project_name': 'projecty', 'username': 'usernamey'} - formatter = context._FileFormatter(config=config) - self.assertEqual(('%(asctime)s.%(msecs)03d %(process)d %(levelname)s ' - '%(name)s [cloudy usernamey projecty] %(message)s'), - formatter.fmt) - - -class TestLogConfigurator(utils.TestCase): - def setUp(self): - super(TestLogConfigurator, self).setUp() - self.options = mock.Mock() - self.options.verbose_level = 1 - self.options.log_file = None - self.options.debug = False - self.root_logger = mock.Mock() - self.root_logger.setLevel = mock.Mock() - self.root_logger.addHandler = mock.Mock() - self.requests_log = mock.Mock() - self.requests_log.setLevel = mock.Mock() - self.cliff_log = mock.Mock() - self.cliff_log.setLevel = mock.Mock() - self.stevedore_log = mock.Mock() - self.stevedore_log.setLevel = mock.Mock() - self.iso8601_log = mock.Mock() - self.iso8601_log.setLevel = mock.Mock() - self.loggers = [ - self.root_logger, - self.requests_log, - self.cliff_log, - self.stevedore_log, - self.iso8601_log] - - @mock.patch('logging.StreamHandler') - @mock.patch('logging.getLogger') - @mock.patch('openstackclient.common.context.set_warning_filter') - def test_init(self, warning_filter, getLogger, handle): - getLogger.side_effect = self.loggers - console_logger = mock.Mock() - console_logger.setFormatter = mock.Mock() - console_logger.setLevel = mock.Mock() - handle.return_value = console_logger - - configurator = context.LogConfigurator(self.options) - - getLogger.assert_called_with('iso8601') # last call - warning_filter.assert_called_with(logging.WARNING) - self.root_logger.setLevel.assert_called_with(logging.DEBUG) - self.root_logger.addHandler.assert_called_with(console_logger) - self.requests_log.setLevel.assert_called_with(logging.ERROR) - self.cliff_log.setLevel.assert_called_with(logging.ERROR) - self.stevedore_log.setLevel.assert_called_with(logging.ERROR) - self.iso8601_log.setLevel.assert_called_with(logging.ERROR) - self.assertEqual(False, configurator.dump_trace) - - @mock.patch('logging.getLogger') - @mock.patch('openstackclient.common.context.set_warning_filter') - def test_init_no_debug(self, warning_filter, getLogger): - getLogger.side_effect = self.loggers - self.options.debug = True - - configurator = context.LogConfigurator(self.options) - - warning_filter.assert_called_with(logging.DEBUG) - self.requests_log.setLevel.assert_called_with(logging.DEBUG) - self.assertEqual(True, configurator.dump_trace) - - @mock.patch('logging.FileHandler') - @mock.patch('logging.getLogger') - @mock.patch('openstackclient.common.context.set_warning_filter') - @mock.patch('openstackclient.common.context._FileFormatter') - def test_init_log_file(self, formatter, warning_filter, getLogger, handle): - getLogger.side_effect = self.loggers - self.options.log_file = '/tmp/log_file' - file_logger = mock.Mock() - file_logger.setFormatter = mock.Mock() - file_logger.setLevel = mock.Mock() - handle.return_value = file_logger - mock_formatter = mock.Mock() - formatter.return_value = mock_formatter - - context.LogConfigurator(self.options) - - handle.assert_called_with(filename=self.options.log_file) - self.root_logger.addHandler.assert_called_with(file_logger) - file_logger.setFormatter.assert_called_with(mock_formatter) - file_logger.setLevel.assert_called_with(logging.WARNING) - - @mock.patch('logging.FileHandler') - @mock.patch('logging.getLogger') - @mock.patch('openstackclient.common.context.set_warning_filter') - @mock.patch('openstackclient.common.context._FileFormatter') - def test_configure(self, formatter, warning_filter, getLogger, handle): - getLogger.side_effect = self.loggers - configurator = context.LogConfigurator(self.options) - cloud_config = mock.Mock() - config_log = '/tmp/config_log' - cloud_config.config = { - 'log_file': config_log, - 'verbose_level': 1, - 'log_level': 'info'} - file_logger = mock.Mock() - file_logger.setFormatter = mock.Mock() - file_logger.setLevel = mock.Mock() - handle.return_value = file_logger - mock_formatter = mock.Mock() - formatter.return_value = mock_formatter - - configurator.configure(cloud_config) - - warning_filter.assert_called_with(logging.INFO) - handle.assert_called_with(filename=config_log) - self.root_logger.addHandler.assert_called_with(file_logger) - file_logger.setFormatter.assert_called_with(mock_formatter) - file_logger.setLevel.assert_called_with(logging.INFO) - self.assertEqual(False, configurator.dump_trace) diff --git a/openstackclient/tests/common/test_logs.py b/openstackclient/tests/common/test_logs.py new file mode 100644 index 00000000..fe054a3b --- /dev/null +++ b/openstackclient/tests/common/test_logs.py @@ -0,0 +1,202 @@ +# 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. +# + +import logging +import mock + +from openstackclient.common import logs +from openstackclient.tests import utils + + +class TestContext(utils.TestCase): + + def test_log_level_from_options(self): + opts = mock.Mock() + opts.verbose_level = 0 + self.assertEqual(logging.ERROR, logs.log_level_from_options(opts)) + opts.verbose_level = 1 + self.assertEqual(logging.WARNING, logs.log_level_from_options(opts)) + opts.verbose_level = 2 + self.assertEqual(logging.INFO, logs.log_level_from_options(opts)) + opts.verbose_level = 3 + self.assertEqual(logging.DEBUG, logs.log_level_from_options(opts)) + + def test_log_level_from_config(self): + cfg = {'verbose_level': 0} + self.assertEqual(logging.ERROR, logs.log_level_from_config(cfg)) + cfg = {'verbose_level': 1} + self.assertEqual(logging.WARNING, logs.log_level_from_config(cfg)) + cfg = {'verbose_level': 2} + self.assertEqual(logging.INFO, logs.log_level_from_config(cfg)) + cfg = {'verbose_level': 3} + self.assertEqual(logging.DEBUG, logs.log_level_from_config(cfg)) + cfg = {'verbose_level': 1, 'log_level': 'critical'} + self.assertEqual(logging.CRITICAL, logs.log_level_from_config(cfg)) + cfg = {'verbose_level': 1, 'log_level': 'error'} + self.assertEqual(logging.ERROR, logs.log_level_from_config(cfg)) + cfg = {'verbose_level': 1, 'log_level': 'warning'} + self.assertEqual(logging.WARNING, logs.log_level_from_config(cfg)) + cfg = {'verbose_level': 1, 'log_level': 'info'} + self.assertEqual(logging.INFO, logs.log_level_from_config(cfg)) + cfg = {'verbose_level': 1, 'log_level': 'debug'} + self.assertEqual(logging.DEBUG, logs.log_level_from_config(cfg)) + cfg = {'verbose_level': 1, 'log_level': 'bogus'} + self.assertEqual(logging.WARNING, logs.log_level_from_config(cfg)) + cfg = {'verbose_level': 1, 'log_level': 'info', 'debug': True} + self.assertEqual(logging.DEBUG, logs.log_level_from_config(cfg)) + + @mock.patch('warnings.simplefilter') + def test_set_warning_filter(self, simplefilter): + logs.set_warning_filter(logging.ERROR) + simplefilter.assert_called_with("ignore") + logs.set_warning_filter(logging.WARNING) + simplefilter.assert_called_with("ignore") + logs.set_warning_filter(logging.INFO) + simplefilter.assert_called_with("once") + + +class TestFileFormatter(utils.TestCase): + def test_nothing(self): + formatter = logs._FileFormatter() + self.assertEqual(('%(asctime)s.%(msecs)03d %(process)d %(levelname)s ' + '%(name)s %(message)s'), formatter.fmt) + + def test_options(self): + class Opts(object): + cloud = 'cloudy' + os_project_name = 'projecty' + username = 'usernamey' + options = Opts() + formatter = logs._FileFormatter(options=options) + self.assertEqual(('%(asctime)s.%(msecs)03d %(process)d %(levelname)s ' + '%(name)s [cloudy usernamey projecty] %(message)s'), + formatter.fmt) + + def test_config(self): + config = mock.Mock() + config.config = {'cloud': 'cloudy'} + config.auth = {'project_name': 'projecty', 'username': 'usernamey'} + formatter = logs._FileFormatter(config=config) + self.assertEqual(('%(asctime)s.%(msecs)03d %(process)d %(levelname)s ' + '%(name)s [cloudy usernamey projecty] %(message)s'), + formatter.fmt) + + +class TestLogConfigurator(utils.TestCase): + def setUp(self): + super(TestLogConfigurator, self).setUp() + self.options = mock.Mock() + self.options.verbose_level = 1 + self.options.log_file = None + self.options.debug = False + self.root_logger = mock.Mock() + self.root_logger.setLevel = mock.Mock() + self.root_logger.addHandler = mock.Mock() + self.requests_log = mock.Mock() + self.requests_log.setLevel = mock.Mock() + self.cliff_log = mock.Mock() + self.cliff_log.setLevel = mock.Mock() + self.stevedore_log = mock.Mock() + self.stevedore_log.setLevel = mock.Mock() + self.iso8601_log = mock.Mock() + self.iso8601_log.setLevel = mock.Mock() + self.loggers = [ + self.root_logger, + self.requests_log, + self.cliff_log, + self.stevedore_log, + self.iso8601_log] + + @mock.patch('logging.StreamHandler') + @mock.patch('logging.getLogger') + @mock.patch('openstackclient.common.logs.set_warning_filter') + def test_init(self, warning_filter, getLogger, handle): + getLogger.side_effect = self.loggers + console_logger = mock.Mock() + console_logger.setFormatter = mock.Mock() + console_logger.setLevel = mock.Mock() + handle.return_value = console_logger + + configurator = logs.LogConfigurator(self.options) + + getLogger.assert_called_with('iso8601') # last call + warning_filter.assert_called_with(logging.WARNING) + self.root_logger.setLevel.assert_called_with(logging.DEBUG) + self.root_logger.addHandler.assert_called_with(console_logger) + self.requests_log.setLevel.assert_called_with(logging.ERROR) + self.cliff_log.setLevel.assert_called_with(logging.ERROR) + self.stevedore_log.setLevel.assert_called_with(logging.ERROR) + self.iso8601_log.setLevel.assert_called_with(logging.ERROR) + self.assertEqual(False, configurator.dump_trace) + + @mock.patch('logging.getLogger') + @mock.patch('openstackclient.common.logs.set_warning_filter') + def test_init_no_debug(self, warning_filter, getLogger): + getLogger.side_effect = self.loggers + self.options.debug = True + + configurator = logs.LogConfigurator(self.options) + + warning_filter.assert_called_with(logging.DEBUG) + self.requests_log.setLevel.assert_called_with(logging.DEBUG) + self.assertEqual(True, configurator.dump_trace) + + @mock.patch('logging.FileHandler') + @mock.patch('logging.getLogger') + @mock.patch('openstackclient.common.logs.set_warning_filter') + @mock.patch('openstackclient.common.logs._FileFormatter') + def test_init_log_file(self, formatter, warning_filter, getLogger, handle): + getLogger.side_effect = self.loggers + self.options.log_file = '/tmp/log_file' + file_logger = mock.Mock() + file_logger.setFormatter = mock.Mock() + file_logger.setLevel = mock.Mock() + handle.return_value = file_logger + mock_formatter = mock.Mock() + formatter.return_value = mock_formatter + + logs.LogConfigurator(self.options) + + handle.assert_called_with(filename=self.options.log_file) + self.root_logger.addHandler.assert_called_with(file_logger) + file_logger.setFormatter.assert_called_with(mock_formatter) + file_logger.setLevel.assert_called_with(logging.WARNING) + + @mock.patch('logging.FileHandler') + @mock.patch('logging.getLogger') + @mock.patch('openstackclient.common.logs.set_warning_filter') + @mock.patch('openstackclient.common.logs._FileFormatter') + def test_configure(self, formatter, warning_filter, getLogger, handle): + getLogger.side_effect = self.loggers + configurator = logs.LogConfigurator(self.options) + cloud_config = mock.Mock() + config_log = '/tmp/config_log' + cloud_config.config = { + 'log_file': config_log, + 'verbose_level': 1, + 'log_level': 'info'} + file_logger = mock.Mock() + file_logger.setFormatter = mock.Mock() + file_logger.setLevel = mock.Mock() + handle.return_value = file_logger + mock_formatter = mock.Mock() + formatter.return_value = mock_formatter + + configurator.configure(cloud_config) + + warning_filter.assert_called_with(logging.INFO) + handle.assert_called_with(filename=config_log) + self.root_logger.addHandler.assert_called_with(file_logger) + file_logger.setFormatter.assert_called_with(mock_formatter) + file_logger.setLevel.assert_called_with(logging.INFO) + self.assertEqual(False, configurator.dump_trace) -- cgit v1.2.1