How can I redirect the output to the boost log?

I have a C ++ program that uses a boost log and I load a user-provided dynamic link library. I would like to redirect stderr to boost log, so anytime the user library does:

std::cerr << "Some stuff"; 

It produces the same result ** as:

 BOOST_LOG_SEV(log,info) << "Some stuff"; 

Is this possible, and if so, how to do it?

(Also, I'm not sure what to do with severity ... since cerr << does not transmit severity information. I am also open to suggestions about this ...)

** By "same result" I mean that it is logged in the same log file as the rest of the log messages, and the same log format applies to these lines.

+2
source share
2 answers

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) { } }; 
+2
source

I assume you can redirect the File descriptor STDERR to the file descriptor of the stream [you should get the desc file of your stream] using dup/dup2 api [its a posix api]

-2
source

All Articles