diff --git a/oslo_log/handlers.py b/oslo_log/handlers.py index bd1b071d..9ecbcd69 100644 --- a/oslo_log/handlers.py +++ b/oslo_log/handlers.py @@ -69,6 +69,7 @@ class RFCSysLogHandler(logging.handlers.SysLogHandler): return msg _AUDIT = logging.INFO + 1 +_TRACE = 5 if syslog is not None: @@ -102,6 +103,7 @@ if syslog is not None: class ColorHandler(logging.StreamHandler): LEVEL_COLORS = { + _TRACE: '\033[00;35m', # MAGENTA logging.DEBUG: '\033[00;32m', # GREEN logging.INFO: '\033[00;36m', # CYAN _AUDIT: '\033[01;36m', # BOLD CYAN diff --git a/oslo_log/log.py b/oslo_log/log.py index 2785f510..e062614a 100644 --- a/oslo_log/log.py +++ b/oslo_log/log.py @@ -51,6 +51,18 @@ from oslo_log import _options from oslo_log import formatters from oslo_log import handlers +CRITICAL = logging.CRITICAL +FATAL = logging.FATAL +ERROR = logging.ERROR +WARNING = logging.WARNING +WARN = logging.WARNING +INFO = logging.INFO +DEBUG = logging.DEBUG +NOTSET = logging.NOTSET +TRACE = handlers._TRACE + +logging.addLevelName(TRACE, 'TRACE') + def _get_log_file_path(conf, binary=None): logfile = conf.log_file @@ -77,6 +89,9 @@ class BaseLoggerAdapter(logging.LoggerAdapter): def handlers(self): return self.logger.handlers + def trace(self, msg, *args, **kwargs): + self.log(TRACE, msg, *args, **kwargs) + def isEnabledFor(self, level): if _PY26: # This method was added in python 2.7 (and it does the exact diff --git a/oslo_log/tests/unit/test_log.py b/oslo_log/tests/unit/test_log.py index 8e10c0ff..016b64b6 100644 --- a/oslo_log/tests/unit/test_log.py +++ b/oslo_log/tests/unit/test_log.py @@ -242,27 +242,37 @@ class LogLevelTestCase(BaseTestCase): levels = self.CONF.default_log_levels levels.append("nova-test=INFO") levels.append("nova-not-debug=WARN") - levels.append("nova-below-debug=5") + levels.append("nova-below-debug=7") + levels.append("nova-trace=TRACE") self.config(default_log_levels=levels, verbose=True) log.setup(self.CONF, 'testing') self.log = log.getLogger('nova-test') self.log_no_debug = log.getLogger('nova-not-debug') self.log_below_debug = log.getLogger('nova-below-debug') + self.log_trace = log.getLogger('nova-trace') def test_is_enabled_for(self): self.assertTrue(self.log.isEnabledFor(logging.INFO)) self.assertFalse(self.log_no_debug.isEnabledFor(logging.DEBUG)) self.assertTrue(self.log_below_debug.isEnabledFor(logging.DEBUG)) - self.assertTrue(self.log_below_debug.isEnabledFor(5)) + self.assertTrue(self.log_below_debug.isEnabledFor(7)) + self.assertTrue(self.log_trace.isEnabledFor(log.TRACE)) def test_has_level_from_flags(self): self.assertEqual(logging.INFO, self.log.logger.getEffectiveLevel()) + def test_has_level_from_flags_for_trace(self): + self.assertEqual(log.TRACE, self.log_trace.logger.getEffectiveLevel()) + def test_child_log_has_level_of_parent_flag(self): l = log.getLogger('nova-test.foo') self.assertEqual(logging.INFO, l.logger.getEffectiveLevel()) + def test_child_log_has_level_of_parent_flag_for_trace(self): + l = log.getLogger('nova-trace.foo') + self.assertEqual(log.TRACE, l.logger.getEffectiveLevel()) + class JSONFormatterTestCase(LogTestBase): def setUp(self): @@ -546,6 +556,20 @@ class InstanceRecordTestCase(LogTestBase): self.assertEqual(infoexpected, self.stream.getvalue()) +class TraceLevelTestCase(LogTestBase): + def setUp(self): + super(TraceLevelTestCase, self).setUp() + self.config(logging_context_format_string="%(message)s") + self.mylog = log.getLogger() + self._add_handler_with_cleanup(self.mylog) + self._set_log_level_with_cleanup(self.mylog, log.TRACE) + + def test_trace_log_msg(self): + ctxt = _fake_context() + self.mylog.trace("my trace message", context=ctxt) + self.assertEqual('my trace message\n', self.stream.getvalue()) + + class DomainTestCase(LogTestBase): def setUp(self): super(DomainTestCase, self).setUp()