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:
from osc_lib import exceptions
from osc_lib import logs
from osc_lib import utils
# OSC common interfaces available to plugins:
from openstackclient.common import command
from openstackclient.common import parseractions
from openstackclient.common import logs
class DeleteMypluginobject(command.Command):

View File

@ -11,186 +11,16 @@
# 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 warnings
from osc_lib.logs import * # noqa
from osc_lib.logs import _FileFormatter # noqa
def get_loggers():
loggers = {}
for logkey in logging.Logger.manager.loggerDict.keys():
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)
sys.stderr.write(
"WARNING: %s is deprecated and will be removed after Jun 2017. "
"Please use osc_lib.logs\n" % __name__
)

View File

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

View File

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