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=VALUE
QCommandLineOption 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=VALUE
QCommandLineOption 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
输出的帮助信息