osc-lib: logs

Change-Id: I2a4d40cd72cc22e97a600751ae29c2309ebed28b
This commit is contained in:
Dean Troyer 2016-06-09 16:29:42 -05:00
parent e5e29a8fef
commit 59dffb9c62
4 changed files with 20 additions and 187 deletions

View File

@ -153,12 +153,12 @@ the plugin commands:
# osc-lib interfaces available to plugins: # osc-lib interfaces available to plugins:
from osc_lib import exceptions from osc_lib import exceptions
from osc_lib import logs
from osc_lib import utils from osc_lib import utils
# OSC common interfaces available to plugins: # OSC common interfaces available to plugins:
from openstackclient.common import command from openstackclient.common import command
from openstackclient.common import parseractions from openstackclient.common import parseractions
from openstackclient.common import logs
class DeleteMypluginobject(command.Command): class DeleteMypluginobject(command.Command):

View File

@ -11,186 +11,16 @@
# under the License. # under the License.
# #
"""Application logging""" # NOTE(dtroyer): This file is deprecated in Jun 2016, remove after 4.x release
# or Jun 2017.
import logging
import sys import sys
import warnings
from osc_lib.logs import * # noqa
from osc_lib.logs import _FileFormatter # noqa
def get_loggers(): sys.stderr.write(
loggers = {} "WARNING: %s is deprecated and will be removed after Jun 2017. "
for logkey in logging.Logger.manager.loggerDict.keys(): "Please use osc_lib.logs\n" % __name__
loggers[logkey] = logging.getLevelName(logging.getLogger(logkey).level) )
return loggers
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_string(level_string):
log_level = {
'critical': logging.CRITICAL,
'error': logging.ERROR,
'warning': logging.WARNING,
'info': logging.INFO,
'debug': logging.DEBUG,
}.get(level_string, logging.WARNING)
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'
return log_level_from_string(verbose_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')
if log_file:
if not self.file_logger:
self.file_logger = logging.FileHandler(filename=log_file)
self.file_logger.setFormatter(_FileFormatter(config=cloud_config))
self.file_logger.setLevel(log_level)
self.root_logger.addHandler(self.file_logger)
logconfig = cloud_config.config.get('logging')
if logconfig:
highest_level = logging.NOTSET
for k in logconfig.keys():
level = log_level_from_string(logconfig[k])
logging.getLogger(k).setLevel(level)
if (highest_level < level):
highest_level = level
self.console_logger.setLevel(highest_level)
if self.file_logger:
self.file_logger.setLevel(highest_level)
# loggers that are not set will use the handler level, so we
# need to set the global level for all the loggers
for logkey in logging.Logger.manager.loggerDict.keys():
logger = logging.getLogger(logkey)
if logger.level == logging.NOTSET:
logger.setLevel(log_level)

View File

@ -27,6 +27,7 @@ from cliff import command
from cliff import complete from cliff import complete
from cliff import help from cliff import help
from osc_lib import exceptions as exc from osc_lib import exceptions as exc
from osc_lib import logs
from osc_lib import utils from osc_lib import utils
from oslo_utils import importutils from oslo_utils import importutils
from oslo_utils import strutils from oslo_utils import strutils
@ -34,7 +35,6 @@ from oslo_utils import strutils
import openstackclient import openstackclient
from openstackclient.common import clientmanager from openstackclient.common import clientmanager
from openstackclient.common import commandmanager from openstackclient.common import commandmanager
from openstackclient.common import logs
from openstackclient.common import timing from openstackclient.common import timing
from os_client_config import config as cloud_config from os_client_config import config as cloud_config

View File

@ -11,6 +11,9 @@
# under the License. # under the License.
# #
# NOTE(dtroyer): This file is deprecated in Jun 2016, remove after 4.x release
# or Jun 2017.
import logging import logging
import mock import mock
@ -121,7 +124,7 @@ class TestLogConfigurator(utils.TestCase):
@mock.patch('logging.StreamHandler') @mock.patch('logging.StreamHandler')
@mock.patch('logging.getLogger') @mock.patch('logging.getLogger')
@mock.patch('openstackclient.common.logs.set_warning_filter') @mock.patch('osc_lib.logs.set_warning_filter')
def test_init(self, warning_filter, getLogger, handle): def test_init(self, warning_filter, getLogger, handle):
getLogger.side_effect = self.loggers getLogger.side_effect = self.loggers
console_logger = mock.Mock() console_logger = mock.Mock()
@ -142,7 +145,7 @@ class TestLogConfigurator(utils.TestCase):
self.assertFalse(configurator.dump_trace) self.assertFalse(configurator.dump_trace)
@mock.patch('logging.getLogger') @mock.patch('logging.getLogger')
@mock.patch('openstackclient.common.logs.set_warning_filter') @mock.patch('osc_lib.logs.set_warning_filter')
def test_init_no_debug(self, warning_filter, getLogger): def test_init_no_debug(self, warning_filter, getLogger):
getLogger.side_effect = self.loggers getLogger.side_effect = self.loggers
self.options.debug = True self.options.debug = True
@ -155,8 +158,8 @@ class TestLogConfigurator(utils.TestCase):
@mock.patch('logging.FileHandler') @mock.patch('logging.FileHandler')
@mock.patch('logging.getLogger') @mock.patch('logging.getLogger')
@mock.patch('openstackclient.common.logs.set_warning_filter') @mock.patch('osc_lib.logs.set_warning_filter')
@mock.patch('openstackclient.common.logs._FileFormatter') @mock.patch('osc_lib.logs._FileFormatter')
def test_init_log_file(self, formatter, warning_filter, getLogger, handle): def test_init_log_file(self, formatter, warning_filter, getLogger, handle):
getLogger.side_effect = self.loggers getLogger.side_effect = self.loggers
self.options.log_file = '/tmp/log_file' self.options.log_file = '/tmp/log_file'
@ -176,8 +179,8 @@ class TestLogConfigurator(utils.TestCase):
@mock.patch('logging.FileHandler') @mock.patch('logging.FileHandler')
@mock.patch('logging.getLogger') @mock.patch('logging.getLogger')
@mock.patch('openstackclient.common.logs.set_warning_filter') @mock.patch('osc_lib.logs.set_warning_filter')
@mock.patch('openstackclient.common.logs._FileFormatter') @mock.patch('osc_lib.logs._FileFormatter')
def test_configure(self, formatter, warning_filter, getLogger, handle): def test_configure(self, formatter, warning_filter, getLogger, handle):
getLogger.side_effect = self.loggers getLogger.side_effect = self.loggers
configurator = logs.LogConfigurator(self.options) configurator = logs.LogConfigurator(self.options)