Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Read stderr output from own process



  • Hi there,

    currently i'm writing a gui application which uses the external c library "libssh":http://www.libssh.org . This library prints log messages (of adjustable verbosity) on stderr. I would like display them "live" in my gui. So i want the process to read it's own stderr.

    First, some clarifications:
    The libssh stuff runs (blocking) in a QThread since i don't use callback functions.
    libssh is a pure c library, so i'm looking for stderr, not std::cerr.
    The platform is Linux.

    My research/approaches so far:

    qInstallMessageHandler():

    If understood correctly, it only works with qDebug(), qWarning()... thus useless.

    Run the application in a QProcess:

    At first i thought QProcess::readAllStandardError() was the solution, but apparently you can only run external programs in QProcess. I cannot run run my MainWindow Class from main.cpp as a QProcess, right? Because that would probably work, i think, otherwise it's infeasible.

    I've read a few threads about redirecting stdout/stderr to a file, but i didn't find a way to read into a TextStream, and using a file as buffer is not feasible aswell.

    Any ideas? Thanks in advance :)
    Regards, Alex



  • If libssh does not have any configuration option to redirect error log to a file or to a pipe you may try to do it yourself before making a call to libssh
    You may use "freopen()":http://www.cplusplus.com/reference/cstdio/freopen/ or use "dup()":http://stackoverflow.com/a/956269


  • Moderators

    You can also redirect stderr through custom buffer:
    @
    char buffer[BUFSIZ];
    setbuf(stderr, buffer);
    @



  • Thanks for the answers! I tested Chris suggestion and i appeared to be working. However, i couldn't get it working in my program as i intended to. I will give you an update next week.



  • Ok, so i wrote a class wich uses setvbuf() to emit the libssh stderr output periodically as QString signal. This works perfect, for Linux, here is the code:

    errorlogger.h
    @#ifndef ERRORLOGGER_H
    #define ERRORLOGGER_H

    #include <QObject>
    #include <QTimer>
    #include <QDebug>

    #include <iostream>
    #include <stdio.h>

    #define BUFFERSIZE 655360

    /*

    • This class catches the stderr console output (from libssh) and emits it as signal.
    • The stderr stream is buffered in errorBuffer. logErrors() checks the buffer periodically, invoked by a QTimer (every 500ms). If there is content available it is sent via the errorMessage signal to the gui.
      */
      class ErrorLogger : public QObject
      {
      Q_OBJECT
      public:
      explicit ErrorLogger(QObject *parent = 0);

    signals:
    void errorMessage(QString message);

    public slots:
    void logErrors();

    private:
    char errorBuffer[BUFFERSIZE];
    QTimer *timer;

    };

    #endif // ERRORLOGGER_H
    @

    errorlogger.cpp
    @
    #include "errorlogger.h"

    ErrorLogger::ErrorLogger(QObject *parent) :
    QObject(parent)
    {
    // redirect stderr to errorBuffer
    memset(errorBuffer, 0, sizeof(errorBuffer));
    setvbuf(stderr, errorBuffer, _IOLBF, sizeof(errorBuffer));

    // set up QTimer to call logErrors periodically
    timer = new QTimer(this);
    timer->start(500);
    connect(timer, SIGNAL(timeout()), this, SLOT(logErrors()));
    

    }

    void ErrorLogger::logErrors()
    {
    fflush(stderr);

    // if there is stuff in the buffer, send it as errorMessage signal and clear the buffer
    if(strlen(errorBuffer) > 0){
        emit errorMessage(errorBuffer);        // send buffer content to gui
        memset(errorBuffer, 0, sizeof(errorBuffer));
    }
    

    }
    @

    The thing is, i need this for Windows as well. Under Windows, it compiles without a warning, but it doesn't work properly. If i have something like fprintf(stderr, "test"); in my code, it is caught by the class, however, the whole output from libssh is not.
    Does anyone have an idea why? Maybe because the libssh stuff runs in an extra thread?



  • On Windows you need to be sure that your software and 3rd-party library use the same CRT library. If they don't then you will read nothing as every CRT version has separated std-objects instances. "Read this for more details":http://www.syndicateofideas.com/posts/fighting-the-msvcrt-dll-hell



  • Wow, that was the actual problem, thanks Bogdan! I used a precompiled libssh dll from the internet, which was apparently compiled with Visual Studio 2013. I then compiled my own version of libssh with Visual Studio 2012 (which is a huge pain btw) and it worked. The code is even platfrom independent.
    Thanks you all for your support!

    P.s.: For anyone else ever encountering this problem: You can figure out with wich version of Visual Studio your dll has been compiled with the following way: Open the dll with the program Dependency Walker and watch out for msvcr1X0.dll
    msvcr120.dll is VS 2013, msvcr110.dll is VS 2012.


Log in to reply