Как читать из библиотеки стандартную ошибку? - PullRequest
2 голосов
/ 08 февраля 2012

У меня есть приложение Qt / C ++, использующее библиотеку C ++.

В этой библиотеке есть механизм журнала, который записывает строковые сообщения в стандартную ошибку.

Теперь я бы хотел бытьвозможность перенаправлять эти сообщения на панель в моем инструменте Qt.Я хотел бы избежать модификации библиотеки, потому что принят многими другими клиентами.Любая идея, как получить во время выполнения эти сообщения?

Имея вместо этого возможность изменить его, что может быть хорошей практикой для передачи этих сообщений в приложение?

Ответы [ 4 ]

4 голосов
/ 08 февраля 2012

Это очень плохой дизайн библиотеки. Однако ...

Как записать в стандартную ошибку. Если это вывод на 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*, есть функция freopen в C (и включение в C ++), что вы можете использовать.

Если они используют вывод системного уровня (write под Unix, WriteFile под Windows), тогда вам придется использовать некоторый код системного уровня изменить выход. (open в новом файле, close в fd STDERR_FILENO и dup2 для установки STDERR_FILENO для использования недавно открыл файл под Unix. Я не уверен, что это возможно под Windows - может быть что-то с ReOpenFile или какой-то комбинацией CloseHandle, а затем CreateFile.)

EDIT:

Я только что заметил, что вы действительно хотите выводить в окно Qt. это означает, что вам, вероятно, нужна строка, а не файл. Если библиотека использует std::cerr, вы можете использовать std::stringbuf вместо а std::filebuf; на самом деле вы можете захотеть создать свой собственный потоковый буфер, принимать звонки на номер sync (который обычно вызывается после каждого << на std::cerr). Если библиотека использует один из других методов, Единственное, о чем я могу думать, это периодически читать файл, чтобы увидеть если что-нибудь было добавлено. (Я бы использовал read() в Unix, ReadFile() в Windows для этого, чтобы быть в состоянии отличить чтение нулевых байтов, поскольку ничего не было записано с момента последнего прочитайте, и состояние ошибки. FILE* и функции iostream обрабатывают читать ноль байтов как конец файла и не будет читать дальше.)

2 голосов
/ 08 февраля 2012

запись в 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]);

тогда все, что записать в stderr, можно получить, прочитав pipe [0]:

read(pipe[0], buffer, ...);
1 голос
/ 08 февраля 2012

Если они используют вызовы на 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.

Демонстрация на ideone .

0 голосов
/ 09 февраля 2012

Здесь я нашел полную реализацию того, что мне было нужно ...

Спасибо всем за помощь!:)

Будет ли загрузка DLL динамически согласовывать ее stderr с основным приложением?Если так, то как ...?

...