/******************************************************************************************
* loghanfler.cpp
* by kangchuang
* time:20200514
*
* 使用方法如下:
#include "kcLog.h"
#include <QApplication>
#include <QDebug>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
//安装消息处理函数
Singleton<kcLog>::getInstance().installMessageHandler();
//输出测试,查看是否写入到文件(写入)
qDebug("qDebug:安装消息处理函数,写入到文件!");
qInfo("qInfo:安装消息处理函数,写入到文件!");
qWarning("qWarning:安装消息处理函数,写入到文件!");
qCritical("qCritical:安装消息处理函数,写入到文件!");
// qFatal("qFatal:安装消息处理函数,写入到文件!"); // 写入该行直接致命错误!,以下代码不执行!
//卸载消息处理函数
Singleton<kcLog>::getInstance().uninstallMessageHandler();
//输出测试,查看是否写入到文件(不写入)
qDebug() << "qDebug:卸载消息处理函数,不写入到文件!";
qInfo() << "qInfo:卸载消息处理函数,不写入到文件!";
//再次安装消息处理函数
Singleton<kcLog>::getInstance().installMessageHandler();
//输出测试,查看是否写入到文件(写入)
qDebug() << "qDebug:再次安装消息处理函数,写入到文件!";
qInfo() << "qInfo:再次安装消息处理函数,写入到文件!";
return app.exec();
}
******************************************************************************************/
#include "kcLog.h"
#include <stdio.h>
#include <stdlib.h>
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QMutexLocker>
#include <QTextCodec>
#include <QTextStream>
#include <QTimer>
#include <QtGlobal>
#include <iostream>
/************************************************************************************************************
* *
* kcLogPrivate *
* *
***********************************************************************************************************/
struct kcLogPrivate {
kcLogPrivate();
~kcLogPrivate();
// 打开日志文件 log.txt,如果日志文件不是当天创建的,则使用创建日期把其重命名为 yyyy-MM-dd.log,并重新创建一个 log.txt
void openAndBackupLogFile();
// 消息处理函数
static void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg);
// 如果日志所在目录不存在,则创建
void makeSureLogDirectory() const;
QDir logDir; // 日志文件夹
QTimer renameLogFileTimer; // 重命名日志文件使用的定时器
QTimer flushLogFileTimer; // 刷新输出到日志文件的定时器
QDate logFileCreatedDate; // 日志文件创建的时间
static QFile *logFile; // 日志文件
static QTextStream *logOut; // 输出日志的 QTextStream,使用静态对象就是为了减少函数调用的开销
static QMutex logMutex; // 同步使用的 mutex
};
// 初始化 static 变量
QMutex kcLogPrivate::logMutex;
QFile *kcLogPrivate::logFile = nullptr;
QTextStream *kcLogPrivate::logOut = nullptr;
kcLogPrivate::kcLogPrivate() {
logDir.setPath("log"); // TODO: 日志文件夹的路径,为 exe 所在目录下的 log 文件夹,可从配置文件读取
QString logPath = logDir.absoluteFilePath("log.txt"); // 日志的路径
// 日志文件创建的时间
// QFileInfo::created(): On most Unix systems, this function returns the time of the last status change.
// 所以不能运行时使用这个函数检查创建时间,因为会在运行时变化,于是在程序启动时保存下日志文件的最后修改时间,
// 在后面判断如果不是今天则用于重命名 log.txt
// 如果是 Qt 5.10 后,lastModified() 可以使用 birthTime() 代替
logFileCreatedDate = QFileInfo(logPath).lastModified().date();
// 打开日志文件,如果不是当天创建的,备份已有日志文件
openAndBackupLogFile();
// 十分钟检查一次日志文件创建时间
renameLogFileTimer.setInterval(1000 * 60 * 10); // TODO: 可从配置文件读取
// renameLogFileTimer.setInterval(1000); // 为了快速测试看到日期变化后是否新创建了对应的日志文件,所以 1 秒检查一次
renameLogFileTimer.start();
QObject::connect(&renameLogFileTimer, &QTimer::timeout, [this] {
QMutexLocker locker(&kcLogPrivate::logMutex);
openAndBackupLogFile();
});
// 定时刷新日志输出到文件,尽快的能在日志文件里看到最新的日志
flushLogFileTimer.setInterval(1000); // TODO: 可从配置文件读取
flushLogFileTimer.start();
QObject::connect(&flushLogFileTimer, &QTimer::timeout, [] {
// qDebug() << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"); // 测试不停的写入内容到日志文件
QMutexLocker locker(&kcLogPrivate::logMutex);
if (nullptr != logOut) {
logOut->flush();
}
});
}
kcLogPrivate::~kcLogPrivate() {
if (nullptr != logFile) {
logFile->flush();
logFile->close();
delete logOut;
delete logFile;
// 因为他们是 static 变量
logOut = nullptr;
logFile = nullptr;
}
}
// 打开日志文件 log.txt,如果不是当天创建的,则使用创建日期把其重命名为 yyyy-MM-dd.log,并重新创建一个 log.txt
void kcLogPrivate::openAndBackupLogFile() {
// 总体逻辑:
// 1. 程序启动时 logFile 为 nullptr,初始化 logFile,有可能是同一天打开已经存在的 logFile,所以使用 Append 模式
// 2. logFileCreatedDate is nullptr, 说明日志文件在程序开始时不存在,所以记录下创建时间
// 3. 程序运行时检查如果 logFile 的创建日期和当前日期不相等,则使用它的创建日期重命名,然后再生成一个新的 log.txt 文件
makeSureLogDirectory(); // 如果日志所在目录不存在,则创建
QString logPath = logDir.absoluteFilePath("log.txt"); // 日志的路径
// [[1]] 程序启动时 logFile 为 nullptr
if (nullptr == logFile) {
logFile = new QFile(logPath);
logOut = (logFile->open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) ? new QTextStream(logFile) : nullptr;
if (nullptr != logOut) {
logOut->setCodec("UTF-8");
}
// [[2]] 如果文件是第一次创建,则创建日期是无效的,把其设置为当前日期
if (logFileCreatedDate.isNull()) {
logFileCreatedDate = QDate::currentDate();
}
// TODO: 可以检查日志文件超过 30 个,删除 30 天前的日志文件
}
// [[3]] 程序运行时如果创建日期不是当前日期,则使用创建日期重命名,并生成一个新的 log.txt
if (logFileCreatedDate != QDate::currentDate()) {
logFile->flush();
logFile->close();
delete logOut;
delete logFile;
QString newLogPath = logDir.absoluteFilePath(logFileCreatedDate.toString("yyyy-MM-dd.log"));
;
QFile::copy(logPath, newLogPath); // Bug: 按理说 rename 会更合适,但是 rename 时最后一个文件总是显示不出来,需要 killall Finder 后才出�
康闯
- 粉丝: 330
- 资源: 20
最新资源
- CS-TY4-4WCN-转-公版-XP1-8B4WF-wifi8188
- 从零学习自动驾驶Lattice规划算法(下) 轨迹采样 轨迹评估 碰撞检测 包含matlab代码实现和cpp代码实现,方便对照学习 cpp代码用vs2019编译 依赖qt5.15做可视化 更新:
- 风光储、风光储并网直流微电网simulink仿真模型 系统由光伏发电系统、风力发电系统、混合储能系统(可单独储能系统)、逆变器VSR+大电网构成 光伏系统采用扰动观察法实现mppt控
- (180014016)pycairo-1.18.2-cp35-cp35m-win32.whl.rar
- (180014046)pycairo-1.21.0-cp311-cp311-win32.whl.rar
- DS-7808-HS-HF / DS-7808-HW-E1
- (180014004)pycairo-1.20.0-cp36-cp36m-win32.whl.rar
- (178330212)基于Springboot+VUE的校园图书管理系统
- (402216)人脸识别
- enspOSPF多区域路由配置
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈