MXS-1405: Log subprocess output immediately

When the subprocess outputs a line, the message should be logged
immediately. This allows automated timestamps for the output of the
executed subprocess.
This commit is contained in:
Markus Mäkelä
2017-09-15 10:03:46 +03:00
parent 7e6e8d3e29
commit 130b686d9b
3 changed files with 31 additions and 27 deletions

View File

@ -159,11 +159,8 @@ void externcmd_free(EXTERNCMD* cmd)
} }
} }
int externcmd_execute(EXTERNCMD* cmd, char** dest) int externcmd_execute(EXTERNCMD* cmd)
{ {
// Always set dest to NULL before starting
*dest = NULL;
// Create a pipe where the command can print output // Create a pipe where the command can print output
int fd[2]; int fd[2];
@ -173,10 +170,6 @@ int externcmd_execute(EXTERNCMD* cmd, char** dest)
return -1; return -1;
} }
// Make them non-blocking
fcntl(fd[0], F_SETFL, O_NONBLOCK);
fcntl(fd[1], F_SETFL, O_NONBLOCK);
int rval = 0; int rval = 0;
pid_t pid; pid_t pid;
@ -219,8 +212,9 @@ int externcmd_execute(EXTERNCMD* cmd, char** dest)
uint64_t t = 0; uint64_t t = 0;
uint64_t t_max = cmd->timeout * 1000; uint64_t t_max = cmd->timeout * 1000;
// Close the write end of the pipe // Close the write end of the pipe and make the read end non-blocking
close(fd[1]); close(fd[1]);
fcntl(fd[0], F_SETFL, O_NONBLOCK);
while (again) while (again)
{ {
@ -284,12 +278,31 @@ int externcmd_execute(EXTERNCMD* cmd, char** dest)
{ {
// Read all available output // Read all available output
output.append(buf, n); output.append(buf, n);
for (size_t pos = output.find("\n");
pos != std::string::npos; pos = output.find("\n"))
{
if (pos == 0)
{
output.erase(0, 1);
}
else
{
std::string line = output.substr(0, pos);
output.erase(0, pos + 1);
MXS_NOTICE("%s", line.c_str());
}
}
} }
} }
if (!output.empty())
{
MXS_NOTICE("%s", output.c_str());
}
// Close the read end of the pipe and copy the data to the output parameter // Close the read end of the pipe and copy the data to the output parameter
close(fd[0]); close(fd[0]);
*dest = MXS_STRDUP_A(output.c_str());
} }
return rval; return rval;

View File

@ -58,11 +58,10 @@ void externcmd_free(EXTERNCMD* cmd);
* The output of the command must be freed by the caller by calling MXS_FREE. * The output of the command must be freed by the caller by calling MXS_FREE.
* *
* @param cmd Command to execute * @param cmd Command to execute
* @param dest Pointer where to store the output of the command
* *
* @return The return value of the executed command or -1 on error * @return The return value of the executed command or -1 on error
*/ */
int externcmd_execute(EXTERNCMD* cmd, char** dest); int externcmd_execute(EXTERNCMD* cmd);
/** /**
* Substitute all occurrences of @c match with @c replace in the arguments for @c cmd * Substitute all occurrences of @c match with @c replace in the arguments for @c cmd

View File

@ -1209,29 +1209,21 @@ monitor_launch_script(MXS_MONITOR* mon, MXS_MONITOR_SERVERS* ptr, const char* sc
externcmd_substitute_arg(cmd, "[$]SYNCEDLIST", nodelist); externcmd_substitute_arg(cmd, "[$]SYNCEDLIST", nodelist);
} }
char* out = NULL; int rv = externcmd_execute(cmd);
std::string str;
int rv = externcmd_execute(cmd, &out);
if (out)
{
str = trim(out);
MXS_FREE(out);
}
if (rv) if (rv)
{ {
if (rv == -1) if (rv == -1)
{ {
// Internal error // Internal error
MXS_ERROR("Failed to execute script '%s' on server state change event '%s': %s", MXS_ERROR("Failed to execute script '%s' on server state change event '%s'",
script, mon_get_event_name(ptr), str.c_str()); script, mon_get_event_name(ptr));
} }
else else
{ {
// Script returned a non-zero value // Script returned a non-zero value
MXS_ERROR("Script '%s' returned %d on event '%s': %s", MXS_ERROR("Script '%s' returned %d on event '%s'",
script, rv, mon_get_event_name(ptr), str.c_str()); script, rv, mon_get_event_name(ptr));
} }
} }
else else
@ -1273,8 +1265,8 @@ monitor_launch_script(MXS_MONITOR* mon, MXS_MONITOR_SERVERS* ptr, const char* sc
scriptStr = cmd->argv[0]; // print at least something scriptStr = cmd->argv[0]; // print at least something
} }
MXS_NOTICE("Executed monitor script '%s' on event '%s': %s", MXS_NOTICE("Executed monitor script '%s' on event '%s'",
scriptStr, mon_get_event_name(ptr), str.c_str()); scriptStr, mon_get_event_name(ptr));
if (!memError) if (!memError)
{ {