一、介绍
在qt中要使用qt自带的日志系统我们都知道实现回调函数QtMessageHandler,再用qInstallMessageHandler函数进行注册:
// 注册日志处理
qInstallMessageHandler();
同时在pro文件中加入:
DEFINES += QT_MESSAGELOGCONTEXT # 日志
题外话:一般在商业项目中,我们可能不会使用qt的日志系统,而是会采用第三方的日志系统,比如常用语java后端的log4j,在qt中有Log4Qt,这篇文章很详细:https://blog.youkuaiyun.com/robert_cysy/article/details/105446185
二、实现
基于此我们就可以写出我们自定义的日志系统了,我写的这个日志系统具有以下特点:
1、支持设置日志输出路径
2、支持日志打印格式设置
3、支持不同日志级别的不同样式设置
4、支持3种日志备份策略,采用延迟策略,不是用定时器实现周期备份,而是在具体打印内容时才触发,这么做的目的是减少定时的开销
5、支持分日志类型备份日志
6、支持备份策略参数的json文件地址存储自定义
7、支持回调函数注册,便于一些想将日志输出到自己项目界面展示的小伙伴
下面是我的实现,我们只需要引入相应的h和cpp文件即可:
log.h
#ifndef LOG_H
#define LOG_H
#include <QApplication>
#include <QReadWriteLock>
#include <QFile>
/**
* @brief The Color class 颜色设置
*/
class ConsoleFont {
public:
const static int DEFAULT; // 重置颜色设置
const static int BOLD; // 加粗
const static int UN_BOLD; // 去粗
const static int UNDER_LINE; // 下滑线
const static int GLINT; // 闪烁
const static int INVERSE;// 反色
const static int BOLD_2; // 加粗
const static int NORMAL ; // 正常
const static int UN_UNDER_LINE; // 去掉下滑线
const static int STOP_GLINT; // 停止闪烁
const static int INVERSE_2;// 反色
const static int FORE_GROUND_BLACK;// 前景,黑色
const static int FORE_GROUND_RED;// 前景,红色
const static int FORE_GROUND_GREEN;// 前景,绿色
const static int FORE_GROUND_ORANGE;// 前景,黄色
const static int FORE_GROUND_BLUE; //前景,篮色
const static int FORE_GROUND_PURPLE; //前景,紫色
const static int FORE_GROUND_CYAN; //前景,青色
const static int FORE_GROUND_WHITE; //前景,白色
const static int BACK_GROUND_BLACK;// 背景,黑色
const static int BACK_GROUND_RED;// 背景,红色
const static int BACK_GROUND_GREEN;// 背景,绿色
const static int BACK_GROUND_ORANGE;// 背景,黄色
const static int BACK_GROUND_BLUE; //背景,篮色
const static int BACK_GROUND_PURPLE; //背景,紫色
const static int BACK_GROUND_CYAN; //背景,青色
const static int BACK_GROUND_WHITE; //背景,白色
/**
* @brief setConsoleFont 设置控制台字体样式
* @param codes 字体样式code集合,用{}设置数组的方式进行传参
* @param msg 信息
* @return 设置样式后的内容
*/
const static QString setConsoleFont(std::initializer_list<int> codes, QString msg);
};
/**
* @brief The LogType enum 日志输出类型
*/
enum LogOutType {
STANDARD_OUTPUT, // 标准输出流
STANDARD_ERROR_OUTPUT // 标准错误输出流
};
/**
* @brief The LogSwitchoverType enum 日志切换方式(即备份方式)
*/
enum LogSwitchoverType{
ALL_DAY, // 指定天数备份,即相隔天数的凌晨00:00:00(对应单位是天d)
TIME_PERIOD, // 指定时间间隔备份,即从项目启动开始后的间隔时间周期(对应单位是秒s)
FILE_SIZE // 指定文件大小备份(对应单位是kb)
};
/**
* 回调函数,日志类型、日志上下文,日志信息、格式化之后的信息,传入对象上下文
*/
typedef void (*LogInfoCallBackHandler)(QtMsgType, const QMessageLogContext &, const QString &,const QString &,void *);
/**
* @brief The CallBackInfo class 回调信息
*/
class CallBackInfo{
public:
CallBackInfo() {}
CallBackInfo(QString unique, LogInfoCallBackHandler hander, void* context) {
this->unique = unique;
this->hander = hander;
this->context = context;
}
QString unique; // 唯一标识
LogInfoCallBackHandler hander; // 回调函数
void* context; // 对象上下文
};
/**
* 回调信息线程安全集合
*/
class CallBackInfoSafeList{
public:
CallBackInfoSafeList() {}
void add(CallBackInfo info){
QWriteLocker lock(readWriteLock);
this->mList.append(info);
}
QList<CallBackInfo> getList(){
QReadLocker lock(readWriteLock);
return mList;
}
CallBackInfo get(int index){
QReadLocker lock(readWriteLock);
return mList.value(index);
}
private:
QList<CallBackInfo> mList; // 回调信息集合
mutable QReadWriteLock *readWriteLock = new QReadWriteLock(); // 读写锁
};
/**
* @brief The Log class 日志
*/
class Log
{
public:
Log() {}
const static QString INFO_FORMAT_TIME; // 格式化输出日期表示
const static QString INFO_FORMAT_LEVEL; // 格式化输出日志级别表示
const static QString INFO_FORMAT_CODE_FILE; // 格式化输出代码文件地址表示
const static QString INFO_FORMAT_CODE_LINE; // 格式化输出代码所在行表示
const static QString INFO_FORMAT_CODE_FUNCTION; // 格式化输出代码所在方法函数表示
const static QString INFO_FORMAT_CODE_MSG; // 格式化输出代码打印内容表示
/**
* @brief setFormat 设置日志输出内容格式化
* @param infoFormat 内容格式化参数
* @param timeFormat 日期格式化
*/
static void setFormat(QString infoFormat, QString timeFormat = "yyyy-MM-dd hh:mm:ss:zzz");
/**
* @brief setLevelColor 设置不同日志级别的字体格式
* @param type 日志类型
* @param levelColor 字体格式
*/
static void setLevelFont(QtMsgType type, std::initializer_list<int> levelFont);
/**
* @brief setOutLogPath 设置输出地址
* @param outLogPath 日志输出地址
*/
static void setOutLogPath(QString outLogPath);
/**
* @brief setOutLogParamPath 设置日志备份参数json存储地址
* @param logParamPath 日志备份参数json存储地址
*/
static void setOutLogParamJsonPath(QString logParamJsonPath);
/**
* @brief setLogSwitchover 设置日志切换备份方式
* @param logSwitchoverType 日志备份类型
* @param switchoverNum 备份时间或大小(ALL_DAY则是天数;TIME_PERIOD是时间间隔,单位秒;FILE_SIZE是文件大小,单位时kb)
*/
static void setLogSwitchover(LogSwitchoverType logSwitchoverType, long long switchoverNum);
/**
* @brief setDistinguishLevel 设置备份输出是否区分日志级别单独输出
* @param isDistinguishLevel 是否区分
*/
static void setDistinguishLevel(bool isDistinguishLevel);
/**
* @brief messageOutput 日志输出注册函数
* @param type 日志信息类型
* @param context 日志信息上下文
* @param msg 输出内容信息
*/
static void messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg);
/**
* @brief registLogInfoCallBack 注册回调函数,注册函数使用链式调用,只要注册的函数都会进行调用
* @param unique 唯一标识
* @param hander 回调函数
* @param contex 上下文,可以传入自己想操作的对象
* @return
*/
static LogInfoCallBackHandler registLogInfoCallBack(QString unique, LogInfoCallBackHandler hander,void* context = nullptr);
private:
/**
* @brief msgTypeMap 日志类型与标识、输出类型映射
*/
static QMap<QtMsgType,QPair<QString, LogOutType>> msgTypeMap;
/**
* @brief levelFontMap 针对不同日志级别的字体显示设置映射
*/
static QMap<QtMsgType,std::initializer_list<int>> levelFontMap;
/**
* @brief logSwitchoverTypeMap 备份类型与字符的映射
*/
static QMap<LogSwitchoverType, QString> logSwitchoverTypeMap;
/**
* @brief outLogFile 输出file
*/
static QFile* outLogFile;
/**
* @brief levelPaths 不同级别对应的输出路径
*/
static QMap<QtMsgType, QFile*> levelPaths;
/**
* @brief isDistinguishLevel 是否区分日志级别输出
*/
static bool isDistinguishLevel;
/**
* @brief infoFormat 日志输出内容格式化参数
*/
static QString infoFormat;
/**
* @brief timeFormat 日期格式
*/
static QString timeFormat;
/**
* @brief logParamJsonFile 日志备份策略参数保存json文件
*/
static QFile* logParamJsonFile;
/**
* @brief logSwitchoverType 指定备份类型
*/
static LogSwitchoverType logSwitchoverType;
/**
* @brief switchoverNum 指定备份时间或大小
*/
static long long switchoverNum;
/**
* @brief switchoverTime 备份切换时间
*/
static QDateTime switchoverTime;
/**
* @brief isLoadLogSwitchoverSetting 是否加载备份日志设置
*/
static bool isLoadLogSwitchoverSetting;
/**
* @brief pCallback 存放回调函数的集合
*/
static CallBackInfoSafeList pCallbacks;
/**
* @brief initMsgTypeMap 初始化日志类型与标识、输出类型映射
* @return 日志类型与标识、输出类型映射
*/
static QMap<QtMsgType,QPair<QString, LogOutType>> initMsgTypeMap();
/**
* @brief initLevelColors 初始化不同日志级别的字体显示设置映射
*/
static QMap<QtMsgType,std::initializer_list<int>> initLevelFonts();
/**
* @brief initLogSwitchoverTypeMap 初始化备份类型与字符的映射
*/
static QMap<LogSwitchoverType, QString> initLogSwitchoverTypeMap();
/**
* @brief writeLog 输出日志内容到文件
* @param str 日志内容
* @param QtMsgType 日志类型
*/
static void writeLog(QString str, QtMsgType msgType);
/**
* @brief loadLogSwitchoverSetting 加载日志备份设置
*/
static void loadLogSwitchoverSetting();
/**
* @brief logSwitchoverSettingHander 日志备份设置处理
*/
static void logSwitchoverSettingHander();
/**
* @brief writeLogParamJson 向json文件中写入备份参数
*/
static void writeLogParamJson();
/**
* @brief copyLogOutFile 备份日志文件
*/
static void copyLogOutFile(QtMsgType msgType);
/**
* @brief copy 拷贝文件,目标文件存在则覆盖
* @param srcFilepPath 源文件
* @param targetFilePath 目标文件
* @param 拷贝成功与否
*/
static bool copy(QString srcFilepPath, QString targetFilePath);
/**
* @brief replace 替换字符串
* @param src 原字符串
* @param before 被替换的字符串
* @param after 替换字符串
* @return 被替换之后的字符串
*/
static QString replace(QString src, QString before, QString after);
/**
* @brief isContainInfoFormat 判断是否包含格式化信息
* @return 包含与否