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

小结

相关推荐
用户805533698034 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner4 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz9 天前
QML Hello World 入门示例
qt
xcyxiner12 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner13 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner13 天前
DicomViewer (添加模型类)3
qt
xcyxiner14 天前
DicomViewer (目录调整) 2
qt
xcyxiner14 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00616 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术16 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript