【问题标题】:How can I redirect output to a boost log?如何将输出重定向到提升日志?
【发布时间】:2013-07-29 03:07:10
【问题描述】:

我有一个使用 boost 日志的 C++ 程序,并且我加载了一个用户提供的动态链接库。我想将 stderr 重定向到 boost 日志,以便用户的库在任何时候这样做:

std::cerr << "Some stuff";

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

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

这可能吗?如果可以,我该怎么做?

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

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

【问题讨论】:

    标签: c++ redirect boost stderr boost-log


    【解决方案1】:

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

    警告:如果您重定向 stderrstdout 并且正在使用 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)
        {
        }
    };
    

    【讨论】:

    • 请注意,Boost.Log 明确不支持进程分叉。如果子进程碰巧与父进程同时写入日志,这可能会导致日志损坏,这似乎无法防止。
    【解决方案2】:

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

    【讨论】:

    • AFAIK,没有记录的方法来获取提升日志接收器的底层文件描述符。我不知道它是否可能(使用一些未记录的方法)。此外,这实际上会绕过日志机制而不是通过它(例如,绕过所有过滤、格式化等)
    猜你喜欢
    • 1970-01-01
    • 2016-10-07
    • 2019-08-21
    • 2012-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-10
    • 2014-08-10
    相关资源
    最近更新 更多