From bd3e2904e7ac401df73a617948e2ef0c6b0a0fa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Mon, 18 Sep 2017 06:30:27 +0300 Subject: [PATCH] MXS-1405: Log subprocess output according to log level If the executed subprocess prefixes its output with either `error:`, `warning:` or `info:`, the message will be logged on the appropriate level. If no prefix is provided, the message is logged on the notice level. --- Documentation/Monitors/Monitor-Common.md | 11 ++++ .../MaxScale-2.2.0-Release-Notes.md | 5 ++ server/core/externcmd.cc | 60 ++++++++++++++++++- 3 files changed, 74 insertions(+), 2 deletions(-) diff --git a/Documentation/Monitors/Monitor-Common.md b/Documentation/Monitors/Monitor-Common.md index ecdb624fb..6ec363c00 100644 --- a/Documentation/Monitors/Monitor-Common.md +++ b/Documentation/Monitors/Monitor-Common.md @@ -87,6 +87,17 @@ For example, the previous example will be executed as: /home/user/myscript.sh initiator=[192.168.0.10]:3306 event=master_down live_nodes=[192.168.0.201]:3306,[192.168.0.121]:3306 ``` +Any output by the executed script will be logged into the MaxScale log. Each +outputted line will be logged as a separate log message. + +The log level on which the messages are logged depends on the format of the +messages. If the first word in the output line is one of `alert:`, `error:`, +`warning:`, `notice:`, `info:` or `debug:`, the message will be logged on the +corresponding level. If the message is not prefixed with one of the keywords, +the message will be logged on the notice level. Whitespace before, after or +inbetween the keyword and the colon is ignored and the matching is +case-insensitive. + ### `script_timeout` The timeout for the executed script in seconds. The default value is 90 diff --git a/Documentation/Release-Notes/MaxScale-2.2.0-Release-Notes.md b/Documentation/Release-Notes/MaxScale-2.2.0-Release-Notes.md index d8494d79c..563a66556 100644 --- a/Documentation/Release-Notes/MaxScale-2.2.0-Release-Notes.md +++ b/Documentation/Release-Notes/MaxScale-2.2.0-Release-Notes.md @@ -24,6 +24,11 @@ that a monitor will wait until the executed script is done or until a timeout is exceeded. The timeout is configurable with the `script_timeout` parameter. +In addition to this, the output of the script is logged into the MaxScale log +file. The message is logged on the matching log level if it is prefixed with one +of `alert:`, `error:`, `warning:`, `notice:`, `info:` or `debug:`. If no prefix +is provided, the message is logged on the notice level. + For more information, refer to the [monitor documentation](../Monitors/Monitor-Common.md). ### Read-only Administrative Users diff --git a/server/core/externcmd.cc b/server/core/externcmd.cc index 27e92407f..22cfe791c 100644 --- a/server/core/externcmd.cc +++ b/server/core/externcmd.cc @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -159,6 +160,61 @@ void externcmd_free(EXTERNCMD* cmd) } } +static const char* skip_whitespace(const char* ptr) +{ + while (*ptr && isspace(*ptr)) + { + ptr++; + } + + return ptr; +} + +static const char* skip_prefix(const char* str) +{ + const char* ptr = strchr(str, ':'); + ss_dassert(ptr); + + ptr++; + return skip_whitespace(ptr); +} + +static void log_output(const char* cmd, const std::string& str) +{ + int err; + + if (mxs_pcre2_simple_match("(?i)^[[:space:]]*alert[[:space:]]*[:]", + str.c_str(), 0, &err) == MXS_PCRE2_MATCH) + { + MXS_ALERT("%s: %s", cmd, skip_prefix(str.c_str())); + } + else if (mxs_pcre2_simple_match("(?i)^[[:space:]]*error[[:space:]]*[:]", + str.c_str(), 0, &err) == MXS_PCRE2_MATCH) + { + MXS_ERROR("%s: %s", cmd, skip_prefix(str.c_str())); + } + else if (mxs_pcre2_simple_match("(?i)^[[:space:]]*warning[[:space:]]*[:]", + str.c_str(), 0, &err) == MXS_PCRE2_MATCH) + { + MXS_WARNING("%s: %s", cmd, skip_prefix(str.c_str())); + } + else if (mxs_pcre2_simple_match("(?i)^[[:space:]]*notice[[:space:]]*[:]", + str.c_str(), 0, &err) == MXS_PCRE2_MATCH) + { + MXS_NOTICE("%s: %s", cmd, skip_prefix(str.c_str())); + } + else if (mxs_pcre2_simple_match("(?i)^[[:space:]]*(info|debug)[[:space:]]*[:]", + str.c_str(), 0, &err) == MXS_PCRE2_MATCH) + { + MXS_INFO("%s: %s", cmd, skip_prefix(str.c_str())); + } + else + { + // No special format, log as notice level message + MXS_NOTICE("%s: %s", cmd, skip_whitespace(str.c_str())); + } +} + int externcmd_execute(EXTERNCMD* cmd) { // Create a pipe where the command can print output @@ -290,7 +346,7 @@ int externcmd_execute(EXTERNCMD* cmd) { std::string line = output.substr(0, pos); output.erase(0, pos + 1); - MXS_NOTICE("%s", line.c_str()); + log_output(cmd->argv[0], line); } } } @@ -298,7 +354,7 @@ int externcmd_execute(EXTERNCMD* cmd) if (!output.empty()) { - MXS_NOTICE("%s", output.c_str()); + log_output(cmd->argv[0], output); } // Close the read end of the pipe and copy the data to the output parameter