3

我有一个使用 boost 日志的 C++ 程序,并且我加载了一个用户提供的动态链接库。我想将 stderr 重定向到 boost 日志,以便用户的库可以随时执行以下操作:

std::cerr << "Some stuff";

它产生与以下相同的结果**:

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

这是可能的,如果是这样,我该怎么做?

(另外,我不确定如何处理严重性......因为cerr <<不提供严重性信息。我也愿意接受有关这方面的建议......)

** “相同的结果”是指它被记录到与其余日志消息相同的日志文件中,并且相同的日志格式化程序应用于这些行。

4

2 回答 2

3

这是我的 C++11 实现。此类可用于任何事情(不仅仅是提升)以逐行捕获 stdout/stderr 并调用用户函数(可能是 lambda)来处理它。

警告:如果您重定向stderr并且stdout正在使用 Boost,则stderr首先重定向,然后stdout. 否则,Boost 会将 stderr 消息回送回 stdout,并且您将在另一个 boost 日志条目中获得一个 boost 日志条目。

使用示例

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;

示例输出

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

代码

#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)
    {
    }
};
于 2014-08-01T19:32:19.080 回答
-2

我猜,您可以使用api [它是一个 posix api]重定向File descriptor STDERR到您的流文件描述符 [您必须获取流的文件描述]dup/dup2

于 2013-07-29T05:55:53.340 回答