如何将输出重定向到boost日志? 我有一个使用Boost日志的C++程序,我加载了一个用户提供的动态链接库。我想将stderr重定向到boost日志,以便在用户的库执行以下操作时: std::cerr << "Some stuff"; std::cerr

如何将输出重定向到boost日志? 我有一个使用Boost日志的C++程序,我加载了一个用户提供的动态链接库。我想将stderr重定向到boost日志,以便在用户的库执行以下操作时: std::cerr << "Some stuff"; std::cerr,c++,redirect,boost,stderr,boost-log,C++,Redirect,Boost,Stderr,Boost Log,我猜,您可以使用dup/dup2api[它是一个POSIXAPI]将文件描述符STDERR重定向到流文件描述符[您必须获得流的文件描述]。这个类可以用于任何事情(不仅仅是boost)来逐行捕获stdout/stderr,并调用用户函数(可以是lambda)来处理它 警告:如果重定向stderr和stdout并且正在使用Boost,则首先重定向stderr,然后重定向stdout。否则,Boost将把stderr消息写回stdout,您将在另一个Boost日志条目中得到一个Boost日志条目 用法

我猜,您可以使用
dup/dup2
api[它是一个POSIXAPI]

文件描述符STDERR
重定向到流文件描述符[您必须获得流的文件描述]。这个类可以用于任何事情(不仅仅是boost)来逐行捕获stdout/stderr,并调用用户函数(可以是lambda)来处理它

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

用法示例 代码
#包括
#包括
#包括
#包括
#包括
#包括
类StdioHandler
{
私人:
pid_t pid=0;
int origfd;
int流线型;
int-pipefd[2];
公众:
枚举类流
{
stdout=stdout\u文件号,
stderr=stderr\u文件号
};
StdioHandler(流,std::函数回调)
:streamid(静态_转换(流))
{
origfd=dup(流线ID);
管道(pipefd);//创建管道
pid=fork();//生成一个子进程来处理管道的输出
如果(pid==0)
{
字符行[256];
文件*输出;
关闭(pipefd[1]);
输出=fdopen(pipefd[0],“r”);
如果(输出)
{
while(fgets(行、sizeof(行)、输出))
{
int n=strlen(直线);
如果(n>0)
如果(第[n-1]行='\n')第[n-1]行=0;
回调(行);
}
fclose(输出);
}
中止();
}否则{
//将管道的输入连接到
关闭(pipefd[0]);
dup2(pipefd[1],流线型);
}
}
~StdioHandler()
{
智力状态;
美国LEEP(10000);
关闭(pipefd[1]);
kill(pid,SIGINT);
waitpid(pid和status,0);
dup2(origfd,流线型);
}
};
类StdOutHandler:公共StdioHandler
{
公众:
StdOutHandler(std::函数回调):
StdioHandler(流::stdout,回调)
{
}
};
类StdErrHandler:公共StdioHandler
{
公众:
StdErrHandler(std::函数回调):
StdioHandler(流::stderr,回调)
{
}
};

AFAIK,没有记录在案的方法来获取boost日志接收器的底层文件描述符。我不知道这是否可能(使用一些未记录的方法)。此外,这实际上会绕过日志机制,而不是通过它(例如,绕过所有过滤、格式化等)。请注意,Boost.Log显式地不支持进程分叉。如果子进程与父进程同时写入日志,这可能会导致日志损坏,这似乎无法防止。
BOOST_LOG_SEV(log,info) << "Some stuff";
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)
    {
    }
};