logUtils.h
#ifndef LOGUTILS_H
#define LOGUTILS_H
#include <QString>
#include <QDateTime>
class LogUtils final
{
public:
explicit LogUtils() = delete;
static void checkAppCacheLogDir(const QString &subDirName = "");
static QString appCacheLogPath();
static QString localDateTime();
static QString localDate();
static QString localDataTimeCSV();
static uint lastTimeStamp(const QDateTime &dateTime, uint dayCount);
static QDateTime lastDateTime(const QDateTime &dateTime, uint dayCount);
static bool containLastDay(const QDateTime &src, const QDateTime &dst, uint dayCount);
static QDateTime toDayZero();
};
#endif // LOGUTILS_H
logUtils.cpp
#include "logutils.h"
#include <QDateTime>
#include <QMutex>
#include <QDebug>
#include <QStandardPaths>
#include <QCoreApplication>
#include <QFileInfo>
#include <QDir>
namespace GlobalPrivate
{
const QString cachePath = QStandardPaths::locate(QStandardPaths::CacheLocation,
"",
QStandardPaths::LocateDirectory);
const QString deepinCachePath = cachePath + "deepin" + QDir::separator();
}
/**
* @brief checkAppCacheLogDir
* 检查应用程序缓存日志的文件夹
* @param subDirName 日志目录下的子目录
* 默认为空,则检查顶层目录
*/
void LogUtils::checkAppCacheLogDir(const QString &subDirName)
{
if (!QFileInfo::exists(GlobalPrivate::deepinCachePath))
QDir().mkdir(appCacheLogPath());
if (!QFileInfo::exists(appCacheLogPath()))
QDir().mkdir(appCacheLogPath());
if (subDirName.isEmpty()) return;
if (!QFileInfo::exists(appCacheLogPath() + QDir::separator() + subDirName))
QDir().mkdir(appCacheLogPath() + QDir::separator() + subDirName);
}
/**
* @brief appCacheLogPath
* 获取当前应用程序的缓存日志路径,
* @return QString 返回的结果总是一个Dir类型的字符路径
*/
QString LogUtils::appCacheLogPath()
{
return GlobalPrivate::deepinCachePath + QCoreApplication::applicationName();
}
/**
* @brief localDateTime 获取年/月/日/时间
* @return QString 格式化字符串后的时间
*/
QString LogUtils::localDateTime()
{
return QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
}
/**
* @brief localDate 获取年/月/日
* @return QString 格式化字符串后的时间
*/
QString LogUtils::localDate()
{
return QDate::currentDate().toString("yyyy-MM-dd");
}
/**
* @brief localDate 获取年/月/日/时间,
* 年/月/日/与时间之间以逗号分割
* @return QString 格式化字符串后的时间
*/
QString LogUtils::localDataTimeCSV()
{
return QDateTime::currentDateTime().toString("yyyy-MM-dd,hh:mm:ss,zzz");
}
/**
* @brief lastTimeStamp 获取输入时间之前指定天数时间戳,
* 最小单位s
* @param dateTime 时间
* @param dayCount 向前的天数
* @return uint 时间戳
*/
uint LogUtils::lastTimeStamp(const QDateTime &dateTime, uint dayCount)
{
return dateTime.toTime_t() - (86400 * dayCount);
}
/**
* @brief lastDateTime 获取输入时间之前指定天数时间,
* 最小单位s
* @param dateTime 时间
* @param dayCount 向前的天数
* @return QDateTime 时间
*/
QDateTime LogUtils::lastDateTime(const QDateTime &dateTime, uint dayCount)
{
return QDateTime::fromTime_t(lastTimeStamp(dateTime,dayCount));
}
/**
* @brief containLastDay 判断时间是否包含时间(天)范围
* 最小单位s
* @param src 基准时间
* @param dst 对比时间
* @param dayCount 往前推的天数
* @return bool 是否包含的结果
*
* |------dst--------src----|
* |------dayCount----|
* return true;
*
* |-----------dst-------------src|
* |-dayCount--|
* return false
*/
bool LogUtils::containLastDay(const QDateTime &src, const QDateTime &dst, uint dayCount)
{
uint srcStamp = src.toTime_t();
uint dstStamp = dst.toTime_t();
return dstStamp - (86400 * dayCount) < srcStamp && srcStamp <= dstStamp;
}
/**
* @brief toDayZero 获取今天的00:00:00的时间
* @return
*/
QDateTime LogUtils::toDayZero()
{
QDateTime dateTime;
dateTime.setDate(QDate::currentDate());
dateTime.setTime(QTime(0,0,0));
return dateTime;
}
frameworklog.h
#include <QDebug>
#include <QLoggingCategory>
/**
* @brief Framework 可进行相关调用,如下
* @code
* qCDebug(Framework) << "hello"; //调试信息打印
* qCInfo(Framework) << "hello"; //信息打印
* qCDWarning(Framework) << "hello"; //警告打印
* qCCritical(Framework) << "hello"; //关键日志打印
* @endcode
*/
Q_DECLARE_LOGGING_CATEGORY(Framework)
/**
* @brief FrameworkLog 宏函数,可进行相关打印调用,如下
* @code
* FDebug() << "hello"; //调试信息打印
* FInfo() << "hello"; //信息打印
* FWarning() << "hello"; //警告打印
* FCritical() << "hello"; //关键日志打印
* @endcode
*/
#define FDebug() qCDebug(Framework)
#define FInfo() qCInfo(Framework)
#define FWarning() qCDWarning(Framework)
#define FCritical() qCCritical(Framework)
#endif
/**
* @brief The FrameworkLog class
* 框架日志打印模块,内部封装输出重定向与日志格式化
*/
class FrameworkLog final
{
public:
explicit FrameworkLog() = delete;
static void enableFrameworkLog(bool enabled = true);
static void setLogCacheDayCount(uint dayCount);
static uint logCacheDayCount();
static void initialize();
};
frameworklog.cpp
#include "frameworklog.h"
#include "logutils.h"
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QCoreApplication>
#include <QtConcurrent>
Q_LOGGING_CATEGORY(Framework, "Framework")
namespace GlobalPrivate
{
static QFile file;
static uint dayCount = 7;
static QMutex mutex;
QString formatFrameworkLogOut(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
auto fileNameList = QString(context.file).split(QDir::separator());
auto currentName = fileNameList[fileNameList.size() - 1];
if (type == QtMsgType::QtDebugMsg)
return "[" + QString(context.category) + "]["
+ LogUtils::localDateTime() + "][Debug]["
+ currentName + " "
+ context.function + " "
+ QString::number(context.line) + "]"
+ msg;
if (type == QtMsgType::QtInfoMsg)
return "[" + QString(context.category) + "]["
+ LogUtils::localDateTime() + "][Info]["
+ currentName + " "
+ context.function + " "
+ QString::number(context.line) + "]"
+ msg;
if (type == QtMsgType::QtCriticalMsg)
return "[" + QString(context.category) + "]["
+ LogUtils::localDateTime() + "][Critical]["
+ currentName + " "
+ context.function + " "
+ QString::number(context.line) + "]"
+ msg;
if (type == QtMsgType::QtWarningMsg)
return "[" + QString(context.category) + "]["
+ LogUtils::localDateTime() + "][Warning]["
+ currentName + " "
+ context.function + " "
+ QString::number(context.line) + "]"
+ msg;
if (type == QtMsgType::QtSystemMsg)
return "[" + QString(context.category) + "]["
+ LogUtils::localDateTime() + "][System]["
+ currentName + " "
+ context.function + " "
+ QString::number(context.line) + "]"
+ msg;
if (type == QtMsgType::QtFatalMsg)
return "[" + QString(context.category) + "]["
+ LogUtils::localDateTime() + "][Fatal]["
+ currentName + " "
+ context.function + " "
+ QString::number(context.line) + "]"
+ msg;
return msg;
}
static void rmExpiredLogs()
{
QtConcurrent::run([=](){
QDirIterator itera(LogUtils::appCacheLogPath(),QDir::Files);
while(itera.hasNext()) {
itera.next();
auto list = itera.fileName().split("_");
if (itera.fileInfo().suffix() == "log"
&& list.count() == 2
&& !LogUtils::containLastDay(
QDateTime(QDate::fromString(list[0],"yyyy-MM-dd"),
QTime(0,0,0,0)),
LogUtils::toDayZero(),
GlobalPrivate::dayCount))
{
auto outMsg = formatFrameworkLogOut(QtMsgType::QtInfoMsg,
QMessageLogContext{
__FILE__,
__LINE__,
__FUNCTION__,
Framework().categoryName()
},
QString("remove true(%0) not last week log: %1")
.arg(QDir().remove(itera.path() + QDir::separator() + itera.fileName()))
.arg(itera.fileName().toLocal8Bit().data())
);
fprintf(stderr, "%s\n", outMsg.toUtf8().data());
}
}
});
}
void redirectGlobalDebug(QtMsgType type,
const QMessageLogContext &context,
const QString &msg)
{
QMutexLocker locker(&mutex);
QString logMsg = GlobalPrivate::formatFrameworkLogOut(type,context,msg);
if (type == QtMsgType::QtDebugMsg)
fprintf(stdin,"%s\n",logMsg.toUtf8().data());
if (type == QtMsgType::QtInfoMsg)
fprintf(stderr,"%s\n",logMsg.toUtf8().data());
if (type == QtMsgType::QtSystemMsg)
fprintf(stdin,"%s\n",logMsg.toUtf8().data());
if (type == QtMsgType::QtCriticalMsg)
fprintf(stderr,"%s\n",logMsg.toUtf8().data());
if (type == QtMsgType::QtWarningMsg)
fprintf(stderr,"%s\n",logMsg.toUtf8().data());
if (type == QtMsgType::QtFatalMsg)
fprintf(stderr,"%s\n",logMsg.toUtf8().data());
// cache/deepin/qApp->applicationName()
LogUtils::checkAppCacheLogDir();
if (GlobalPrivate::file.fileName().isEmpty()) {
GlobalPrivate::file.setFileName(LogUtils::appCacheLogPath()
+ QDir::separator()
+ LogUtils::localDate()
+ "_" + QCoreApplication::applicationName()
+ ".log");
auto outMsg = GlobalPrivate::formatFrameworkLogOut(QtMsgType::QtInfoMsg,
QMessageLogContext{
__FILE__,
__LINE__,
__FUNCTION__,
Framework().categoryName()
},
"Current redirect log file path: "
+ GlobalPrivate::file.fileName()
);
fprintf(stderr, "%s\n", outMsg.toUtf8().data());
//清除超出时间段的日志
GlobalPrivate::rmExpiredLogs();
}
if (!GlobalPrivate::file.open(QFile::Append|QFile::ReadOnly)) {
auto outMsg = GlobalPrivate::formatFrameworkLogOut(QtMsgType::QtInfoMsg,
QMessageLogContext{
__FILE__,
__LINE__,
__FUNCTION__,
Framework().categoryName()
},
"Failed, open redirect log file"
+ GlobalPrivate::file.fileName()
+ " "
+ GlobalPrivate::file.errorString()
);
fprintf(stderr, "%s\n", outMsg.toUtf8().data());
return;
}
GlobalPrivate::file.write((logMsg + ("\n")).toLocal8Bit().data());
GlobalPrivate::file.flush();
GlobalPrivate::file.close();
}
} // namespace GlobalPrivate
/**
* @brief enableFrameworkLog 开启框架日志打印
* @param enabled true为开启,false则关闭
*/
void FrameworkLog::enableFrameworkLog(bool enabled)
{
if (enabled) {
QLoggingCategory::setFilterRules(QLatin1String("FrameworkLog.warning=true"));
QLoggingCategory::setFilterRules(QLatin1String("FrameworkLog.debug=true"));
QLoggingCategory::setFilterRules(QLatin1String("FrameworkLog.info=true"));
QLoggingCategory::setFilterRules(QLatin1String("FrameworkLog.critical=true"));
} else {
QLoggingCategory::setFilterRules(QLatin1String("FrameworkLog.warning=false"));
QLoggingCategory::setFilterRules(QLatin1String("FrameworkLog.debug=false"));
QLoggingCategory::setFilterRules(QLatin1String("FrameworkLog.info=false"));
QLoggingCategory::setFilterRules(QLatin1String("FrameworkLog.critical=false"));
}
}
/**
* @brief setLogCacheDayCount 设置日志缓存时间,
* 需要在调用其他函数之前调用
* @param uint 缓存的天数
*/
void FrameworkLog::setLogCacheDayCount(uint dayCount)
{
static QMutex mutex;
mutex.lock();
GlobalPrivate::dayCount = dayCount;
mutex.unlock();
}
/**
* @brief logCacheDayCount 获取设置的日志缓存时间
* @return uint 缓存的天数,默认缓存7天
*/
uint FrameworkLog::logCacheDayCount()
{
return GlobalPrivate::dayCount;
}
/**
* @brief initialize 初始化框架日志打印模块
*/
void FrameworkLog::initialize()
{
qInstallMessageHandler(&GlobalPrivate::redirectGlobalDebug);
}
调用FrameworkLog::initialize()即可重定向日志输出