Module: check_mk
Branch: master
Commit: 027da39d982c4eeade855be732caa157d15f39d7
URL:
http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=027da39d982c4e…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Fri Oct 14 13:24:34 2016 +0200
Started implementing new standard Check_MK logging mechanism
---
lib/log.py | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++
modules/check_mk.py | 22 +++++++--
tests/lib/test_log.py | 47 ++++++++++++++++++
3 files changed, 196 insertions(+), 5 deletions(-)
diff --git a/lib/log.py b/lib/log.py
new file mode 100644
index 0000000..b68721c
--- /dev/null
+++ b/lib/log.py
@@ -0,0 +1,132 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8; py-indent-offset: 4 -*-
+# +------------------------------------------------------------------+
+# | ____ _ _ __ __ _ __ |
+# | / ___| |__ ___ ___| | __ | \/ | |/ / |
+# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
+# | | |___| | | | __/ (__| < | | | | . \ |
+# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
+# | |
+# | Copyright Mathias Kettner 2016 mk(a)mathias-kettner.de |
+# +------------------------------------------------------------------+
+#
+# This file is part of Check_MK.
+# The official homepage is at
http://mathias-kettner.de/check_mk.
+#
+# check_mk is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation in version 2. check_mk is distributed
+# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
+# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. See the GNU General Public License for more de-
+# tails. You should have received a copy of the GNU General Public
+# License along with GNU Make; see the file COPYING. If not, write
+# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+# Boston, MA 02110-1301 USA.
+
+import sys
+import logging as _logging
+
+# Users should be able to set log levels without importing "logging"
+
+CRITICAL = _logging.CRITICAL
+ERROR = _logging.ERROR
+WARNING = _logging.WARNING
+INFO = _logging.INFO
+DEBUG = _logging.DEBUG
+
+
+# We need an additional log level between INFO and DEBUG to reflect the
+# verbose() and vverbose() mechanisms of Check_MK.
+
+VERBOSE = 15
+
+class CMKLogger(_logging.getLoggerClass()):
+ def __init__(self, name, level=_logging.NOTSET):
+ super(CMKLogger, self).__init__(name, level)
+
+ _logging.addLevelName(VERBOSE, "VERBOSE")
+
+ def verbose(self, msg, *args, **kwargs):
+ if self.isEnabledFor(VERBOSE):
+ self._log(VERBOSE, msg, args, **kwargs)
+
+_logging.setLoggerClass(CMKLogger)
+
+
+# Set default logging handler to avoid "No handler found" warnings.
+# Python 2.7+
+logger = _logging.getLogger("cmk")
+logger.addHandler(_logging.NullHandler())
+logger.setLevel(INFO)
+
+
+def get_logger(name):
+ """This function provides the logging object for client code.
+
+ It returns a child logger of the "cmk" main logger, identified
+ by the given name. The name of the child logger will be prefixed
+ with "cmk.", for example "cmk.mkeventd" in case of
"mkeventd".
+ """
+ return logger.getChild(name)
+
+
+def setup_console_logging():
+ """This method enables all log messages to be written to the console
+ without any additional information like date/time, logger-name. Just
+ the log line is written.
+
+ This can be used for existing command line applications which were
+ using sys.stdout.write() or print() before.
+ """
+
+ handler = _logging.StreamHandler(stream=sys.stdout)
+
+ formatter = _logging.Formatter("%(message)s")
+ handler.setFormatter(formatter)
+
+ logger.addHandler(handler)
+
+
+def set_verbosity(verbosity):
+ """Values for "verbosity":
+
+ 0: enables INFO and above
+ 1: enables VERBOSE and above
+ 2: enables DEBUG and above (ALL messages)
+ """
+ if verbosity == 0:
+ logger.setLevel(INFO)
+
+ elif verbosity == 1:
+ logger.setLevel(VERBOSE)
+
+ elif verbosity == 2:
+ logger.setLevel(DEBUG)
+
+ else:
+ raise NotImplementedError()
+
+
+# TODO: Experimental. Not yet used.
+class LogMixin(object):
+ """Inherit from this class to provide logging support.
+
+ Makes a logger available via "self.logger" for objects and
+ "self.cls_logger" for the class.
+ """
+ _logger = None
+ _cls_logger = None
+
+ @property
+ def logger(self):
+ if not self._logger:
+ self._logger = logging.getLogger('.'.join([__name__,
self.__class__.__name__]))
+ return self._logger
+
+
+ @classmethod
+ def logger(cls):
+ if not cls._cls_logger:
+ cls._cls_logger = logging.getLogger('.'.join([__name__,
cls.__name__]))
+ return cls._cls_logger
diff --git a/modules/check_mk.py b/modules/check_mk.py
index 6265a42..138f91d 100755
--- a/modules/check_mk.py
+++ b/modules/check_mk.py
@@ -48,9 +48,11 @@ import inspect
from cmk.regex import regex, is_regex
from cmk.exceptions import MKGeneralException, MKTerminate
import cmk.debug
+import cmk.log
import cmk.tty as tty
import cmk.store as store
import cmk.paths
+import cmk.render as render
import cmk.man_pages as man_pages
# .--Prelude-------------------------------------------------------------.
@@ -74,14 +76,21 @@ if '--debug' in sys.argv[1:]:
cmk.debug.enable()
opt_interactive = '--interactive' in sys.argv[1:]
-opt_verbose = ('-v' in sys.argv[1:] or '--verbose' in sys.argv[1:])
and 1 or 0
+
+opt_verbose = 0 # TODO: Remove this once opt_verbose is gone
+
+cmk.log.setup_console_logging()
+logger = cmk.log.get_logger("base")
+
+# TODO: This is not really good parsing, because it not cares about syntax like e.g.
"-nv".
+# The later regular argument parsing is handling this correctly. Try to clean this
up.
+cmk.log.set_verbosity(verbosity=len([ a for a in sys.argv if a in [ "-v",
"--verbose"] ]))
if '--profile' in sys.argv[1:]:
import cProfile
g_profile = cProfile.Profile()
g_profile.enable()
- if opt_verbose:
- sys.stderr.write("Enabled profiling.\n")
+ logger.verbose("Enabled profiling.")
#.
@@ -4654,16 +4663,17 @@ done = False
seen_I = 0
check_types = None
exit_status = 0
-opt_verbose = 0 # start again from 0, was already faked at the beginning
opt_inv_hw_changes = 0
opt_inv_sw_changes = 0
opt_inv_sw_missing = 0
opt_inv_fail_status = 1 # State in case of an error (default: WARN)
+_verbosity = 0
# Scan modifying options first (makes use independent of option order)
for o,a in opts:
+ # -v/--verbose is handled above manually. Simply ignore it here.
if o in [ '-v', '--verbose' ]:
- opt_verbose += 1
+ _verbosity += 1
elif o in [ '-f', '--force' ]:
opt_force = True
elif o == '-c':
@@ -4720,6 +4730,8 @@ for o,a in opts:
elif o == "--log-to-stdout":
opt_log_to_stdout = True
+cmk.log.set_verbosity(verbosity=_verbosity)
+
# Perform actions (major modes)
try:
for o, a in opts:
diff --git a/tests/lib/test_log.py b/tests/lib/test_log.py
new file mode 100644
index 0000000..aa05d24
--- /dev/null
+++ b/tests/lib/test_log.py
@@ -0,0 +1,47 @@
+import pytest
+import cmk.log
+
+def test_get_logger():
+ l = cmk.log.get_logger("asd")
+ assert l.name == "cmk.asd"
+ assert l.parent == cmk.log.logger
+
+ l = cmk.log.get_logger("asd.aaa")
+ assert l.name == "cmk.asd.aaa"
+
+
+def test_setup_console_logging(capsys):
+ out, err = capsys.readouterr()
+ assert out == ""
+ assert err == ""
+
+ cmk.log.get_logger("test").info("test123")
+
+ out, err = capsys.readouterr()
+ assert out == ""
+ assert err == ""
+
+ cmk.log.setup_console_logging()
+ l = cmk.log.get_logger("test")
+ l.info("test123")
+
+ out, err = capsys.readouterr()
+ assert out == "test123\n"
+ assert err == ""
+
+
+def test_set_verbosity():
+ l = cmk.log.get_logger("test_logger")
+ assert l.getEffectiveLevel() == cmk.log.INFO
+
+ cmk.log.set_verbosity(0)
+ assert l.getEffectiveLevel() == cmk.log.INFO
+
+ cmk.log.set_verbosity(1)
+ assert l.getEffectiveLevel() == cmk.log.VERBOSE
+
+ cmk.log.set_verbosity(2)
+ assert l.getEffectiveLevel() == cmk.log.DEBUG
+
+ with pytest.raises(NotImplementedError):
+ cmk.log.set_verbosity(3)