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
This commit is contained in:
Brian Curtin 2015-02-04 21:41:09 -06:00
parent 005f211f28
commit 8dcff5a621
5 changed files with 86 additions and 24 deletions

View File

@ -96,3 +96,4 @@ can be customized.
identity_v3 identity_v3
resource resource
service_filter service_filter
utils

View File

@ -0,0 +1,4 @@
Utilities
=========
.. automodule:: openstack.utils
:members: enable_logging

View File

@ -42,8 +42,8 @@ import traceback
import uuid import uuid
from openstack import user_preference from openstack import user_preference
from openstack import utils
CONSOLE_MESSAGE_FORMAT = '%(levelname)s: %(name)s %(message)s'
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@ -318,31 +318,9 @@ def option_parser():
return 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(): def setup():
opts = option_parser().parse_args() opts = option_parser().parse_args()
configure_logging(opts) utils.enable_logging(opts.debug)
return opts return opts

View File

@ -12,9 +12,50 @@
import unittest import unittest
import mock
from openstack import utils 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): class Test_urljoin(unittest.TestCase):
def test_strings(self): def test_strings(self):

View File

@ -10,6 +10,44 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # 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): def urljoin(*args):
"""A custom version of urljoin that simply joins strings into a path. """A custom version of urljoin that simply joins strings into a path.