文章目录
- 前言
- 代码
- .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
}