qInstallMessageHandler函数简介
QtMessageHandler qInstallMessageHandler(QtMessageHandler handler)
qInstallMessageHandler 是 Qt 框架中的一个函数,用于安装一个全局的消息处理函数,以替代默认的消息输出机制。这个函数允许开发者自定义 Qt 应用程序中所有调试消息、信息消息、警告消息、严重错误消息和致命错误消息的处理方式。
当 Qt 应用程序中的任何地方调用 qDebug(), qInfo(), qWarning(), qCritical() 或 qFatal() 函数时,如果已经通过 qInstallMessageHandler 安装了一个自定义的消息处理函数,那么这个函数就会被调用,而不是将消息输出到标准输出、标准错误或其他默认位置。
自定义的消息处理函数通常具有以下签名:
void myMessageHandler(QtMsgType, const QMessageLogContext &, const QString &);
type参数:
enum QtMsgType;
实验代码
#include <QApplication>
#include <QMutex>
#include <QMutexLocker>
#include <QFile>
#include <QDir>
#include <QDebug>
#include <QCommandLineParser>
#include <QDateTime>static QMutex qml_logfile_mutex;
static int log_level = QtInfoMsg;
static bool g_enable_debug_time = false;
static enum QtMsgType debug_log_level = QtWarningMsg;
#define FORBID_LOG_OUTPUT_LEVEL (QtInfoMsg + 1)
#define NO_QDEBUG_LEVEL ((enum QtMsgType)(QtDebugMsg + 1))
void myMessageOutput(QtMsgType type, const QMessageLogContext& context, const QString& msg) {static int file_index = 0;if(type < log_level){return;}if(type < debug_log_level){return;}QMutexLocker lock(&qml_logfile_mutex);QString filename = "";while (context.file != nullptr) {QStringList dirList;filename = context.file;if (filename.length() < 1) {break;}dirList = filename.split(QDir::separator());if (dirList.size() > 0) {filename = dirList[dirList.size() - 1];}if (filename.contains("/")) {dirList = filename.split("/");if (dirList.size() > 0) {filename = dirList[dirList.size() - 1];}}if (filename.contains("\\")) {dirList = filename.split("\\");if (dirList.size() > 0) {filename = dirList[dirList.size() - 1];}}break;};QString logFileFullName;logFileFullName = qApp->applicationDirPath();logFileFullName.append(QString("\\log\\console_%1.log").arg(file_index));QFile file(logFileFullName);do{if (!file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {return;}if(file.pos() > 1024 * 1024){file.close();file_index++;QString new_file_name;new_file_name = qApp->applicationDirPath();new_file_name.append(QString("\\log\\console_%1.log").arg(file_index));file.setFileName(new_file_name);continue;}break;}while(1);QTextStream text_stream(&file);QString output_text;if(g_enable_debug_time){QString currentDateTime =QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss-zzz");output_text.append("[");output_text.append(currentDateTime);output_text.append("] ");}output_text.append("[");if (filename.length() > 0) {output_text.append(QString("%1").arg(type));}if (filename.length() > 0) {output_text.append(QString("|%1").arg(filename));}if (context.function != nullptr && strlen(context.function) > 0) {output_text.append(QString("|%1").arg(context.function));}if (context.line > 0) {output_text.append(QString("|%1").arg(context.line));}output_text.append(QString("] -- [ %1 ]").arg(msg));text_stream << output_text << Qt::endl;
}
void check_and_mkdir(){QString log_path = qApp->applicationDirPath();log_path.append("/log");QDir log_dir(log_path);if(!log_dir.exists()){qDebug() << log_path << " not exists";qDebug() << log_dir.mkdir(".");}else{qDebug() << log_path << " exists";}
}
void parse_commond_line(QApplication &app){QCommandLineParser parser;parser.setApplicationDescription("Example application");app.setApplicationVersion("version 0.1");//添加帮助选项QCommandLineOption helpOption = parser.addHelpOption();//添加版本选项QCommandLineOption versionOption = parser.addVersionOption();// 添加 --log 选项,这是一个没有值的开关选项QCommandLineOption logOption(QStringList() << "log",QCoreApplication::translate("main", "enable log functionality."));// 添加 --time 选项,这是一个没有值的开关选项QCommandLineOption timeOption(QStringList() << "time",QCoreApplication::translate("main", "enable show log time."));// 添加 --level 选项,这是一个带有值的选项QCommandLineOption levelOption(QStringList() << "level",QCoreApplication::translate("main", "set log level"),QCoreApplication::translate("main", "level"), // 默认值(可选)"5"); // 值名称,用于解析 --level=VALUEQCommandLineOption debugOption(QStringList() << "debug",QCoreApplication::translate("main", "set log debug"),QCoreApplication::translate("main", "debug"), // 默认值(可选)"2"); // 值名称,用于解析 --level=VALUE// 将选项添加到解析器parser.addOptions({ logOption, timeOption, levelOption, debugOption});// 解析命令行参数bool parseOk = parser.parse(QCoreApplication::arguments());qDebug() << "parseOk:" << parseOk;// 检查是否请求了帮助if (parser.isSet(helpOption)) {parser.showHelp();qDebug() << "-----------------------";qDebug() << parser.helpText(); // 输出帮助信息qDebug() << "-----------------------";exit(0);}// 检查是否请求了版本if (parser.isSet(versionOption)) {parser.showVersion(); // 输出帮助信息qDebug() << "after showVersion";app.processEvents();exit(0);}// 检查 --time 选项是否被设置bool timeEnabled = parser.isSet(timeOption);g_enable_debug_time = timeEnabled;// 检查 --log 选项是否被设置bool logEnabled = parser.isSet(logOption);qDebug() << "Log enabled:" << logEnabled;if(logEnabled){check_and_mkdir();// 检查 --level 选项的值bool hasLevel = parser.isSet(levelOption);if(hasLevel){QString levelQStringValue = parser.value(levelOption);bool isInt = false;int levelValue = levelQStringValue.toInt(&isInt,10);if(isInt){if(levelValue < 0){levelValue = FORBID_LOG_OUTPUT_LEVEL;}log_level = levelValue;}else{log_level = FORBID_LOG_OUTPUT_LEVEL;}}else{log_level = FORBID_LOG_OUTPUT_LEVEL;}bool hasDebug = parser.isSet(debugOption);qDebug() << "hasDebug = " << hasDebug;if(hasDebug){QString debugQStringValue = parser.value(debugOption);bool isInt = false;int debugValue = debugQStringValue.toInt(&isInt,10);qDebug() << debugValue;if(isInt){if(debugValue < 0){debugValue = NO_QDEBUG_LEVEL;}debug_log_level = (enum QtMsgType)debugValue;}else{debug_log_level = NO_QDEBUG_LEVEL;}}else{debug_log_level = NO_QDEBUG_LEVEL;}qInstallMessageHandler(myMessageOutput);}
}
int main(int argc, char *argv[])
{QApplication app(argc, argv);parse_commond_line(app);int count = 0;while(count < 10000){count++;qDebug() << "count = " << count;qDebug() << "qDebug:hello log file";qInfo() << "qInfo:hello log file";qWarning() << "qWarning:hello log file";qCritical() << "QtCriticalMsg:hello log file";}qFatal("qFatal:hello log file");return app.exec();
}
测试结果:
运行后,会生成log文件夹,并生成文件console.log,内容如下:由执行结果可知函数会导致程序退出。
命令行参数
#include <QApplication>
#include <QMutex>
#include <QMutexLocker>
#include <QFile>
#include <QDir>
#include <QDebug>
#include <QCommandLineParser>
#include <QDateTime>static QMutex qml_logfile_mutex;
static int log_level = QtInfoMsg;
static bool g_enable_debug_time = false;
static enum QtMsgType debug_log_level = QtWarningMsg;
#define FORBID_LOG_OUTPUT_LEVEL (QtInfoMsg + 1)
#define NO_QDEBUG_LEVEL ((enum QtMsgType)(QtDebugMsg + 1))
void myMessageOutput(QtMsgType type, const QMessageLogContext& context, const QString& msg) {static int file_index = 0;if(type < log_level){return;}if(type < debug_log_level){return;}QMutexLocker lock(&qml_logfile_mutex);QString filename = "";while (context.file != nullptr) {QStringList dirList;filename = context.file;if (filename.length() < 1) {break;}dirList = filename.split(QDir::separator());if (dirList.size() > 0) {filename = dirList[dirList.size() - 1];}if (filename.contains("/")) {dirList = filename.split("/");if (dirList.size() > 0) {filename = dirList[dirList.size() - 1];}}if (filename.contains("\\")) {dirList = filename.split("\\");if (dirList.size() > 0) {filename = dirList[dirList.size() - 1];}}break;};QString logFileFullName;logFileFullName = qApp->applicationDirPath();logFileFullName.append(QString("\\log\\console_%1.log").arg(file_index));QFile file(logFileFullName);do{if (!file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {return;}if(file.pos() > 1024 * 1024){file.close();file_index++;QString new_file_name;new_file_name = qApp->applicationDirPath();new_file_name.append(QString("\\log\\console_%1.log").arg(file_index));file.setFileName(new_file_name);continue;}break;}while(1);QTextStream text_stream(&file);QString output_text;if(g_enable_debug_time){QString currentDateTime =QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss-zzz");output_text.append("[");output_text.append(currentDateTime);output_text.append("] ");}output_text.append("[");if (filename.length() > 0) {output_text.append(QString("%1").arg(type));}if (filename.length() > 0) {output_text.append(QString("|%1").arg(filename));}if (context.function != nullptr && strlen(context.function) > 0) {output_text.append(QString("|%1").arg(context.function));}if (context.line > 0) {output_text.append(QString("|%1").arg(context.line));}output_text.append(QString("] -- [ %1 ]").arg(msg));text_stream << output_text << Qt::endl;
}
void check_and_mkdir(){QString log_path = qApp->applicationDirPath();log_path.append("/log");QDir log_dir(log_path);if(!log_dir.exists()){qDebug() << log_path << " not exists";qDebug() << log_dir.mkdir(".");}else{qDebug() << log_path << " exists";}
}
void parse_commond_line(QApplication &app){QCommandLineParser parser;parser.setApplicationDescription("Example application");app.setApplicationVersion("version 0.1");//添加帮助选项QCommandLineOption helpOption = parser.addHelpOption();//添加版本选项QCommandLineOption versionOption = parser.addVersionOption();// 添加 --log 选项,这是一个没有值的开关选项QCommandLineOption logOption(QStringList() << "log",QCoreApplication::translate("main", "enable log functionality."));// 添加 --time 选项,这是一个没有值的开关选项QCommandLineOption timeOption(QStringList() << "time",QCoreApplication::translate("main", "enable show log time."));// 添加 --level 选项,这是一个带有值的选项QCommandLineOption levelOption(QStringList() << "level",QCoreApplication::translate("main", "set log level"),QCoreApplication::translate("main", "level"), // 默认值(可选)"5"); // 值名称,用于解析 --level=VALUEQCommandLineOption debugOption(QStringList() << "debug",QCoreApplication::translate("main", "set log debug"),QCoreApplication::translate("main", "debug"), // 默认值(可选)"2"); // 值名称,用于解析 --level=VALUE// 将选项添加到解析器parser.addOptions({ logOption, timeOption, levelOption, debugOption});// 解析命令行参数bool parseOk = parser.parse(QCoreApplication::arguments());qDebug() << "parseOk:" << parseOk;// 检查是否请求了帮助if (parser.isSet(helpOption)) {parser.showHelp();qDebug() << "-----------------------";qDebug() << parser.helpText(); // 输出帮助信息qDebug() << "-----------------------";exit(0);}// 检查是否请求了版本if (parser.isSet(versionOption)) {parser.showVersion(); // 输出帮助信息qDebug() << "after showVersion";app.processEvents();exit(0);}// 检查 --time 选项是否被设置bool timeEnabled = parser.isSet(timeOption);g_enable_debug_time = timeEnabled;// 检查 --log 选项是否被设置bool logEnabled = parser.isSet(logOption);qDebug() << "Log enabled:" << logEnabled;if(logEnabled){check_and_mkdir();// 检查 --level 选项的值bool hasLevel = parser.isSet(levelOption);if(hasLevel){QString levelQStringValue = parser.value(levelOption);bool isInt = false;int levelValue = levelQStringValue.toInt(&isInt,10);if(isInt){if(levelValue < 0){levelValue = FORBID_LOG_OUTPUT_LEVEL;}log_level = levelValue;}else{log_level = FORBID_LOG_OUTPUT_LEVEL;}}else{log_level = FORBID_LOG_OUTPUT_LEVEL;}bool hasDebug = parser.isSet(debugOption);qDebug() << "hasDebug = " << hasDebug;if(hasDebug){QString debugQStringValue = parser.value(debugOption);bool isInt = false;int debugValue = debugQStringValue.toInt(&isInt,10);qDebug() << debugValue;if(isInt){if(debugValue < 0){debugValue = NO_QDEBUG_LEVEL;}debug_log_level = (enum QtMsgType)debugValue;}else{debug_log_level = NO_QDEBUG_LEVEL;}}else{debug_log_level = NO_QDEBUG_LEVEL;}qInstallMessageHandler(myMessageOutput);}
}
int main(int argc, char *argv[])
{QApplication app(argc, argv);parse_commond_line(app);int count = 0;while(count < 10000){count++;qDebug() << "count = " << count;qDebug() << "qDebug:hello log file";qInfo() << "qInfo:hello log file";qWarning() << "qWarning:hello log file";qCritical() << "QtCriticalMsg:hello log file";}qFatal("qFatal:hello log file");return app.exec();
}
测试
帮助信息测试:--help
输出的帮助信息