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)
Module: check_mk
Branch: master
Commit: 32658ebc3b244dbab8c00dec68f7dbb21bfbb72f
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=32658ebc3b244d…
Author: Andreas Boesl <ab(a)mathias-kettner.de>
Date: Fri Oct 14 12:08:55 2016 +0200
3821 FIX WATO Network Scan: Fixed risk of loosing site tags when performing a network scan
A network scan on a folder could cause the loss of any site tags configured in this
folder. As a result, these hosts were monitored multiple times on different sites,
when a distributed WATO setup was used.
---
.werks/3821 | 14 ++++++++++++++
ChangeLog | 1 +
web/htdocs/wato.py | 2 ++
3 files changed, 17 insertions(+)
diff --git a/.werks/3821 b/.werks/3821
new file mode 100644
index 0000000..2509a56
--- /dev/null
+++ b/.werks/3821
@@ -0,0 +1,14 @@
+Title: WATO Network Scan: Fixed risk of loosing site tags when performing a network scan
+Level: 1
+Component: wato
+Compatible: compat
+Version: 1.4.0i2
+Date: 1476439400
+Class: fix
+
+A network scan on a folder could cause the loss of any site tags configured in this
+folder. As a result, these hosts were monitored multiple times on different sites,
+when a distributed WATO setup was used.
+
+Developer note: This only happened when a "fresh" apache process handled this request.
+Any hosttags and site defines were missing..
diff --git a/ChangeLog b/ChangeLog
index ebf4add..65ed130 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -31,6 +31,7 @@
* 3901 Logfile pattern analyser: pattern lists can now be searched
* 3914 FIX: Roles: Aliases are now unique during cloning
* 3820 FIX: Network scan: no longer fails completely if hostname already exists in configuration...
+ * 3821 FIX: WATO Network Scan: Fixed risk of loosing site tags when performing a network scan...
Notifications:
* 3957 mail: now allows extra HTML section between body and table
diff --git a/web/htdocs/wato.py b/web/htdocs/wato.py
index 5ad73ab..7174435 100644
--- a/web/htdocs/wato.py
+++ b/web/htdocs/wato.py
@@ -15854,6 +15854,8 @@ def read_agent_contents_file(root):
# master site. Finds the next folder to scan and starts it via WATO
# automation. The result is written to the folder in the master site.
def execute_network_scan_job():
+ init_wato_datastructures()
+
if is_wato_slave_site():
return # Don't execute this job on slaves.
Module: check_mk
Branch: master
Commit: 5c8db5ff922fee35345c12efa7ed57fc60afdc04
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=5c8db5ff922fee…
Author: Simon Betz <si(a)mathias-kettner.de>
Date: Fri Oct 14 11:34:23 2016 +0200
updated werk
---
.werks/3611 | 2 +-
ChangeLog | 4 +--
checks/websphere_mq_queues | 49 ++++++++++++++++++++++--------------
web/plugins/wato/check_parameters.py | 40 +++++++++++++++++++++++------
4 files changed, 66 insertions(+), 29 deletions(-)
diff --git a/.werks/3611 b/.werks/3611
index 64d9c89..0461c00 100644
--- a/.werks/3611
+++ b/.werks/3611
@@ -1,4 +1,4 @@
-Title: websphere_mq_queues: now age of messages not processed is configurable
+Title: websphere_mq_queues: now age and state of messages not processed is configurable
Level: 1
Component: checks
Compatible: compat
diff --git a/ChangeLog b/ChangeLog
index 77fd5cb..ebf4add 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -149,8 +149,8 @@
* 3609 apc_rackpdu_power: now upper levels for electrical current are confiugurable
* 3136 windows agent: improved crash reporting...
* 3137 linux and solaris agent: mrpe checks now support option to append the cache age to cached results...
- * 3610 mk_oracle: linux plugin now available for solaris...
- * 3611 websphere_mq_queues: now age of messages not processed is configurable...
+ * 3610 mk_oracle: linux plugin now available for solaris
+ * 3611 websphere_mq_queues: now age and state of messages not processed is configurable...
* 3612 nfsmounts: new rule for en/disabling performance data
* 3615 if: Convert bandwidth from octets into bits for graph display...
NOTE: Please refer to the migration notes!
diff --git a/checks/websphere_mq_queues b/checks/websphere_mq_queues
index 811445f..71ba46b 100644
--- a/checks/websphere_mq_queues
+++ b/checks/websphere_mq_queues
@@ -74,7 +74,7 @@ def parse_websphere_mq_queues(info):
parsed[queue_name].setdefault('max_depth', int(line[2]))
if len(line) > 3:
- for what in line[3].split(')'):
+ for what in "".join(line[3:-1]).replace(" ", "").split(')'):
if "(" in what:
key, val = what.split('(')
parsed[queue_name].setdefault(key, val)
@@ -141,29 +141,40 @@ def check_websphere_mq_queues(item, params, parsed):
yield state_perc, info_perc
- if data.get("time_on_client") and data.get("LGETDATE") and \
- data.get("LGETTIME"):
+ if data.get("time_on_client") and \
+ "LGETDATE" in data and "LGETTIME" in data:
- time_str = "%s %s" % (data['LGETDATE'], data['LGETTIME'])
- time_diff = data["time_on_client"] - \
- time.mktime(time.strptime(time_str, "%Y-%m-%d %H.%M.%S"))
- state_diff = 0
- info_diff = "since %s" % get_age_human_readable(time_diff)
+ params = params.get("messages_not_processed", {})
- if 'messages_not_processed_age' in params:
- warn_diff, crit_diff = params['messages_not_processed_age']
+ if cur_depth and data["LGETDATE"] and data["LGETTIME"]:
+ time_str = "%s %s" % (data['LGETDATE'], data['LGETTIME'])
+ time_diff = data["time_on_client"] - \
+ time.mktime(time.strptime(time_str, "%Y-%m-%d %H.%M.%S"))
+ state_diff = 0
+ info_diff = "Messages not processed since %s" % get_age_human_readable(time_diff)
- if time_diff >= crit_diff:
- state_diff = 2
- elif time_diff >= warn_diff:
- state_diff = 1
+ if 'age' in params:
+ warn_diff, crit_diff = params['age']
- if state_diff:
- info_diff += " (warn/crit at %s/%s)" % \
- (get_age_human_readable(warn_diff),
- get_age_human_readable(crit_diff))
+ if time_diff >= crit_diff:
+ state_diff = 2
+ elif time_diff >= warn_diff:
+ state_diff = 1
+
+ if state_diff:
+ info_diff += " (warn/crit at %s/%s)" % \
+ (get_age_human_readable(warn_diff),
+ get_age_human_readable(crit_diff))
+
+ yield state_diff, info_diff
+
+ elif cur_depth:
+ yield params.get("state", 0), "No age of %d message%s not processed" % \
+ (cur_depth, cur_depth > 1 and "s" or "")
+
+ else:
+ yield 0, "Messages processed"
- yield state_diff, info_diff
check_info["websphere_mq_queues"] = {
diff --git a/web/plugins/wato/check_parameters.py b/web/plugins/wato/check_parameters.py
index 8aa8c29..21254f0 100644
--- a/web/plugins/wato/check_parameters.py
+++ b/web/plugins/wato/check_parameters.py
@@ -1507,6 +1507,14 @@ register_check_parameters(
def transform_websphere_mq(source):
if isinstance(source, tuple):
return {"message_count": source}
+
+ elif "messages_not_processed_age" in source:
+ age_params = source["messages_not_processed_age"]
+ source["messages_not_processed"] = {}
+ source["messages_not_processed"]["age"] = age_params
+ del source["messages_not_processed_age"]
+ return source
+
else:
return source
@@ -1570,14 +1578,32 @@ register_check_parameters(
],
optional_keys = []
)),
- ("messages_not_processed_age",
- Tuple(
- title = _("Time settings for messages not processed"),
+ ("messages_not_processed",
+ Dictionary(
+ title = _("Settings for messages not processed"),
+ help = _("With this rule you can determine the warn and crit age "
+ "if LGETTIME and LGETDATE is available in the agent data. "
+ "Note that if LGETTIME and LGETDATE are available but not set "
+ "you can set the service state which is default WARN. "
+ "This rule applies only if the current depth is greater than zero."),
elements = [
- Age(title = _("Warning at")),
- Age(title = _("Critical at")),
- ],
- )),
+ ("age",
+ Tuple(
+ title = _("Upper levels for the age"),
+ elements = [
+ Age(title = _("Warning at")),
+ Age(title = _("Critical at")),
+ ],
+ )
+ ),
+ ("state",
+ MonitoringState(
+ title = _("State if LGETTIME and LGETDATE are available but not set"),
+ default_value = 1)
+ ),
+ ]
+ ),
+ ),
],
),
forth = transform_websphere_mq