QT:QDEBUG输出重定向和命令行参数QCommandLineParser

qInstallMessageHandler函数简介

cpp 复制代码
QtMessageHandler qInstallMessageHandler(QtMessageHandler handler)

qInstallMessageHandler 是 Qt 框架中的一个函数,用于安装一个全局的消息处理函数,以替代默认的消息输出机制。这个函数允许开发者自定义 Qt 应用程序中所有调试消息、信息消息、警告消息、严重错误消息和致命错误消息的处理方式。

当 Qt 应用程序中的任何地方调用 qDebug(), qInfo(), qWarning(), qCritical() 或 qFatal() 函数时,如果已经通过 qInstallMessageHandler 安装了一个自定义的消息处理函数,那么这个函数就会被调用,而不是将消息输出到标准输出、标准错误或其他默认位置。

自定义的消息处理函数通常具有以下签名:

cpp 复制代码
void myMessageHandler(QtMsgType, const QMessageLogContext &, const QString &);

type参数:

cpp 复制代码
enum QtMsgType;

实验代码

cpp 复制代码
#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,内容如下:由执行结果可知函数会导致程序退出。

命令行参数

cpp 复制代码
#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

输出的帮助信息

版本测试--version

调试信息重定向测试--log --level=0

显示时间--log --level=0 --time

小结

相关推荐
海的透彻1 小时前
dockerfile如何快速构建容器(java服务)
java·开发语言
code2cat1 小时前
Java工具篇之Gradle:用任务图组织构建与交付
java·开发语言·单元测试·gradle
北京中科新远科技1 小时前
高速交换机端口预算怎么做?下行、上联、拆分和冗余计算框架
开发语言·php
xiaoye-duck2 小时前
《C++ 项目:手写大模型接入 SDK》DeepSeek接口设计(下):流式响应实现和测试
开发语言·网络·c++·语言模型
AI源码2 小时前
基于 Python 的短视频用户行为分析系统
开发语言·python
旖旎夜光3 小时前
【C++ 基础入门】类和对象(上):封装、对象模型与 this 指针
开发语言·c++·笔记·学习
揽星河..3 小时前
【C语言】结构体
c语言·开发语言
2601_966949653 小时前
如何封装 qd.klines.batch(),让批量 K 线查询函数在多个策略中复用?
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
神仙别闹5 小时前
基于Python实现英词语自动对齐系统
开发语言·python
akinggw5 小时前
libagentcore - 一个基于c++的AI多agent系统升级到2.0版本
开发语言·jvm·c++