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

小结

相关推荐
网络风云20 分钟前
golang中的包管理-下--详解
开发语言·后端·golang
小唐C++38 分钟前
C++小病毒-1.0勒索
开发语言·c++·vscode·python·算法·c#·编辑器
S-X-S43 分钟前
集成Sleuth实现链路追踪
java·开发语言·链路追踪
北 染 星 辰1 小时前
Python网络自动化运维---用户交互模块
开发语言·python·自动化
佳心饼干-1 小时前
数据结构-栈
开发语言·数据结构
我们的五年1 小时前
【C语言学习】:C语言补充:转义字符,<<,>>操作符,IDE
c语言·开发语言·后端·学习
灯火不休ᝰ1 小时前
[java] java基础-字符串篇
java·开发语言·string
励志去大厂的菜鸟2 小时前
系统相关类——java.lang.Math (三)(案例详细拆解小白友好)
java·服务器·开发语言·深度学习·学习方法
w(゚Д゚)w吓洗宝宝了2 小时前
单例模式 - 单例模式的实现与应用
开发语言·javascript·单例模式
siy23332 小时前
【c语言日寄】Vs调试——新手向
c语言·开发语言·学习·算法