如何将标准输出重定向到标准错误

How to redirect stdout to stderr

我正在使用也使用 JavaScript 的 C++ QT 应用程序。在 C++ 中,我使用 qDebug 函数并使用 qInstallMessageHandler 捕获所有数据。

这会捕获定向到 stderr 的所有内容。在 JavaScript 中,我使用 console.info 将数据写入标准输出。

我想做的是将 stdout 重定向到 stderr,这样 console.info 编写的所有消息都会进入同一个消息处理程序。

void qDebugMsgHandler(QtMsgType type, const QMessageLogContext& context, const QString& strMsg) {
    QString strOutput;

    if ( context.file ) {
        strOutput += QString(context.file);

        if ( context.function ) {
            if ( context.line > 0 ) {
                strOutput += QString(" L%1").arg(context.line, 8, 10, QChar('0')) + QString(":");
           }
            strOutput += QString(context.function);
        }
    }
    if ( strMsg.length() > 0 ) {
        if ( strOutput.length() > 0 ) {
            strOutput += ": ";
        }
        strOutput += strMsg;
    }
    switch( type ) {
    case QtDebugMsg:
        fprintf(stderr, "   Debug:%s\n", strOutput.toLatin1().data());
        break;
    case QtInfoMsg:
        fprintf(stderr, "    Info:%s\n", strOutput.toLatin1().data());
        break;
    case QtWarningMsg:
        fprintf(stderr, " Warning:%s\n", strOutput.toLatin1().data());
        break;
    case QtCriticalMsg:
        fprintf(stderr, "Critical:%s\n", strOutput.toLatin1().data());
        break;
    case QtFatalMsg:
        fprintf(stderr, "   Fatal:%s\n", strOutput.toLatin1().data());
        break;
    }
    fflush(stderr);
}

您可以使用 ios::rdbuf.

示例:

#include <iostream>

int main() {
    std::cout << "to stdout\n";
    std::cout.rdbuf(std::cerr.rdbuf());
    std::cout << "to stderr\n";
}

出于我的目的,我最终在 C++ 中创建了一个可调用例程,它可以从 JavaScript、C++ 原型中调用:

Q_INVOKABLE void log(QString strMsg, QString strFile, long ulngLine);

C++ 实现:

void clsScriptHelper::log(QString strMsg, QString strFile, long ulngLine) {
    QJsonObject json;
    json["file"] = strFile;
    json["line"] = QString("%1").arg(ulngLine);
    json["msg"] = strMsg;
    json["type"] = QString("%1").arg(QtDebugMsg);
    qDebug() << json;
}

在JavaScript中,我通过对象引用“api”暴露了我的C++层,然后调用日志例程:

api.log("Testing", "SomeFile.js", 99);

消息处理程序现在如下所示:

void qDebugMsgHandler(QtMsgType type, const QMessageLogContext& context, const QString& strMsg) {
    static const QString scstrQJSONObject("QJsonObject(");

    QString strFile, strFunction, strInfo, strOutput;
    long lngLine = 0;

    switch( type ) {
    case QtDebugMsg:
        strOutput = "   Debug:";
        break;
    case QtInfoMsg:
        strOutput = "    Info:";
        break;
    case QtWarningMsg:
        strOutput = " Warning:";
        break;
    case QtCriticalMsg:
        strOutput = "Critical:";
        break;
    case QtFatalMsg:
        strOutput = "   Fatal:";
        break;
    }
    if ( strMsg.startsWith(scstrQJSONObject) ) {
//Message contains a JSON object, extract the details
        int intLength = strMsg.length() - (scstrQJSONObject.length() + 1);
        QString strJSON = strMsg.mid(scstrQJSONObject.length(), intLength);
        QJsonDocument objDoc = QJsonDocument::fromJson(strJSON.toUtf8());

        if ( objDoc.isNull() ) {
            return;
        }
        QJsonObject objJSON = objDoc.object();
        strFile = objJSON.take("file").toString();
        lngLine = static_cast<long>(objJSON.take("line").toDouble());
        strInfo = objJSON.take("msg").toString();
        type = static_cast<QtMsgType>(objJSON.take("type").toInt());
    } else {
        strFile = QString(context.file);

        if ( context.function ) {
            strFunction = QString(context.function);
        }
        if ( context.line > 0 ) {
            lngLine = context.line;
        }
        strInfo = strMsg;
    }
    if ( strFile.length() > 0 ) {
        strOutput += strFile;
    }
    if ( lngLine > 0 ) {
        strOutput += QString(" L%1").arg(lngLine, 8, 10, QChar('0')) + QString(":");
    }
    if ( strFunction.length() > 0 ) {
        strOutput += strFunction;
    }
    if ( strInfo.length() > 0 ) {
        if ( strOutput.length() > 0 ) {
            strOutput += ": ";
        }
        strOutput += strInfo;
    }
    std::cout << strOutput.toLatin1().data() << std::endl << std::flush;
}