捕获并打印程序日志信息的方法(Qt)

2023-05-16

工作中为了方便调试,常常需要加入一些打印。常用 Qt 中的 QDebug / QWarning,C 和 C++ 中的 printf / cout 等等,又或者是三方库提供的标准打印接口。
大部分时候,由于这些打印相当不统一(格式和位置),并且因为 Qt 作为 GUI 框架,调试信息实在不应该直接置于 UI 之上。
接下来介绍一种能统一和标准化所有标准打印的方法( 所谓标准打印即标准输出 stdout 等),并且能够动态配置。

关键函数

QT4下
typedef void (*QtMsgHandler)(QtMsgType, const char *);
Q_CORE_EXPORT QtMsgHandler qInstallMsgHandler(QtMsgHandler);
QT5下
typedef void (*QtMessageHandler)(QtMsgType, const QMessageLogContext &, const QString &);
Q_CORE_EXPORT QtMessageHandler qInstallMessageHandler(QtMessageHandler);

对于 Qt 自身的打印,捕获起来比较容易,使用 qInstallMsgHandler 或 qInstallMessageHandler() 安装一个消息处理器,它指向一个函数,其函数签名如下第一行所示. 该函数能够捕获由 Qt Debug 产生的各种类型的打印消息,然后可以在此函数集中处理。

对于三方库,只要他是标准输出,我们就可以使用一些技巧来捕获它:
这里我们需要借助一个C库函数 freopen(),其声明如下:

FILE *freopen(const char * restrict filename, const char * restrict mode, FILE * restrict stream);

该函数用于重定向输入输出流。它可以在不改变代码原貌的情况下改变输入输出环境,但使用时应当保证流是可靠的。

样例

接下来实现一个完整的,能够处理所有情况的例子:

ShowInfo类

#include "showinfo.h"
#include <cstdio>

using namespace std;

ShowInfo::ShowInfo(QObject *parent) :
    QObject(parent),    watchedStdoutFile(qApp->applicationDirPath() + "/test" + "/stdout")
{
    edit  = new QTextEdit();
    stdoutFileDir = qApp->applicationDirPath() + "/test";
    lineCount = 0;
    fileSize = 0;
    initialized = false;
    count = 1;
    initialized = false;

    watcher = new QTimer(qApp);
}
  
void ShowInfo::myUpdate(){
    int len = watchedStdoutFile.size();
    if (len != fileSize) {
        fileSize = watchedStdoutFile.size();
        QString watchedMsg = QString::fromLocal8Bit(watchedStdoutFile.readAll());
        if (!watchedMsg.isEmpty()) {
            QStringList list = watchedMsg.split('\n');
            foreach (QString msg,list) {
                msg = msg.trimmed();
                QString time = QDateTime::currentDateTime().toString("[yyyy-MM-dd-hh:mm:ss:zzz] ");
                if (!msg.isEmpty()) msg = time + msg;
                edit->append(msg);
                if (!edit->textCursor().hasSelection()) edit->moveCursor(QTextCursor::End);
                if (++lineCount > 50000) {
                    lineCount = 0;
                    edit->clear();
                }
            }
        }
    }
    return;
}

void ShowInfo::initializeDebugEnveriment()
{
  if (!initialized) {
      qRegisterMetaType<QTextCursor>("QTextCursor");

      QPalette palette = edit->palette();
      palette.setBrush(QPalette::Highlight, QColor(0, 120, 230));
      edit->setPalette(palette);
      edit->setReadOnly(true);
      edit->setWindowTitle(QString("test窗口"));
      edit->setWindowFlags(Qt::WindowStaysOnTopHint);
      edit->resize(800, 500);
      edit->show();

      if (!QDir().exists(stdoutFileDir)) QDir().mkpath(stdoutFileDir);

      std::freopen((stdoutFileDir + "/stdout").toLocal8Bit().data(), "w", stdout);
      if (!watchedStdoutFile.open(QIODevice::ReadOnly | QIODevice::Text)){
          initialized = false;
          return;
      }

      connect(watcher,SIGNAL(timeout()), this, SLOT(myUpdate()));
      watcher->start(100);
      initialized = true;
  }
}

void ShowInfo::countPlus(){
    qDebug() << "This is Qt Debug message! Count:" << count++;
	qWarning() << "Warning: " << count++;
}

void ShowInfo::countPlus2(){
    std::printf("This is printf stdout message! Count: %d", count++);
    std::fflush(stdout);
}

main.cpp

ShowInfo * sInfo = NULL;

void outputMessage(QtMsgType type,   const char *msg)
{
    QString time = QDateTime::currentDateTime().toString("[yyyy-MM-dd-hh:mm:ss:zzz] ");
    sInfo->edit->append(time + QString(msg));
    if (!sInfo->edit->textCursor().hasSelection()) sInfo->edit->moveCursor(QTextCursor::End);
    if (++sInfo->lineCount > 50000) {
        sInfo->lineCount = 0;
        sInfo->edit->clear();
    }
}


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

     sInfo = new ShowInfo();
     sInfo->initializeDebugEnveriment();
    //注册MessageHandler
     qInstallMsgHandler (outputMessage);

    QTimer timer;
    QObject::connect(&timer, SIGNAL(timeout()), sInfo, SLOT(countPlus()));
    timer.start(1000);

    QTimer otherTimer;
    QObject::connect(&otherTimer, SIGNAL(timeout()), sInfo, SLOT(countPlus2()));
    otherTimer.start(1500);

    return a.exec();
}

运行结果

在这里插入图片描述

结束

基于这个例子 ,日志信息就可以自由保存了。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

捕获并打印程序日志信息的方法(Qt) 的相关文章

  • logback高级特性使用(三)

    本文转自 xff1a 点击打开链接 异步记录日志 注意 xff1a 该功能需要高版本才能支持 xff0c 如1 0 11 AsyncAppender xff0c 异步记录日志 工作原理 xff1a 当Logging Event进入Async
  • spring 官方下载地址(Spring Framework 3.2.x&Spring Framework 4.0.x)

    本文转自 xff1a 点击打开链接 SPRING官方网站改版后 xff0c 建议都是通过 Maven和Gradle 下载 xff0c 对不使用 Maven和Gradle 开发项目的 xff0c 下载就非常麻烦 xff0c 下给出Spring
  • ThreadLocal是否会引起内存溢出?

    本文参考 xff1a 点击打开链接 最近碰到一个使用ThreadLocal时因为未调用remove 而险些引起内存溢出的问题 xff0c 所以看了下ThreadLocal的源码 xff0c 结合线程池原理做一个简单的分析 xff0c 确认是
  • JS判断日期范围(日期范围应在一个月之内)

    本文转自 xff1a 点击打开链接 之前的一个项目的日期选择功能由单个日期 xff0c 修改为日期范围 xff0c 用到了日期范围的判断 xff0c 使用JS实现 xff0c 希望对需要的人有所帮助 代码如下 xff1a var start
  • python视频教程大全集下载啦

    本文转自 xff1a 点击打开链接 python3英文视频教程 全87集 http pan baidu com s 1dDnGBvV python从入门到精通视频 xff08 全60集 xff09 链接 xff1a http pan bai
  • 如何关闭ubuntu alt快捷键

    本文转自 xff1a 点击打开链接 有时候发现ubuntu的alt快捷键真是太烦人了 xff0c 动不动就能把搜索框呼唤出来 xff0c 尤其是我在ubuntu上装了win7虚拟机 xff0c 喜欢用qq的alt 43 s发送消息 xff0
  • ubuntu安装原生迅雷,让下载成为简单

    今天想到电影天堂下点电影 xff0c 发现TM全都是迅雷链接 xff0c 旋风链接什么的 无奈自带的BT下载器速度又慢 xff0c 又满足不了日常的一些文件下载 于是乎google了下 xff0c 哎呀 xff0c 有个mldonkey的电
  • Android 采用fastboot刷system.img boot.img recovery.img’

    手机正常启动后 xff0c 命令行模式下输入 adb reboot bootloader 该命令会自动进入fastboot模式 接着 xff1a fastboot devices 查看是否有设备 erase 擦除的意思 xff0c 你懂得
  • Executors.newSingleThreadExecutor的一些坑

    还是直接上源码吧 public static ExecutorService newSingleThreadExecutor return new FinalizableDelegatedExecutorService new Thread
  • 学习AOP之透过Spring的Ioc理解Advisor

    本文转自 xff1a 点击打开链接 花了几天时间来学习Spring xff0c 突然明白一个问题 xff0c 就是看书不能让人理解Spring xff0c 一方面要结合使用场景 xff0c 另一方面要阅读源代码 xff0c 这种方式理解起来
  • 计算广告资料汇总

    papers 计算广告论文 学习资料 业界分享 王喆Paper Collection of Real Time Bidding Weinan Zhang计算广告干货整理 雪伦 在线课程 Introduction to Computation
  • 编辑器之神-vim的使用技巧

    vim VS emacs vim被誉为编辑器之神 xff0c 而emacs被誉为神之编辑器 中国文化博大精深 xff0c 他们究竟有什么区别呢 xff1f 作为emacs小白的我来说不想在这里献丑 xff0c 直接贴上一篇博客 xff0c
  • Linux离线环境安装bzip2

    1 下载离线安装包 bzip2 1 0 6 13 el7 x86 64 rpm http mirror centos org centos 7 os x86 64 Packages bzip2 1 0 6 13 el7 x86 64 rpm
  • Vivado使用与注意事项

    作者 QQ群 xff1a 852283276 微信 xff1a arm80x86 微信公众号 xff1a 青儿创客基地 B站 xff1a 主页 https space bilibili com 208826118 DRC INBB 3 Bl
  • Android Beam 详细实现步骤

    前言 最近没怎么写东西了 xff0c 主要是在了解Beam这个东东 找到一些高手写的文章 xff0c 奈何水平有限看的云里雾里的 没办法 xff0c 只好去复习官方文档 正文 xff1a 先摘取一部分官方文档 xff1a Beaming N
  • Qt中UTF-8转Unicode

    include lt QtCore QCoreApplication gt include lt QDebug gt include lt iostream gt include lt QTextCodec gt int main int
  • Qt中unicode转utf-8

    最经在研究AT指令接受短信 xff0c 短信是unicode编码 xff0c 接受后需要根据系统的编码方案进行相关的转码 比如接受到了一串字符4F60597D xff0c 它是 你好 的unicode编码 xff0c 一个unicode编码
  • 移植qt5.3.1到arm

    最近刚入手一款开发板 比较低端 刚毕业工作还没一个月 穷屌丝一个 在学校以前都是用的是Friendly Arm的6410 使用的qt版本是使用的最多的4 7 0版本 入手的板子是4 7 4 qt5出来也有好长的时间了 其中提供了很多的特性
  • Linux下生产者与消费者的线程实现

    代码见 现代操作系统 第3版 为了显示效果 xff0c 添加了printf 函数来显示运行效果 1 include lt stdio h gt 2 include lt pthread h gt 3 define MAX 20 4 pthr

随机推荐

  • 基于TCP协议的视频传输

    这个程序是为了大二上学期一个设计作业 xff0c 写的太水 xff0c 之前也发过 xff0c 那个不是最新版 xff0c 这个找到了可能是最新版的 xff0c 昨晚调试了下 xff0c 没用 xff0c 是一个itcol的函数操作无效 x
  • 使用nginx作为websocket的proxy server

    WebSocket WebSocket协议为创建客户端和服务器端需要实时双向通讯的webapp提供了一个选择 其为HTML5的一部分 WebSocket相较于原来开发这类app的方法来说 其能使开发更加地简单 大部分现在的浏览器都支持Web
  • 前后端分离开发部署模式

    身体出了点小毛病 xff0c 这周基本在家养病 xff0c 转文章一篇 xff0c 以激励学习 在开始讨论这个话题之前我们先来认识一下传统的开发模式 一 传统开发模式 相信很多做过Web开发童鞋应该都会经历这样一种开发模式 xff0c 利用
  • I2C总线协议

    毕业设计中使用到了AT24C04器件 xff0c 其是Ateml公司出品的 xff0c 是一种低功耗CMOS串行EEPROM xff0c 其使用两线串行的总线和控制器进行通讯 其内部保存的数据在掉电的情况下可以有40年以上的有效期 其采用8
  • Spark--用Java开发微服务

    这个说的Spark不是apache的Spark xff0c 这边说的是一个java的web application的框架 官网 http sparkjava com 我做过一段时间的后台架构开发 xff0c 使用的是微服务架构 xff0c
  • MQTT协议与mosquitto的安装使用

    MQTT xff08 Message Queuing Telemetry Transport xff0c 消息队列遥测传输 xff09 是一种标准化的发布 订阅消息传输协议 它是一种非常轻量级的协议 xff0c 由于对带宽需求很低 xff0
  • Linux 文件锁

    在文已经共享的情况下如何操作 xff0c 也就是当多个进程同时操作同一个文件时 xff0c 我们怎么保证文件数据的正确性 linux通常采用的方法是文件上锁 xff0c 来避免共享资源的产生竞争状态 文件锁包括建议性锁和强制性的锁 建议性的
  • 基于qt的多线程视频采集与传输

    将服务端的设备虚拟化 xff0c 供客户端调用 使用TCP IP协议传输 xff0c 使用V4L2实现视频采集 只是实现了简单的功能 资源占用大 xff0c 线程的终结还有问题 xff0c 数据大 xff0c 不知道用什么技术压缩图片 这是
  • Qt元对象系统和模板机制的冲突

    Qt元对象系统是对为了Qt对象类型和信号与槽机制引进的 xff0c Qt的工具包中有一个元对象编译器 xff0c 它是为支持Qt元对象系统而产生一些额外C 43 43 代码 xff0c 这些编码会和源码一起被标准的C 43 43 编译器编译
  • qwt学习一

    学习这个东西方向对了 xff0c 就对了一半 今天我开始学习基于qt库的一个开源的绘制2维的统计图的库 qwt 我们画东西首先要有一个容器 xff0c 不然都是徒劳 xff0c 今天我们就介绍这个类 QwtPlot 它继承自QFrame和Q
  • vs自动对齐快捷键

    vs里的行间距和字间距不是c语言的格式解决办法 xff1a 自动对齐 xff1a 方法一 xff08 部分对齐 xff09 xff1a 用鼠标选中要对齐的区域 xff0c 按Crtl 43 K 43 F 方法二 xff08 全部对齐 xff
  • Ubuntu1804编译QWebEngine

    编译环境 Ubuntu1804 43 Qt5 13 2在终端命令框转到qtwebengine源码路径 cd opt Qt5 13 2 5 13 2 Src qtwebengine 执行qmake xff0c 并增加编译参数 opt Qt5
  • 【CSharp + JSON】序列化与反序列化基类集合中的子类对象

    1 测试数据结构 span class token keyword public span span class token keyword interface span span class token class name IPerso
  • iOS开发 富文本加载html代码 (swift版本)UITextView 设置不允许选中,允许链接跳转

    记录iOS 添加 支持html 富文本展示 xff0c 针对隐私政策更新弹框效果展示 xff1a ps 修改 link 属性的颜色 textView linkTextAttributes 61 NSAttributedString Key
  • Arrays用法总结

    数组转字符串 span class hljs keyword int span span class hljs built in array span 61 span class hljs keyword new span span cla
  • 在anaconda中为jupyter安装扩展Nbextensions插件

    1 在开始菜单中 xff0c 以管理员身份打开Anaconda Prompt xff0c 否则安装的时候会提示没有写权限 2 执行安装命令 xff0c 提示是否继续的时候 xff0c 输入y conda install c conda fo
  • ElasticSearch系列(四)--springboot使用ElasticsearchRestTemplate整合ElasticSearch,实现文本高亮检索

    前言 ElasticsearchRestTemplate是spring data elasticsearch项目中的一个类 xff0c 和其他spring项目中的template类似 网上的学习资料大都是基于ElasticsearchTem
  • Activemq 的topic总结

    一 activemq 使用队列 spring boot集成ActiveMQ 简单的队列和 JmsMessagingTemplate 可以参考这个 http blog csdn net zhangjq520 article details 5
  • systemctl服务部署错误:code=exited, status=217/USER

    卸载重装 xff0c 搞定了 xff0c 卸载要彻底 xff0c 参考链接https www cnblogs com nicknailo articles 8563456 html 问题描述 xff1a 在用Linux安装mysql时报错
  • 捕获并打印程序日志信息的方法(Qt)

    工作中为了方便调试 xff0c 常常需要加入一些打印 常用 Qt 中的 QDebug QWarning xff0c C 和 C 43 43 中的 printf cout 等等 xff0c 又或者是三方库提供的标准打印接口 大部分时候 xff