Configure basic logging, and make it possible to log to console.

--log-to-console will output messages at INFO and above to the
command-line.  This is super-useful when running cloud-init from a
terminal, when you don't want to have to dig in a log file.

Change-Id: Ieb3db384b73441c19ef463649c94b04ffaac8026
This commit is contained in:
Daniel Watkins 2015-09-04 15:40:22 +01:00
parent dc3efec379
commit a51119762c
4 changed files with 51 additions and 0 deletions

View File

@ -40,6 +40,7 @@ class _BlatherLoggerAdapter(logging.LoggerAdapter):
# TODO(harlowja): we should remove when we no longer have to support 2.6...
if sys.version_info[0:2] == (2, 6): # pragma: nocover
from logutils.dictconfig import dictConfig
class _FixedBlatherLoggerAdapter(_BlatherLoggerAdapter):
"""Ensures isEnabledFor() exists on adapters that are created."""
@ -72,6 +73,7 @@ if sys.version_info[0:2] == (2, 6): # pragma: nocover
self.lock = None
else:
from logging.config import dictConfig
_NullHandler = logging.NullHandler
@ -80,3 +82,32 @@ def getLogger(name=_BASE, extra=None):
if not logger.handlers:
logger.addHandler(_NullHandler())
return _BlatherLoggerAdapter(logger, extra=extra)
def configure_logging(log_to_console=False):
logging_config = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s',
},
},
'handlers': {
'console': {
'level': 'INFO',
'class': 'logging.StreamHandler',
'formatter': 'standard',
},
},
'loggers': {
'': {
'handlers': [],
'level': 'DEBUG',
'propagate': True,
},
},
}
if log_to_console:
logging_config['loggers']['']['handlers'].append('console')
dictConfig(logging_config)

View File

@ -6,6 +6,8 @@
import argparse
import sys
from cloudinit import logging
def populate_parser(parser, common, subcommands):
"""Populate an ArgumentParser with data rather than code
@ -48,6 +50,7 @@ def main(args=sys.argv):
if not hasattr(parsed, 'func'):
parser.error('too few arguments')
logging.configure_logging(log_to_console=parsed.log_to_console)
parsed.func(parsed)
return 0
@ -63,6 +66,7 @@ def unimplemented_subcommand(args):
COMMON_ARGS = [
(('--log-to-console',), {'action': 'store_true', 'default': False}),
(('--verbose', '-v'), {'action': 'count', 'default': 0}),
]

View File

@ -46,3 +46,18 @@ class TestMain(TestCase):
self.assertRaises(SystemExit, shell.main, args=['cloud-init'])
self.assertIn('cloud-init: error: too few arguments',
stderr.getvalue())
class TestLoggingConfiguration(TestCase):
@mock.patch('cloudinit.shell.sys.stderr', new_callable=six.StringIO)
def test_log_to_console(self, stderr):
shell.main(args=['cloud-init', '--log-to-console', 'version'])
shell.logging.getLogger().info('test log message')
self.assertIn('test log message', stderr.getvalue())
@mock.patch('cloudinit.shell.sys.stderr', new_callable=six.StringIO)
def test_log_to_console_not_default(self, stderr):
shell.main(args=['cloud-init', 'version'])
shell.logging.getLogger().info('test log message')
self.assertNotIn('test log message', stderr.getvalue())

View File

@ -22,6 +22,7 @@ install_command = pip install {opts} {packages}
[testenv:py26]
deps = {[testenv]deps}
importlib
logutils
[testenv:py27-coverage]
commands = {envpython} {toxinidir}/tools/noproxy nosetests --with-coverage --cover-erase --cover-package=cloudinit --cover-min-percentage=90 --cover-html {posargs}