Qt重定向QDebug,自定义一个简易的日志管理类

article/2025/10/14 5:33:10

0.前言

相对于第三方的日志库,在 Qt 中使用 QDebug 打印更便捷,有时候也需要对 QDebug 输出进行重定向,如写入文件等。

在 Qt4 中使用 qInstallMsgHandler 函数设置重定向的函数指针:

typedef void (*QtMsgHandler)(QtMsgType, const char *);
Q_CORE_EXPORT QT_DEPRECATED QtMsgHandler qInstallMsgHandler(QtMsgHandler);

在 Qt5 中应该使用 qInstallMessageHandler 来注册函数指针:

typedef void (*QtMessageHandler)(QtMsgType, const QMessageLogContext &, const QString &);
Q_CORE_EXPORT QtMessageHandler qInstallMessageHandler(QtMessageHandler);

返回的函数指针我们可以保存起来,需要输出到控制台时进行调用。 

1.最简单的操作

一个最简单的示例如下,重定向到文件: 

#include <QApplication>
#include <QMutex>
#include <QMutexLocker>
#include <QFile>
#include <QTextStream>
#include <QDebug>//重定向qdebug输出到文件
void myMessageHandle(QtMsgType , const QMessageLogContext& , const QString& msg)
{static QMutex mut; //多线程打印时需要加锁QMutexLocker locker(&mut);QFile file("log.txt");if(file.open(QIODevice::WriteOnly|QIODevice::Append)){QTextStream stream(&file);stream<<msg<<endl;file.close();}
}int main()
{//设置重定向操作的函数qInstallMessageHandler(myMessageHandle);qDebug()<<"Test debug111";qDebug()<<"Test debug222";return 0;
}

运行结果:

2.实现一个简易的日志管理类

需求很简单,同时输出到界面中的编辑框、文件、控制台。

代码链接:https://github.com/gongjianbo/SimpleQtLogger

运行效果:

输出到控制台,我是保存了调用 qInstallMessageHandler 时返回的函数指针,然后调用进行默认的输出。

输出到文件,因为函数调用发生在 qDebug() 调用的线程,所以需要加锁。

输出到界面,我使用了信号槽的方式,将文本发送给 connect 的槽。

当然,还可以添加一些细节,如日志等级的控制等。

下面是部分源码:

#include <QApplication>#include "LogManager.h"
#include "mainwindow.h"int main(int argc, char *argv[])
{LogManager::getInstance()->initManager();//初始化QApplication a(argc, argv);MainWindow w;w.show();return a.exec();
}
#pragma once
#include <QObject>
#include <QFile>
#include <QMutex>
#include <QElapsedTimer>
#include <QDebug>/*** @brief 简易的日志管理类,作为单例* @author 龚建波* @date 2020-08-13* @details* 初始化时调用 initManager 重定向* @note* 改为手动调用 initManager 是为了便于流程控制* 此外,也可以手动调用 freeManager*/
class LogManager : public QObject
{Q_OBJECTQ_DISABLE_COPY_MOVE(LogManager)LogManager();
public:~LogManager();// 获取单例实例static LogManager *getInstance();// 获取带 html 样式标签的富文本Q_INVOKABLE static QString richText(int msgType, const QString &log);// 初始化,如重定向等void initManager(const QString &path = QString());// 释放void freeManager();private:// 重定向到此接口static void outputHandler(QtMsgType type, const QMessageLogContext &context, const QString&msg);// 获取重定向的打印信息,在静态函数种回调该接口void outputLog(QtMsgType type, const QMessageLogContext &context, const QString &msg);signals:// 可以关联信号接收日志信息,如显示到 ui 中// 注意,如果槽函数为 lambda 或者其他没有接收者的情况,需要保证槽函数中的变量有效性// 因为 static 变量的生命周期更长,可能槽函数所在模块已经释放资源,最好 connect 加上接收者void newLog(int msgType, const QString &log);private:// 保留默认 handle,用于输出到控制台QtMessageHandler defaultOutput = nullptr;// 输出到文件QFile file;// 输出路径QString filePath;// 多线程操作时需要加锁QMutex logMutex;// 计算操作间隔,分时生成文件QElapsedTimer elapsedTimer;
};
#include "LogManager.h"
#include <QApplication>
#include <QDir>
#include <QThread>
#include <QTextStream>
#include <QDateTime>LogManager::LogManager()
{//initManager();
}LogManager::~LogManager()
{freeManager();
}LogManager *LogManager::getInstance()
{// 单例,初次调用时实例化static LogManager instance;return &instance;
}QString LogManager::richText(int msgType, const QString &log)
{QString log_text;QTextStream stream(&log_text);switch (msgType) {case QtDebugMsg: stream << "<span style='color:green;'>"; break;case QtInfoMsg: stream << "<span style='color:blue;'>"; break;case QtWarningMsg: stream << "<span style='color:gold;'>"; break;case QtCriticalMsg: stream << "<span style='color:red;'>"; break;case QtFatalMsg: stream << "<span style='color:red;'>"; break;default: stream << "<span style='color:red;'>"; break;}stream << log << "</span>";return log_text;
}void LogManager::initManager(const QString &path)
{// 保存路径filePath = path;if (filePath.isEmpty()){// 用到了 QApplication::applicationDirPath(),需要先实例化一个appint argc = 0;QApplication app(argc,nullptr);filePath = app.applicationDirPath() + "/log";}QDir dir(filePath);if (!dir.exists()){// QFile 不会自动创建不存在的目录dir.mkpath(filePath);}elapsedTimer.start();// 重定向qdebug到自定义函数defaultOutput = qInstallMessageHandler(LogManager::outputHandler);
}void LogManager::freeManager()
{file.close();qInstallMessageHandler(nullptr);
}void LogManager::outputHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{// 转发给单例的成员函数LogManager::getInstance()->outputLog(type, context, msg);
}void LogManager::outputLog(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{// widget 中的 log,context.category = default// qml 中的 log,context.category = qml,此时默认的 output 会增加一个 "qml:" 前缀输出//fprintf(stderr, "print: type = %d, category = %s \n", type, context.category);// 如果要写文件需要加锁,因为函数调用在 debug 调用线程QMutexLocker locker(&logMutex);QString out_text;QTextStream stream(&out_text);// 时间stream << QDateTime::currentDateTime().toString("[yyyy-MM-dd hh:mm:ss]");// 日志类型switch (type) {case QtDebugMsg: stream << "[Debug]"; break;case QtInfoMsg: stream << "[Info]"; break;case QtWarningMsg: stream << "[Warning]"; break;case QtCriticalMsg: stream << "[Critical]"; break;case QtFatalMsg: stream << "[Fatal]"; break;default: stream << "[Unknown]"; break;}// 线程 idstream << "[" << QThread::currentThreadId() << "]";// 输出位置stream << "[" << context.file << ":" << context.line << "]";// 日志信息stream << msg;//写入文件if (file.isOpen()) {// elapsed 距离 start 的毫秒数// 这里设置 1 分钟用来测试if (elapsedTimer.elapsed() > 1000 * 60){file.close();// 重新计时elapsedTimer.restart();}}if (!file.isOpen()) {// 新的文件file.setFileName(filePath + QString("/log_%1.txt").arg(QDateTime::currentDateTime().toString("yyyyMMdd_hhmm")));// Append 追加模式,避免同一文件被清除if (!file.open(QIODevice::WriteOnly | QIODevice::Append)) {emit newLog(QtWarningMsg, "Open log file error:" + file.errorString() + file.fileName());}}if (file.isOpen()) {// 写入文件stream.setDevice(&file);stream << out_text << Qt::endl;}// 发送信号给需要的对象,如 ui 上显示日志emit newLog(type, out_text);// 默认的输出,控制台// 区分日志类型给文本加颜色// 常见格式为:\e[显示方式;背景颜色;前景文字颜色m << 输出字符串 << \e[0m// 其中 \e=\033// -----------------// 背景色  字体色// 40:    30:    黑// 41:    31:    红// 42:    32:    绿// 43:    33:    黄// 44:    34:    蓝// 45:    35:    紫// 46:    36:    深绿// 47:    37:    白// -----------------QString cmd_text;stream.setString(&cmd_text);switch (type) {case QtDebugMsg: // debug 绿色stream << "\033[32m"; break;case QtInfoMsg: // info 蓝色stream << "\033[34m"; break;case QtWarningMsg: // warning 黄色stream << "\033[33m"; break;case QtCriticalMsg: // critical 红字stream << "\033[31m"; break;case QtFatalMsg: // fatal 黑底红字// qFatal 表示致命错误,默认处理会报异常的stream<<"\033[0;31;40m"; break;default: // defualt 默认颜色stream << "\033[0m"; break;}stream << out_text << "\033[0m";defaultOutput(type, context, cmd_text);
}


http://chatgpt.dhexx.cn/article/xASpH8tu.shtml

相关文章

qDebug 控制台输出

做个小笔记:qDebug 控制台输出 Ⅰ&#xff1a;*.pro文件中添加 win32:CONFIG console Ⅱ&#xff1a;配置项目运行设置&#xff0c;将Run in terminal 复选框打勾 Ⅲ&#xff1a;添加头文件 #include <QDebug> Ⅳ&#xff1a;用qDebug()<<"xxxx";输…

Qt ——debug调试

程序调试&#xff1a; 方法一&#xff1a;断点调试法方法二&#xff1a;使用qDebug()函数 方法一&#xff1a;断点调试法 我们可以在程序加断点&#xff0c;然后再利用单步调试查看变量的值是否异常。 1. 设置断点。 可以左击相应的代码行前的区域&#xff08;下图用红色框标…

jadx反编译—下载和使用(傻瓜教程,非常详细)

原文地址 一、在GitHub上直接下载 下载地址 可以下这个版本&#xff1a; 二、运行图形化界面 1、将zip文件解压后定位到在lib文件夹中&#xff0c;在此处打开命令行 2、运行jadx-gui-0.7.1.jar&#xff08;前提是已经装好了JDK1.8&#xff09; 命令如下&#xff1a; <sp…

Android APK 反编译工具 JADX

文章目录 JADX 介绍JADX 安装JADX 使用补充APK 目录结构含义APK 打包流程 JADX 介绍 GitHub 地址&#xff1a;https://github.com/skylot/jadx JADX 支持将 APK, dex, aar, zip 中的 dalvik 字节码反编译为 Java 代码&#xff0c;也支持反编译 AndroidManifest.xml 和 resource…

jadx-gui 重命名功能

jad-gui 是大家常用的一款反编译工具&#xff0c;其中有些小使用技巧可以帮助大家更快的“学习”知识。 安装 方法参考项目GitHub主页 重命名 最新的 1.2.0 版本支持了方法、类、字段的重命名&#xff0c;这是一个非常有用的功能&#xff0c;之前反编译出来的都是混淆后的名…

Android 反编译神器jadx的使用

一、前言 今天介绍一个非常好用的反编译的工具 jadx 。jadx 的功能非常的强大&#xff0c;对我而言&#xff0c;基本上满足日常反编译需求。 jadx 优点&#xff1a; 图形化的界面。拖拽式的操作。反编译输出 Java 代码。导出 Gradle 工程。 这些优点都让 jadx 成为我反编译…

jadx工具windows下载

Release v1.2.0 skylot/jadx GitHubDex to Java decompiler. Contribute to skylot/jadx development by creating an account on GitHub.https://github.com/skylot/jadx/releases/tag/v1.2.0选择第三个jadx-gui-1.2.0-with-jre-win.zip解压exe可正常使用

jadx反编译—下载和使用

一、在GitHub上直接下载 https://github.com/skylot/jadx 可以下这个版本&#xff1a; 二、运行图形化界面 1、将zip文件解压后定位到在lib文件夹中&#xff0c;在此处打开命令行 2、运行jadx-gui-0.7.1.jar&#xff08;前提是已经装好了JDK1.8&#xff09; 命令如下&#xf…

jadx初识

一.jadx介绍 一款相对流行的反编译工具 下载&#xff1a;https://github.com/skylot/jadx/releases/tag/v1.0.0 解压后得到这么几个文件&#xff1a; 启动&#xff1a;&#xff08;以下来两个文件都可以&#xff09; 启动后的界面&#xff1a; 二.使用 打开之后&#xff0c;你可…

反编译工具之jadx

反编译神器之 - jadx git网址&#xff1a; https://github.com/skylot/jadx简介 首先推荐功能强大的jadx&#xff0c;官方网站为&#xff1a;https://github.com/skylot/jadx&#xff0c;可以直接在releases页面下载其最新版&#xff0c;解压即可使用。 安装 Windows下安装 …

Android 反编译工具 jadx-gui

jadx-gui 是一种基于 jadx 项目的图形界面工具&#xff0c;用于反编译 Android 应用程序的工具。通过使用jadx-gui&#xff0c;开发人员可以打开 APK&#xff08;Android应用程序包&#xff09;文件&#xff0c;并查看其反编译的源代码。这对于分析、理解和调试 Android 应用程…

jadx工具介绍及使用

往期推荐 签名校验之“xx银行” Jeb调试ctf(破解密码 Crack the key) ”川报观察“协议分析(抓不到包) 实战分析43XX的HTTPS协议 需要相关资料的朋友&#xff0c;可以【加入此处即可打包获取】 jadx工具是一款反编译利器&#xff0c;同时支持命令行和图形界面&#xff0c…

Java jar反编译工具 jadx

jadx 支持 Windows、Linux、 macOS 项目下载地址 https://github.com/skylot/jadx/releases 按需下载 1.下载zip解压后&#xff0c;进入 bin 目录即可找到执行脚本 jadx&#xff1a;命令行版本 jadx-gui&#xff1a;图形操作界面版本2.下载exe本地双击运行&#xff0c;将…

kali Linux 逆向环境pyenv、Frida、objection、jadx、的安装

目录 1.pyenv安装和使用 1.1pyenv 简介 1.2pyenv 常用命令 1.3pyenv安装和使用 2.Frida安装 2.1Fraida简介 2.1Fraida安装 2.2objection安装 2.3objection常用命令 查看日志 查看包含Frida的日志信息 查看objection的帮助命令 2.3.0进入objection REPL环境 2.3.1直接…

jadx动态调试安卓apk

选用某ctf题目的apk作为调试目标。 工具&#xff1a; 雷电模拟器 jadx1.3.2 步骤&#xff1a; 1、在雷电模拟器安装apk&#xff1a; 2、在jadx打开apk&#xff1a; 3、检查模拟器的adb服务状态&#xff1a; 必须确保模拟器里的adb服务启动&#xff0c;且状态正常&#xff0…

android 反编译 jadx,jadx gui下载 jadx(Android反编译gui工具) v0.6.1 官方版 下载-脚本之家...

jadx是一款Android反编译gui工具&#xff0c;它支持apk、dex、jar、class、zip、aar等文件。jadx操作方便&#xff0c;反编译后的代码可读性高&#xff0c;同时还拥有较完善的gui界面&#xff0c;除去混淆部分的代码&#xff0c;jadx已经非常接近源代码了。需要的朋友可以下载试…

jadx反编译

刚发现的一个反编译神器jadx,对比之前的apktool跟dex2jar,jadx胜在可读性好太多,apktool后的smali长的跟汇编语言一样,dex2jar产生的源码也经常出现奇奇怪怪的语法,让我理解不能. jadx GitHub 地址:https://github.com/skylot/jadx 下载或克隆后,在目录下运行 ./gradlew dis…

新版jadx-gui导入dex会提示Bad checksum

新版jadx-gui导入dex会提示Bad checksum 问题解决方案 问题 今天将一个app脱壳后&#xff0c;拿到DEX&#xff0c;导入jadx中时&#xff0c;弹出了一个错误 也就是会校验dex的checksum&#xff0c;此时如果关闭按钮&#xff0c;忽略错误&#xff0c;会导致dex文件反编译失败&…

jadx学习记录01

原计划是先学习 okHttp 和拦截器&#xff0c;再用 Android Studio 来 demo 下&#xff0c;奈何 Android Studio 装完 sync 一直失败&#xff0c;后续换个电脑再试下、一并整理 okHttp 相关知识点。 今日任务&#xff1a;用 jadx 分析小红书 6.90 版本的 java 代码&#xff0c;…

【Android】Jadx动态调试应用

【Android】Jadx动态调试应用 1. 前言 Jadx已支持动态调试APP&#xff0c;但一直没试过&#xff0c;从逆向角度尝试走一遍流程并熟悉&#xff0c;方便日后翻阅。 2. 相关知识 2.1 动态调试原理 动态调试的原理可以概括为以下几个步骤&#xff1a; 启动应用程序进程&#x…