Article directory
foreword
In the software development process, the use of logs cannot be avoided.
In Qt, what we usually use #include <QDebug>
is part of the log that comes with Qt, and the most common thing we usually use is to output on the console.
However, this article uses custom redirection qInstallMessageHandler()
to type information into the log file.
the code
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 Standalone package
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_);
/// ./myFiles/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();
}
Effect
debug mode
debug mode, set to output in the console
release mode
The release mode is set to record to a file
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
analyze
Qt internal structure
/// 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);
core function
#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);
}
core configuration
# QApplication 所在的库
QT += widgets
# 由于release模式会对程序进行优化
# 通过设定 DEFINES 取消这些优化
# 并取消 debug 信息的输出
CONFIG(release, debug|release) {
# 取消release优化
# 取消优化这些信息:文件名、函数名、行数
DEFINES += QT_MESSAGELOGCONTEXT
# 消除debug输出
DEFINES += QT_NO_DEBUG_OUTPUT
}