【问题标题】:Prevent qDebug() from writing to std output防止 qDebug() 写入标准输出
【发布时间】:2018-06-15 12:12:13
【问题描述】:

我正在使用qDebug()qInfo() 等结合qInstallMessageHandler 来写我的logfiles。执行我的应用程序时,我还在批处理屏幕上获得输出。

我只找到QT_NO_DEBUG_OUTPUT,但我想在运行时切换此配置。有没有办法阻止 Qt 写入标准输出?

【问题讨论】:

  • qInstallMessageHandler 是否有助于过滤掉所有调试消息?
  • 遗憾的是,您只能访问消息,但不能阻止将蜜蜂写入标准输出。
  • 为什么不呢?处理 case QtDebugMsg: 并直接中断而不打印任何内容。
  • 我只将它打印到一个文件中,而不是到标准输出中。这是我的代码: static void simpleLoggerMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { QTextStream(QcgSimpleLogger::theSimpleLogger->getLogFile())
  • 这根本不是一个好主意。 QTextStream 的娱乐表现不佳。

标签: c++ qt qdebug


【解决方案1】:

很遗憾,您只能访问消息,但无法阻止将其写入标准输出。

至少在 Qt 5 中这是错误的。消息打印代码looks as follows:可以清楚的看到只使用了消息处理函数:

if (grabMessageHandler()) {
    // prefer new message handler over the old one
    if (msgHandler.load() == qDefaultMsgHandler
            || messageHandler.load() != qDefaultMessageHandler) {
        (*messageHandler.load())(msgType, context, message);
    } else {
        (*msgHandler.load())(msgType, message.toLocal8Bit().constData());
    }
    ungrabMessageHandler();
} else {
    fprintf(stderr, "%s\n", message.toLocal8Bit().constData());
}

如您所见,仅当从 messageHandler 本身检测到递归时,fprintf(stderr, ...) 才是回退。

因此,您只需实现并设置您自己的messageHandler,即可阻止任何调试输出。

要完全关闭 Qt 中的所有调试输出,可以使用以下方法:

#include <QtCore>
int main() {
  qDebug() << "I'm not quiet at all yet";
  qInstallMessageHandler(+[](QtMsgType, const QMessageLogContext &, const QString &){});
  qDebug() << "I'm very, very quiet";
}

在任何情况下,应用程序范围的文件记录器的合理实现可能如下所示 - 它不会不必要地重新创建 QTextStream;它改用QString::toUtf8(),并显式写入行尾。

#include <QtCore>

class Logger {
   static struct Data {
      Logger *instance;
      QtMessageHandler chainedHandler;
   } d;
   bool m_isOpen;
   QFile m_logFile;
   QtMessageHandler m_oldHandler = {};
   static void handler(QtMsgType type, const QMessageLogContext &context, const QString &msg) {
      if (d.instance)
         d.instance->log(msg);
      if (d.chainedHandler)
         d.chainedHandler(type, context, msg);
   }
public:
   enum ChainMode { DontChain, Chain };
   Logger() {
      Q_ASSERT(!instance());
      m_logFile.setFileName("myLog.txt");
      m_isOpen = m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);
      d.instance = this;
   }
   ~Logger() { uninstallHandler(); }
   bool isOpen() const { return m_isOpen; }
   void installHandler(ChainMode mode) {
      Q_ASSERT(!m_oldHandler);
      m_oldHandler = qInstallMessageHandler(handler);
      if (mode == Chain)
         d.chainedHandler = m_oldHandler;
   }
   void uninstallHandler() {
      if (m_oldHandler) {
         m_oldHandler = nullptr;
         d.chainedHandler = nullptr;
         qInstallMessageHandler(m_oldHandler);
      }
   }
   /// This method is *not* thread-safe. Use with a thread-safe wrapper such as `qDebug`.
   void log(const QString & msg) {
      if (isOpen()) {
         m_logFile.write(msg.toUtf8());
         m_logFile.write("\n", 1);
      }
   }
   /// Closes the log file early - this is mostly used for testing.
   void endLog() {
      uninstallHandler();
      m_logFile.close();
   }
   static Logger *instance() { return d.instance; }
};

Logger::Data Logger::d;

template <typename T> QByteArray streamOutputFor(const T &data) {
   QBuffer buf;
   buf.open(QIODevice::ReadWrite | QIODevice::Text);
   QTextStream s(&buf);
   s << data << endl;
   buf.close();
   return buf.data();
}

QByteArray readEnd(const QString &fileName, int count) {
   QFile file(fileName);
   if (file.open(QIODevice::ReadOnly | QIODevice::Text) && file.size() >= count) {
      file.seek(file.size() - count);
      return file.readAll();
   }
   return {};
}

void test() {
   auto const entry = QDateTime::currentDateTime().toString().toUtf8();
   Q_ASSERT(Logger::instance()->isOpen());
   qDebug() << entry.data();
   Logger::instance()->endLog();

   auto reference = streamOutputFor(entry.data());
   auto readback = readEnd("myLog.txt", reference.size());
   Q_ASSERT(!reference.isEmpty());
   Q_ASSERT(readback == reference);
}

int main() {
   Logger logger;
   logger.installHandler(Logger::DontChain);
   qDebug() << "Something or else";
   test();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-31
    • 2012-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多