Here is my C ++ 11 implementation. This class can be used for anything (and not just for raising) to capture stdout / stderr in turn and call a user-defined function (maybe a lambda) to process it.
Warning: if you redirect stderr and stdout and use Boost, redirect stderr first, then stdout . Otherwise, Boost will write the loopback message stderr back to stdout, and you will get a boost log entry in another alarm entry.
Usage example
cout << "testing out before 1 2 3 " << endl; cerr << "testing err before 1 2 3 " << endl; { StdErrHandler err([](const char* line){ BOOST_LOG_TRIVIAL(error) << "ERROR:" << strlen(line) << " " << line; }); StdOutHandler out([](const char* line){ BOOST_LOG_TRIVIAL(info) << "OUT:" << strlen(line) << " " << line; }); cout << "cout testing 1 2 3 " << endl; cerr << "cerr testing 1 2 3 " << endl; } cout << "testing out after 1 2 3 " << endl; cerr << "testing err after 1 2 3 " << endl;
Output example
pa-poca$ ./test testing out before 1 2 3 testing err before 1 2 3 [2014-08-01 12:24:56.468335] [0x000007f89d8990d4] [error] ERROR:19 cerr testing 1 2 3 [2014-08-01 12:24:56.468360] [0x000007f89d8990d4] [info] OUT:19 cout testing 1 2 3 testing out after 1 2 3 testing err after 1 2 3
Code
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <string.h> #include <signal.h> #include <sys/wait.h> class StdioHandler { private: pid_t pid = 0; int origfd; int streamid; int pipefd[2]; public: enum class Stream { stdout = STDOUT_FILENO, stderr = STDERR_FILENO }; StdioHandler(Stream stream, std::function<void(const char*)> callback) :streamid(static_cast<int>(stream)) { origfd = dup(streamid); pipe(pipefd); // create pipe pid = fork(); //spawn a child process to handle output of pipe if (pid == 0) { char line[256]; FILE* output; close(pipefd[1]); output = fdopen(pipefd[0], "r"); if (output) { while(fgets(line, sizeof(line), output)) { int n = strlen(line); if (n > 0) if (line[n-1] == '\n') line[n-1] = 0; callback(line); } fclose(output); } abort(); } else { // connect input of pipe to close(pipefd[0]); dup2(pipefd[1], streamid); } } ~StdioHandler() { int status; usleep(10000); close(pipefd[1]); kill(pid,SIGINT); waitpid(pid, &status, 0); dup2(origfd, streamid); } }; class StdOutHandler : public StdioHandler { public: StdOutHandler(std::function<void(const char*)> callback) : StdioHandler(Stream::stdout, callback) { } }; class StdErrHandler : public StdioHandler { public: StdErrHandler(std::function<void(const char*)> callback) : StdioHandler(Stream::stderr, callback) { } };
source share