/******************************************************************************************
* 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 后才出�
没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
C++ 中比较不错的日志工具有 log4cxx,log4qt 等,但是它们都不能和 qDebug(), qInfo() 等有机的结合在一起,所以在 Qt 中使用总觉得不够舒服,感谢 Qt 提供了 qInstallMessageHandler() 这个函数,使用这个函数可以安装自定义的日志输出处理函数,把日志输出到文件,控制台等,具体的使用可以查看 Qt 的帮助文档。 本文主要是介绍使用 qInstallMessageHandler() 实现一个简单的日志工具,例如调用 qDebug() << “Hi”,输出的内容会同时输出到日志文件和控制台,并且日志文件如果不是当天创建的,会使用它的创建日期备份起来 ———————————————— 版权声明:本文为CSDN博主「康闯」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/sirkang/article/details/106115635
资源推荐
资源详情
资源评论
收起资源包目录
kcLog.zip (6个子文件)
kcLog
kcLog.pro.user 15KB
Singleton.h 3KB
kcLog.cpp 11KB
kcLog.h 401B
main.cpp 1KB
kcLog.pro 1KB
共 6 条
- 1
资源评论
康闯
- 粉丝: 320
- 资源: 20
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功