Qt5通过qInstallMessageHandler将日志重定向到文件
先看看日志重定向到文件的内容
[2023-06-08 15:36.907 main.cpp:17 INFO] --------------------------
[2023-06-08 15:36.908 main.cpp:18 INFO] Application Initilizing...
[2023-06-08 15:36.909 main.cpp:19 INFO] --------------------------
[2023-06-08 15:36.892 ShowHikGL.cpp:611 INFO] --------------------------
[2023-06-08 15:36.892 ShowHikGL.cpp:612 INFO] Begin cv::ocl::PlatformInfo
[2023-06-08 15:36.892 ShowHikGL.cpp:622 INFO] Name: NVIDIA CUDA
[2023-06-08 15:36.893 ShowHikGL.cpp:623 INFO] Vendor: NVIDIA Corporation
[2023-06-08 15:36.893 ShowHikGL.cpp:624 INFO] Version: OpenCL 3.0 CUDA 12.1.107
[2023-06-08 15:36.893 ShowHikGL.cpp:625 INFO] Number of devices: 1
[2023-06-08 15:36.893 ShowHikGL.cpp:632 INFO] Device 1
[2023-06-08 15:36.893 ShowHikGL.cpp:633 INFO] Vendor Id: 3
[2023-06-08 15:36.893 ShowHikGL.cpp:634 INFO] Vendor name: NVIDIA Corporation
[2023-06-08 15:36.893 ShowHikGL.cpp:635 INFO] Name: NVIDIA GeForce RTX 3060 Laptop GPU
[2023-06-08 15:36.893 ShowHikGL.cpp:636 INFO] Driver version: 3
[2023-06-08 15:36.893 ShowHikGL.cpp:645 INFO] Is NVidia device
[2023-06-08 15:36.893 ShowHikGL.cpp:647 INFO] Global Memory size: 6441926656
[2023-06-08 15:36.893 ShowHikGL.cpp:648 INFO] Memory cache size: 860160
[2023-06-08 15:36.893 ShowHikGL.cpp:649 INFO] Memory cache type: 2
[2023-06-08 15:36.893 ShowHikGL.cpp:650 INFO] Local Memory size: 49152
[2023-06-08 15:36.893 ShowHikGL.cpp:651 INFO] Local Memory type: 1
[2023-06-08 15:36.893 ShowHikGL.cpp:652 INFO] Max Clock frequency: 1425
[2023-06-08 15:36.893 ShowHikGL.cpp:655 INFO] End cv::ocl::PlatformInfo
[2023-06-08 15:36.893 ShowHikGL.cpp:656 INFO] --------------------------
日志类的代码如下
#ifndef TY_LOGGER_HEADER
#define TY_LOGGER_HEADER
#include <QApplication>
#include <QDebug>
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QTextStream>
#include <QDate>
#include <QDateTime>
#include <QMutex>
#include <QQueue>
#include <QFuture>
#include <QtConcurrent/QtConcurrent>
class TyLogger
{
private:
TyLogger()
{
//writeRunning = 0;
createLogFile();
}
TyLogger(const TyLogger&) = delete;
TyLogger& operator=(const TyLogger&) = delete;
public:
~TyLogger()
{
writeFuture.waitForFinished();
file.close();
}
void write()
{
//if (!writeRunning.testAndSetAcquire(0, 1))
//{
// //qInfo() << "write log has running queue";
// return;
//}
while (true)
{
QMutexLocker locker(&mutex);
if (queue.isEmpty()) break;
const auto msg = queue.dequeue();
// 当日期跨度后相应的更新日志文件名
if (!isCurrentLogFile()) {
file.close();
createLogFile();
}
if (file.isOpen()) {
QTextStream stream(&file);
// 设置编码为UTF-8
stream.setCodec("UTF-8");
stream << msg << endl;
}
}
//// 重置标志允许write在QtConcurrent::run中运行
//writeRunning.store(0);
}
static void customMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg)
{
QString level;
switch (type)
{
case QtDebugMsg:
level = "DEBUG";
break;
case QtWarningMsg:
level = "WARN";
break;
case QtCriticalMsg:
level = "ERROR";
break;
case QtFatalMsg:
level = "FATAL";
break;
case QtInfoMsg:
level = "INFO";
break;
default:
level = "UNKN ";
break;
}
#if _DEBUG
auto fileName = QFileInfo(context.file).fileName();
QString formattedMessage = QString("[%1 %3:%4 %2] %5")
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm.zzz"))
.arg(level)
.arg(fileName)
.arg(context.line)
.arg(msg);
#else
QString formattedMessage = QString("[%1 %2] %5")
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm.zzz"))
.arg(level)
.arg(msg);
#endif
auto& logger = instance();
// locker mutex scope
{
QMutexLocker locker(&logger.mutex);
logger.queue.enqueue(formattedMessage);
}
if (!logger.writeFuture.isRunning())
{
// 使用QtConcurrent::run在后台线程中异步写入日志文件
logger.writeFuture = QtConcurrent::run(&instance(), &TyLogger::write);
}
}
static TyLogger& instance()
{
// C++11标准保证静态局部变量的初始化是线程安全的
static TyLogger logger;
return logger;
}
private:
void createLogFile()
{
QString logDirPath = "Logs";
QDir logDir(logDirPath);
if (!logDir.exists()) {
logDir.mkpath(".");
}
QString logFilePath = logDirPath + "/" + QDateTime::currentDateTime().toString("yyyy-MM-dd") + ".log";
file.setFileName(logFilePath);
file.open(QIODevice::WriteOnly | QIODevice::Append);
currentLogFileDate = QDate::currentDate();
}
bool isCurrentLogFile() const
{
return currentLogFileDate == QDate::currentDate();
}
private:
QMutex mutex;
QQueue<QString> queue;
//QAtomicInt writeRunning;
QFuture<void> writeFuture;
QFile file;
QDate currentLogFileDate;
};
#endif // TY_LOGGER_HEADER
这里主要是传递customMessageHandler到qInstallMessageHandler来重定向日志到文件,在线程中写日志并保证线程安全,通过Queue