From 8dcff5a62147a5beb8df39df598ceac96ac3516f Mon Sep 17 00:00:00 2001 From: Brian Curtin Date: Wed, 4 Feb 2015 21:41:09 -0600 Subject: [PATCH] Add logging functionality to openstack.utils This change moves the ability to enable logging out of the examples.common module and into the openstack.utils since it is generally useful. This is intended to give users a short-term solution to receive debugging messages. If they want to always have our messages logged in their application they should create their own logging handler(s) with their own format, and that will cause our messages to be sent to their handlers as they wish. https://bugs.launchpad.net/python-openstacksdk/+bug/1418307 is open to track the documentation aspect of this. Change-Id: Ic8768d529d0389b9b04bd4ea31453a82f30faf33 --- doc/source/users/index.rst | 1 + doc/source/users/utils.rst | 4 ++++ examples/common.py | 26 ++-------------------- openstack/tests/test_utils.py | 41 +++++++++++++++++++++++++++++++++++ openstack/utils.py | 38 ++++++++++++++++++++++++++++++++ 5 files changed, 86 insertions(+), 24 deletions(-) create mode 100644 doc/source/users/utils.rst diff --git a/doc/source/users/index.rst b/doc/source/users/index.rst index 5ea3649ae..363dabab9 100644 --- a/doc/source/users/index.rst +++ b/doc/source/users/index.rst @@ -96,3 +96,4 @@ can be customized. identity_v3 resource service_filter + utils diff --git a/doc/source/users/utils.rst b/doc/source/users/utils.rst new file mode 100644 index 000000000..f69638e30 --- /dev/null +++ b/doc/source/users/utils.rst @@ -0,0 +1,4 @@ +Utilities +========= +.. automodule:: openstack.utils + :members: enable_logging diff --git a/examples/common.py b/examples/common.py index c3b5a88b4..68bcdceda 100755 --- a/examples/common.py +++ b/examples/common.py @@ -42,8 +42,8 @@ import traceback import uuid from openstack import user_preference +from openstack import utils -CONSOLE_MESSAGE_FORMAT = '%(levelname)s: %(name)s %(message)s' _logger = logging.getLogger(__name__) @@ -318,31 +318,9 @@ def option_parser(): return parser -def configure_logging(opts): - """Typical app logging setup - - Based on OSC/cliff - - """ - - root_logger = logging.getLogger('') - - # Always send higher-level messages to the console via stderr - console = logging.StreamHandler(sys.stderr) - formatter = logging.Formatter(CONSOLE_MESSAGE_FORMAT) - console.setFormatter(formatter) - root_logger.addHandler(console) - - if opts.debug: - root_logger.setLevel(logging.DEBUG) - else: - root_logger.setLevel(logging.WARNING) - return - - def setup(): opts = option_parser().parse_args() - configure_logging(opts) + utils.enable_logging(opts.debug) return opts diff --git a/openstack/tests/test_utils.py b/openstack/tests/test_utils.py index 4031d9c8e..59e4e0868 100644 --- a/openstack/tests/test_utils.py +++ b/openstack/tests/test_utils.py @@ -12,9 +12,50 @@ import unittest +import mock + from openstack import utils +class Test_enable_logging(unittest.TestCase): + + def _console_tests(self, fake_logging, level, debug): + the_logger = mock.MagicMock() + fake_logging.getLogger.return_value = the_logger + + utils.enable_logging(debug=debug) + + self.assertEqual(the_logger.addHandler.call_count, 1) + the_logger.setLevel.assert_called_with(level) + + def _file_tests(self, fake_logging, level, debug): + the_logger = mock.MagicMock() + fake_logging.getLogger.return_value = the_logger + fake_path = "fake/path.log" + + utils.enable_logging(debug=debug, path=fake_path) + + fake_logging.FileHandler.assert_called_with(fake_path) + self.assertEqual(the_logger.addHandler.call_count, 2) + the_logger.setLevel.assert_called_with(level) + + @mock.patch("openstack.utils.logging") + def test_debug_console(self, fake_logging): + self._console_tests(fake_logging, fake_logging.DEBUG, True) + + @mock.patch("openstack.utils.logging") + def test_warning_console(self, fake_logging): + self._console_tests(fake_logging, fake_logging.WARNING, False) + + @mock.patch("openstack.utils.logging") + def test_debug_file(self, fake_logging): + self._file_tests(fake_logging, fake_logging.DEBUG, True) + + @mock.patch("openstack.utils.logging") + def test_warning_file(self, fake_logging): + self._file_tests(fake_logging, fake_logging.WARNING, False) + + class Test_urljoin(unittest.TestCase): def test_strings(self): diff --git a/openstack/utils.py b/openstack/utils.py index ae7342e0b..367a53985 100644 --- a/openstack/utils.py +++ b/openstack/utils.py @@ -10,6 +10,44 @@ # License for the specific language governing permissions and limitations # under the License. +import logging +import sys + + +def enable_logging(debug=False, path=None): + """Enable logging of messages to sys.stderr + + This function is available for debugging purposes. If you wish to + log this package's message in your application, the standard library + ``logging`` package will receive these messages in any handlers you + create. + + :param bool debug: Set this to ``True`` to receive debug messages, + which includes HTTP requests and responses, + or ``False`` for warning messages. + :param str path: If a *path* is specified, logging output will + written to that file in addition to sys.stderr. + The path is passed to logging.FileHandler, + which will append messages the file (and create + it if needed). *Default: None* + + :rtype: None + """ + root_logger = logging.getLogger('') + formatter = logging.Formatter( + '%(asctime)s %(levelname)s: %(name)s %(message)s') + + console = logging.StreamHandler(sys.stderr) + console.setFormatter(formatter) + root_logger.addHandler(console) + + if path is not None: + file_handler = logging.FileHandler(path) + file_handler.setFormatter(formatter) + root_logger.addHandler(file_handler) + + root_logger.setLevel(logging.DEBUG if debug else logging.WARNING) + def urljoin(*args): """A custom version of urljoin that simply joins strings into a path.