如何从库标准错误中读取?

时间:2012-02-08 07:48:17

标签: c++ qt logging stderr

我有一个使用C ++库的Qt / C ++应用程序。

此库具有将字符串消息写入标准错误的日志机制。

现在,我希望能够将这些消息重定向到我的Qt工具中的面板。 我想避免修改库,因为许多其他客户端都采用了它。 知道如何在运行时获取这些消息吗?

相反,改变它的可能性将这些消息传递给应用程序可能是一个好的做法?

4 个答案:

答案 0 :(得分:4)

这是非常糟糕的图书馆设计。然而...

它如何写入标准错误。如果输出到std::cerr, 然后,您可以更改streambuf使用的std::cerr,例如:

std::filebuf logStream;
if ( ~logStream.open( "logfile.txt" ) )
    //  Error handling...
std::streambuf* originalCErrStream = std::cerr.rdbuf();
std::cerr.rdbuf( &logStream );
//  Processing here, with calls to library
std::cerr.rdbuf( originalCErrStream );  //  Using RAII would be better.

不要忘记恢复原始的streambuf;离开std::cerr 指向已被破坏的filebuf 是一个好主意。

如果他们使用的是FILE*,那么C中就会有一个freopen函数 你可以使用包含在C ++中)。

如果他们在Unix下使用系统级输出(writeWriteFile 在Windows下,那么你将不得不使用一些系统级代码 改变输出。 (open在新文件上,close在fd上 STDERR_FILENOdup2设置STDERR_FILENO以使用新版本 在Unix下打开文件。我不确定它是否可能 Windows - 可能是ReOpenFile或某种组合的东西 CloseHandle后跟CreateFile。)

编辑:

我刚注意到你实际上想要输出到Qt窗口。这个 意味着你可能需要一个字符串,而不是一个文件。如果 库正在使用std::cerr,您可以使用std::stringbuf而不是std::filebuf 一个sync;事实上,你可能想要创建自己的streambuf, 接听<<的呼叫(通常在每次呼叫后调用) std::cerr上的read()。如果库使用其他技术之一, 我唯一能想到的是定期读取文件,看看 如果有任何添加的话。 (我会在Unix中使用ReadFile()FILE* 在Windows中为此,以确保能够区分 读取零字节,因为自上次以来没有写入任何内容 读取和错误条件。 {{1}}和iostream函数处理一个 读取零字节作为文件结尾,不再读取。)

答案 1 :(得分:2)

写入stderr实际上是一个系统调用:

write(2, "blahblah ...");

您可以将文件描述符编号2重定向到任何内容(文件,管道,套接字):

close(2);                        // close old stderr
int redirect_target = open(...); // open a file where you want to redirect to
                                 // or use pipe, socket whatever you like
dup2(redirect_target, 2);        // copy the redirect_target fd to fd number 2
close(redirect_target);

在你的情况下,你需要一个烟斗。

close(2);
int pipefd[2];
pipe2(pipefd);
dup2(pipefd[1], 2);
close(pipefd[1]);

然后,可以通过读取pipe [0]来获取写入stderr的所有内容:

read(pipe[0], buffer, ...);

答案 2 :(得分:1)

如果他们正在使用std::cerr来电,您可以将其重定向到std::ostringstream

#include <iostream>
#include <sstream>

class cerr_redirector
{
public:
    cerr_redirector(std::ostream& os)
        :backup_(std::cerr.rdbuf())
         ,sbuf_(os.rdbuf())
    {
        std::cerr.rdbuf(sbuf_);
    }

    ~cerr_redirector()
    {
        std::cerr.rdbuf(backup_);
    }

private:
    cerr_redirector();
    cerr_redirector(const cerr_redirector& copy);
    cerr_redirector& operator =(const cerr_redirector& assign);

    std::streambuf* backup_;
    std::streambuf* sbuf_;
};

您可以使用以下方式捕获输出:

std::ostringstream os;
cerr_redirector red(os);
std::cerr << "This is written to the stream" << std::endl;

std::cout将不受影响:

std::cout << "This is written to stdout" << std::endl;

因此,您可以测试您的捕获是否有效:

std::cout << "and now: " << os.str() << std::endl;

或者只是将os.str()的内容添加到您的Qt窗口。

Demonstration at ideone

答案 3 :(得分:0)

在这里,我找到了我需要的完整实现... 感谢大家的帮助! :)

Will loading a DLL dynamically reconcile its stderr to a main application? If so, then how...?