(Qt) 重定向内置日志

news2025/1/23 14:04:04

文章目录

  • 前言
  • 代码
    • .pri 独立的包
      • log.pri
      • LOG_Config.hpp
      • LOG.h
      • LOG.cpp
    • example
      • log_test.pro
      • main.cpp
  • 使用效果
    • debug模式
    • release模式
  • 分析
    • Qt内部结构
    • 核心函数
    • 核心配置
  • END

前言

在软件开发过程中,避免不了日志的使用。

在Qt中,我们平常用的#include <QDebug>就是Qt自带的日志的一部分,平常我们最常用的就是在控制台进行输出。

而本文通过自定义重定向qInstallMessageHandler(),来将信息打到日志文件中。

代码

E:\Qt\demo\saved\LOG>tree /f
卷 新加卷 的文件夹 PATH 列表
卷序列号为 BAEE-AEDC
E:.
│  log_test.pro
│  main.cpp
│
└─log
        LOG.cpp
        LOG.h
        log.pri
        LOG_Config.hpp

.pri 独立的包

log.pri

QT += widgets

INCLUDEPATH += $$PWD

CONFIG(release, debug|release) {
    # 取消release优化
    # 取消优化这些信息:文件名、函数名、行数
    DEFINES += QT_MESSAGELOGCONTEXT
    # 消除debug输出
    DEFINES += QT_NO_DEBUG_OUTPUT
}

HEADERS += \
    $$PWD/LOG.h \
    $$PWD/LOG_Config.hpp


SOURCES += \
    $$PWD/LOG.cpp

LOG_Config.hpp

#ifndef __LOG__CONFIG__HPP__BY__CuberLotus__
#define __LOG__CONFIG__HPP__BY__CuberLotus__

namespace LOG {

/// 保存路径
const char * const _SAVE_PATH_ = "./myFiles/log";
/// 文件后缀名
const char * const _FILE_SUFFIX_NAME_ = ".log";

/// 根据日期分文件夹
/// 这里是具体日志的内容
const char * const _DATA_FIRMAT_ = "yyyy年MM月dd日";
const char * const _TIME_FORMAT_ = "hh:mm:ss";

} // namespace LOG

#endif // __LOG__CONFIG__HPP__BY__CuberLotus__

LOG.h

#ifndef __LOG__H__BY__CuberLotus__
#define __LOG__H__BY__CuberLotus__
#include <QDebug>

namespace LOG {
/// 给外部调用设置的唯一接口
void QLog_Init();
}

#endif  // __LOG__HPP__BY__CuberLotus__

LOG.cpp

#include <QApplication>
#include <QDateTime>
#include <QDebug>
#include <QDir>

#include "LOG.h"
#include "LOG_Config.hpp"

namespace LOG {
/// data
/// 软件版本
static QString appVersion;
/// 日志存储路径
static QString logPath;
/// 日志文件后缀名
static QString suffixName;
/// 日期时间格式
static QString timeFormat;
/// 日志类型的字符串
static QVector<QString> typeStrList;

/**
 * @brief init_Config
 * 初始化配置
 * enum QtMsgType {
 *  QtDebugMsg,
 *  QtWarningMsg,
 *  QtCriticalMsg,
 *  QtFatalMsg,
 *  QtInfoMsg,
 *  QtSystemMsg = QtCriticalMsg
 * };
 */
static void init_config() {
    /// V1.2.3.4
    appVersion = QCoreApplication::applicationVersion();
    if (appVersion.isEmpty()) {
        appVersion = "No Version";
    } else {
        appVersion = "V" + appVersion;
    }

    /// .log
    suffixName = QString(_FILE_SUFFIX_NAME_);
    /// hh:mm:ss
    timeFormat = QString(_TIME_FORMAT_);
    /// ./SMTPCR/log/yyyy年MM月dd日
    logPath = QDir(_SAVE_PATH_).absoluteFilePath(
                QDateTime::currentDateTime().toString(_DATA_FIRMAT_));
    /// 生成path
    QDir().mkpath(logPath);

    typeStrList << QString("Debug") 
        		<< QString("Warning") 
        		<< QString("Critical")
             	<< QString("Fatal") 
        		<< QString("Info") 
        		<< QString("System");
}

/**
 * @brief QtMessageHandler
 * @param type
 * @param context
 * @param msg
 * 重定向的回调函数
 * 样例:[V0.1.2.0] [18:08:52] [@File:..\LOG\main.cpp @Func:int qMain(int,
 * char**) @Line:16]
 */
static void QtMessageHandler(QtMsgType type, const QMessageLogContext& context,
                      const QString& msg) {
    QString filePath = QDir(logPath).absoluteFilePath(
                typeStrList[type] + suffixName);
    QString&& time = QDateTime::currentDateTime().toString(timeFormat);
    QString&& locate = QString("@File:%1 @Func:%2 @Line:%3")
                           .arg(context.file)
                           .arg(context.function)
                           .arg(context.line);
    /// 注意这里使用 \r\n
    QString&& str = QString("[%1] [%2] [%3]\r\n%4\r\n")
                        .arg(appVersion)
                        .arg(time)
                        .arg(locate)
                        .arg(msg);

    QFile file(filePath);
    file.open(QIODevice::WriteOnly | QIODevice::Append);
    QTextStream(&file) << str;
    file.close();
}

/// 给外部调用设置的唯一接口
void QLog_Init() {
    init_config();
#ifdef QT_NO_DEBUG
    qInstallMessageHandler(QtMessageHandler);
#endif
}

}  // namespace LOG

example

log_test.pro

QT += widgets

DESTDIR = $$PWD/bin/

VERSION = 0.1.3
TARGET = log_test_V$$VERSION

CONFIG(debug, debug|release) {
    CONFIG += console
}

INCLUDEPATH += code
include($$PWD/log/log.pri)

SOURCES += \
    main.cpp

main.cpp

#include <QApplication>
#include <QDebug>
#include "LOG.h"

int main(int argc, char *argv[]) {
    QApplication __app(argc, argv);

    LOG::QLog_Init();

    qDebug("This is a debug message");
    qWarning("This is a warning message");
    qCritical("This is a critical message");
    qInfo() << "这是" << "链式操作" << __func__ << __FUNCTION__ << __PRETTY_FUNCTION__;

    return 0;
    // return __app.exec();
}

使用效果

debug模式

debug模式,设定为在控制台输出

在这里插入图片描述

release模式

release模式设定为记录到文件中

E:\Qt\demo\saved\LOG\bin>tree /f
卷 新加卷 的文件夹 PATH 列表
卷序列号为 BAEE-AEDC
E:.
│  log_test_V0.1.3.exe
│
└─myFiles
    └─log
        └─2023年04月18日
                Critical.log
                Info.log
                Warning.log

在这里插入图片描述

分析

Qt内部结构

/// qlogging.h
enum QtMsgType { 
    QtDebugMsg, 
    QtWarningMsg, 
    QtCriticalMsg, 
    QtFatalMsg, 
    QtInfoMsg, 
    QtSystemMsg = QtCriticalMsg 
};

class Q_CORE_EXPORT QMessageLogger {
#ifndef Q_CC_MSVC
    Q_NORETURN
#endif
    Q_DECL_COLD_FUNCTION
    /// 最高危险等级,使用一次程序直接终止
    void fatal(const char *msg, ...) const noexcept Q_ATTRIBUTE_FORMAT_PRINTF(2, 3);

#ifndef QT_NO_DEBUG_STREAM
    QDebug debug() const;
    QDebug debug(const QLoggingCategory &cat) const;
    QDebug debug(CategoryFunction catFunc) const;
    QDebug info() const;
    QDebug info(const QLoggingCategory &cat) const;
    QDebug info(CategoryFunction catFunc) const;
    QDebug warning() const;
    QDebug warning(const QLoggingCategory &cat) const;
    QDebug warning(CategoryFunction catFunc) const;
    QDebug critical() const;
    QDebug critical(const QLoggingCategory &cat) const;
    QDebug critical(CategoryFunction catFunc) const;

    QNoDebug noDebug() const noexcept;
#endif // QT_NO_DEBUG_STREAM
};

#define qDebug QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).debug
#define qInfo QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).info
#define qWarning QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).warning
#define qCritical QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).critical
#define qFatal QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).fatal

/// 重定向的设定
typedef void (*QtMessageHandler)(QtMsgType, const QMessageLogContext &, const QString &);
Q_CORE_EXPORT QtMessageHandler qInstallMessageHandler(QtMessageHandler);

核心函数

#include <QApplication>

/**
 * @brief QtMessageHandler
 * @param type     日志类型
 * @param context  日志上下文
 * @param msg      日志的信息
 * 重定向的回调函数
 */
void QtMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg) {
}

int main(int argc, char *argv[]) {
    /// 必须有 QApplication 的实例
    QApplication a(argc, argv);
    /// 全局函数
    qInstallMessageHandler(QtMessageHandler);
}

核心配置

# QApplication 所在的库
QT += widgets

# 由于release模式会对程序进行优化
# 通过设定 DEFINES 取消这些优化
# 并取消 debug 信息的输出
CONFIG(release, debug|release) {
    # 取消release优化
    # 取消优化这些信息:文件名、函数名、行数
    DEFINES += QT_MESSAGELOGCONTEXT
    # 消除debug输出
    DEFINES += QT_NO_DEBUG_OUTPUT
}



END

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/433958.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Django | 解决admin增加新用户只有用户名密码和确认密码的问题

文章目录 如图所示&#xff0c;下面给出解决方案&#xff1a; 如果您使用 使用 Django 默认的后台管理界面添加用户时&#xff0c;只看到了三个字段&#xff08;通常是 username、password和 repassword&#xff09;&#xff0c;那么可以通过定义 add_fieldsets 属性来增加更多…

Jenkins关联GitLab

1、Jenkins、GitLab服务器上面生成公钥、私钥 ssh-keygen -t ecdsa # 回车 指到没有交互式2、GitLab WEB端添加 刚刚生成的公钥 cat ~/.ssh/id_ecdsa.pub # 查看密钥登入gitlab > 右上角头像 > 偏好设置 > SSH秘钥 使用相同方法 添加Jenkins秘钥 3、Jenkins创建一…

Graph push pull

图数据的存储结构 键值对存储因具有可扩展强、结构简单、查找迅速等特点被广泛应用于图查询系统中&#xff0c;如Wukong、Trinity.RDF。在Wukong系统中&#xff0c;图上的边会转换成键值对进行存储&#xff0c;将顶点编号、边的类型、边的方向、值的地址和大小等信息组合成键&…

Bitmap 实现当前在线用户数量

Bitmap是什么&#xff1f; Bitmap是Redis中的一种数据结构&#xff0c;它是一个类似于位数组的数据结构&#xff0c;用于处理位数据。在Redis中&#xff0c;Bitmap是使用字符串来存储的&#xff0c;一个Byte可以存储8个二进制位&#xff0c;一个字符串可以存储232个二进制位&a…

成功解决:NLTK包的安装错误

成功解决NLTK包的安装错误 创建环境NLP_Pre_train l环境 conda create -n NLP_Pre_train python3.8激活 conda activate NLP_Pre_train安装NLTK&#xff0c;套用以下命令 pip install NLTK之后是验证NLTK是否安装成功&#xff0c;采用的步骤如下所示&#xff1a; import n…

认识Java文件操作和IO流

文件操作&#xff08;一&#xff09; 文章目录 文件操作&#xff08;一&#xff09;文件的特性路径文件分类File类的使用文件的创建文件的删除文件创建加目录创建列出当前文件夹包含的文件文件重命名函数 文件的特性 我们所说的文件一般指的是硬盘文件&#xff0c;其实文件不止…

Minio对象存储服务介绍、单机和集群部署及其使用

Minio对象存储服务介绍、单机和集群部署及其使用 前言Minio简介Minio版本选择AGPL协议说明Minio优缺点优点缺点 Minio分server 和clientminio-client下载二进制文件查看 mc 版本 Minio分布式集群详细搭建基础环境操作系统Minio下载 准备工作1、机器资源2、创建相关目录3、创建启…

IOC容器与DI依赖注入示例

IOC容器与DI依赖注入示例 IOC深入理解IOC示例&#xff1a; DI深入理解DI示例 IOC深入理解 我们先通过几个问题来加深一下对IOC的理解 (1)Spring是使用IOC容器来管理bean对象的&#xff0c;我们主要管理什么? 主要管理项目中所使用到的类对象&#xff0c;比如(Service层对像和…

哈希表|STL使用

哈希表 时间复杂度为O(1) 拉链法 把X代表的数字映射到N所在区间&#xff0c;有可能会发生冲突俩个或多个数字映射到1个数 拉链法&#xff1a;把冲突的数字挂起来&#xff0c;用单链表挂起来 一般取模的数要取成质数&#xff0c;而且这个质数离二的n次幂要比较远&#xff0c;这样…

什么是深度学习?

目录 简介 深度学习的由来 深度学习未来的趋势 总结 简介 深度学习是在20世纪80年代被提出来的&#xff0c;主要是由加拿大的计算机科学家Geoffrey Hinton、Yoshua Bengio、Yann LeCun等人发起的。Geoffrey Hinton等人在经过多年的研究和实践之后&#xff0c;…

C语言的指针(进阶)

目录 数组指针 数组指针的使用 函数指针 函数指针数组 指向函数指针数组的指针 回调函数 数组指针 数组指针是指针&#xff1f;还是数组&#xff1f; 答案是&#xff1a;指针 数组指针也就是指向一个数组的指针 看下面两条代码&#xff1a; int *p1[10]; int (*p2)[10]; …

Manjaro安装clash-for-windows-bin

安装 安装Clash for Windows yay -S clash-for-windows-bin 配置 命令行进入~/.config/clash/ &#xff0c;配置文件 config.yaml 和 Country.mmdb wget -O config.yaml [订阅链接]wget -O Country.mmdb https://gitee.com/mirrors/Pingtunnel/raw/master/GeoLite2-Country.…

领导给了一千多个需求,这个排序法救了我的命……

什么是MoSCoW排序法&#xff1f; 莫斯科排序法是一种优先级排序法&#xff0c;用于管理需求、任务或功能列表。该方法可以帮助团队确定哪些需求、任务或功能是最重要的&#xff0c;并决定在特定时间段内是否需要完成它们。 所以在对需求进行排序时&#xff0c;可以从以下维度…

优思学院|六西格玛常见问题有哪些?

要实现高质量、高效率和高客户满意度的目标&#xff0c;许多企业采用了六西格玛方法。然而&#xff0c;在实施过程中&#xff0c;往往会遇到各种各样的问题。优思学院会在这里探讨一下几个六西格玛常见问题&#xff0c;并提供解决方案&#xff0c;以帮助企业成功实施六西格玛方…

JSONP数据劫持漏洞

​介绍 JSONP&#xff08;JSON with Padding&#xff09;是 json 的一种"使用模式"&#xff0c;可以让网页从别的域名&#xff08;网站&#xff09;那获取资料&#xff0c;即跨域读取数据&#xff1b;它利用的是script标签的 src 属性不受同源策略影响的特性&#x…

GoNote第二章 Moudles

Go Modules 1. 介绍 Go modules是官方提供的go包管理工具&#xff0c;用于解决go包管理和依赖问题&#xff1b;从1.11开始引入&#xff0c;到现在1.14已经比较完善&#xff0c;1.16已经全面推荐使用&#xff0c;并且默认为开启&#xff1b;Go Modules类似于JS的NPM&#xff0…

校园小助手【GUI/Swing+MySQL】(Java课设)

系统类型 Swing窗口类型Mysql数据库存储数据 使用范围 适合作为Java课设&#xff01;&#xff01;&#xff01; 部署环境 jdk1.8Mysql8.0Idea或eclipsejdbc 运行效果 本系统源码地址&#xff1a; 更多系统资源库地址&#xff1a;骚戴的博客_CSDN_更多系统资源 更多系统…

Apple iWork(Pages、Numbers、Keynote)13.0 - 文档、电子表格、演示文稿

请访问原文链接&#xff1a;https://sysin.org/blog/apple-iwork-13/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org 苹果今天将其专为 iOS 和 macOS 设备设计的 iWork 应用套件更新为版本 12 (sysin)&#xff0c;引入了许多新…

高并发服务器之泄峰

文章目录 背景前言解决方案泄峰 泄峰结果总结代码示例 背景 行业&#xff1a; 车联网机器配置&#xff1a;阿里云服务 8核 16G内存 3M带宽 阿里云操作系统单台server接入设备&#xff1a;5w终端产品&#xff1a;GPS定位设备终端与平台通信方式&#xff1a;TCP长链 前言 近期…

Linux中的五种IO模型

Linux中有以下五种IO模型 一、同步阻塞IO&#xff08;Blocking IO, BIO&#xff09; 用户进程发起IO调用后就阻塞线程让出CPU&#xff0c;等待内核处理完毕返回结果再唤醒继续执行。 二、同步非阻塞IO&#xff08;Non-Blocking IO, NIO&#xff09; 用户进程发起IO调用后就…