123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634 |
- /*--------------------------------------------------------------------------
- * 基于此我们就可以写出我们自定义的日志系统了,我写的这个日志系统具有以下特点:
- 1、支持设置日志输出路径
- 2、支持日志打印格式设置
- 3、支持不同日志级别的不同样式设置
- 4、支持3种日志备份策略,采用延迟策略,不是用定时器实现周期备份,而是在具体打印内容时才触发,这么做的目的是减少定时的开销
- 5、支持分日志类型备份日志
- 6、支持备份策略参数的json文件地址存储自定义
- 7、支持回调函数注册,便于一些想将日志输出到自己项目界面展示
- --------------------------------------------------------------------------------*/
- #include "log.h"
- #include <iostream>
- #include <QDebug>
- #include <QtMessageHandler>
- #include <QFile>
- #include <QDir>
- #include <QDateTime>
- #include <qjsondocument.h>
- #include <qjsonobject.h>
- using namespace std;
- const int ConsoleFont::DEFAULT = 0; // 重置颜色设置
- const int ConsoleFont::BOLD = 1; // 加粗
- const int ConsoleFont::UN_BOLD = 2; // 去粗
- const int ConsoleFont::UNDER_LINE = 4; // 下滑线
- const int ConsoleFont::GLINT = 5; // 闪烁
- const int ConsoleFont::INVERSE = 7;// 反色
- const int ConsoleFont::BOLD_2 = 21; // 加粗
- const int ConsoleFont::NORMAL = 22; // 正常
- const int ConsoleFont::UN_UNDER_LINE = 24; // 去掉下滑线
- const int ConsoleFont::STOP_GLINT = 25; // 停止闪烁
- const int ConsoleFont::INVERSE_2 = 27;// 反色
- const int ConsoleFont::FORE_GROUND_BLACK = 30;// 前景,黑色
- const int ConsoleFont::FORE_GROUND_RED = 31;// 前景,红色
- const int ConsoleFont::FORE_GROUND_GREEN = 32;// 前景,绿色
- const int ConsoleFont::FORE_GROUND_ORANGE = 33;// 前景,黄色
- const int ConsoleFont::FORE_GROUND_BLUE = 34; //前景,篮色
- const int ConsoleFont::FORE_GROUND_PURPLE = 35; //前景,紫色
- const int ConsoleFont::FORE_GROUND_CYAN = 36; //前景,青色
- const int ConsoleFont::FORE_GROUND_WHITE = 37; //前景,白色
- const int ConsoleFont::BACK_GROUND_BLACK = 40;// 背景,黑色
- const int ConsoleFont::BACK_GROUND_RED = 41;// 背景,红色
- const int ConsoleFont::BACK_GROUND_GREEN = 42;// 背景,绿色
- const int ConsoleFont::BACK_GROUND_ORANGE = 43;// 背景,黄色
- const int ConsoleFont::BACK_GROUND_BLUE = 44; //背景,篮色
- const int ConsoleFont::BACK_GROUND_PURPLE = 45; //背景,紫色
- const int ConsoleFont::BACK_GROUND_CYAN = 46; //背景,青色
- const int ConsoleFont::BACK_GROUND_WHITE = 47; //背景,白色
- // 设置控制台字体样式
- const QString ConsoleFont::setConsoleFont(std::initializer_list<int> codes, QString msg)
- {
- if(codes.size() == 0) {
- return msg;
- }
- QString codeStr = "";
- int i = 0;
- for (auto code: codes)
- {
- if(i == 0) {
- codeStr = QString::number(code);
- } else {
- codeStr = codeStr + ";" + QString::number(code);
- }
- i++;
- }
- return "\033[" + codeStr + "m" + msg + "\033[0m";
- }
- const QString Log::INFO_FORMAT_TIME = "%time"; // 格式化输出日期表示
- const QString Log::INFO_FORMAT_LEVEL = "%level"; // 格式化输出日志级别表示
- const QString Log::INFO_FORMAT_CODE_FILE = "%file"; // 格式化输出代码文件地址表示
- const QString Log::INFO_FORMAT_CODE_LINE = "%line"; // 格式化输出代码所在行表示
- const QString Log::INFO_FORMAT_CODE_FUNCTION = "%function"; // 格式化输出代码所在方法函数表示
- const QString Log::INFO_FORMAT_CODE_MSG = "%msg"; // 格式化输出代码打印内容表示
- QMap<QtMsgType,QPair<QString, LogOutType>> Log::msgTypeMap = Log::initMsgTypeMap(); // 日志类型与日志标识、输出类型映射
- QMap<QtMsgType,std::initializer_list<int>> Log::levelFontMap = Log::initLevelFonts(); // 日志类型与字体样式设置映射
- QMap<LogSwitchoverType, QString> Log::logSwitchoverTypeMap = Log::initLogSwitchoverTypeMap(); // 初始化备份类型与字符的映射
- QFile* Log::outLogFile = new QFile("logs/system.log");// 日志输出文件
- QMap<QtMsgType, QFile*> Log::levelPaths = QMap<QtMsgType, QFile*>();// 不同级别的日志输出路径
- bool Log::isDistinguishLevel = false; // 是否区分日志级别输出
- QString Log::infoFormat = QString("%1 [%2] --- [%3:%4] %5: %6")
- .arg(Log::INFO_FORMAT_TIME, Log::INFO_FORMAT_LEVEL, Log::INFO_FORMAT_CODE_FILE,
- Log::INFO_FORMAT_CODE_LINE, Log::INFO_FORMAT_CODE_FUNCTION, Log::INFO_FORMAT_CODE_MSG); // 日志信息格式化
- QString Log::timeFormat = "yyyy-MM-dd hh:mm:ss:zzz"; // 时间格式化
- QFile* Log::logParamJsonFile = new QFile("logdata/logparam.json"); // 日志参数保存json文件
- LogSwitchoverType Log::logSwitchoverType = LogSwitchoverType::ALL_DAY; // 指定备份类型
- long long Log::switchoverNum = 1; // 指定备份时间或大小
- QDateTime Log::switchoverTime = QDateTime(); // 日志备份切换时间
- bool Log::isLoadLogSwitchoverSetting = false; // 是否已经加载日志备份设置
- CallBackInfoSafeList Log::pCallbacks = CallBackInfoSafeList(); // 回调函数集合
- // 设置日志输出内容格式化
- void Log::setFormat(QString infoFormat, QString timeFormat)
- {
- if(infoFormat.trimmed().isEmpty()) {
- Log::printSystemLog("error", "设置日志格式化infoFormat为空,不进行设置");
- return;
- }
- if(!isContainInfoFormat(infoFormat)) {
- Log::printSystemLog("error", "设置日志格式化infoFormat不包含关键词:"+Log::INFO_FORMAT_CODE_MSG+",不进行设置");
- return;
- }
- if(timeFormat.trimmed().isEmpty()) {
- Log::printSystemLog("error", "设置日志格式化timeFormat为空,不进行设置");
- return;
- }
- Log::infoFormat = infoFormat;
- Log::timeFormat = timeFormat;
- Log::printSystemLog("info", "设置日志输出内容格式化:"+infoFormat+",日期格式:"+ timeFormat);
- }
- // 设置日志类型对应的字体样式
- void Log::setLevelFont(QtMsgType type, std::initializer_list<int> levelFont)
- {
- Log::levelFontMap.insert(type, levelFont);
- Log::printSystemLog("info", "设置日志级别"+msgTypeMap.value(type, QPair<QString, LogOutType>()).first+"样式");
- }
- // 设置输出路径
- void Log::setOutLogPath(QString outLogPath)
- {
- if(outLogPath.trimmed().isEmpty()) {
- Log::printSystemLog("error", "设置日志输出路径为空,不进行设置");
- return;
- }
- Log::outLogFile = new QFile(outLogPath);
- Log::printSystemLog("info", "设置日志输出路径:"+ outLogPath);
- // 如果要区分日志级别输出,则重新调用设置是否分日志级别输出
- if(Log::isDistinguishLevel) {
- Log::setDistinguishLevel(Log::isDistinguishLevel);
- }
- }
- // 设置日志备份参数json存储地址
- void Log::setOutLogParamJsonPath(QString logParamJsonPath)
- {
- if(logParamJsonPath.trimmed().isEmpty()) {
- Log::printSystemLog("error","设置日志备份参数json存储地址为空,不进行设置");
- return;
- }
- Log::logParamJsonFile = new QFile(logParamJsonPath);
- Log::printSystemLog("info","设置日志备份参数json存储地址:"+ logParamJsonPath);
- }
- // 设置日志切换类型和时间或大小
- void Log::setLogSwitchover(LogSwitchoverType logSwitchoverType, long long switchoverNum)
- {
- if(switchoverNum < 1) {
- Log::printSystemLog("error", "设置时间或大小切换限定:"+QString::number(switchoverNum)+",小于1,不进行设置");
- return;
- }
- Log::logSwitchoverType = logSwitchoverType;
- Log::switchoverNum = switchoverNum;
- Log::printSystemLog("info","设置日志切换类型:"+ Log::logSwitchoverTypeMap.value(logSwitchoverType,"")+",时间或大小切换限定:"+QString::number(switchoverNum));
- }
- // 是否分日志级别输出
- void Log::setDistinguishLevel(bool isDistinguishLevel)
- {
- // 关闭已经打开的流,和删除已经设置的文件
- for(QtMsgType type : Log::levelPaths.keys()) {
- QFile* file = Log::levelPaths.value(type);
- if(file->isOpen()) {
- file->close();
- }
- if(file->exists()) {
- file->remove();
- }
- }
- // 清空映射关系
- Log::levelPaths.clear();
- // 设置是否分日志级别输出
- Log::isDistinguishLevel = isDistinguishLevel;
- // 如果分日志级别输出,则创建对应的文件和打开文件
- if(isDistinguishLevel) {
- // 关闭默认输出路径
- if(outLogFile->isOpen()) {
- outLogFile->close();
- }
- // 根据设置的输出文件路径构造不同级别的文件
- QFileInfo fileInfo = QFileInfo(Log::outLogFile->fileName());
- QString fileName = fileInfo.fileName();
- QDir dir = fileInfo.absoluteDir();
- if(!dir.exists()) {
- dir.mkdir(dir.absolutePath());
- }
- QMap<QtMsgType, QString> prefixMap = QMap<QtMsgType, QString>();
- prefixMap.insert(QtDebugMsg, "debug_");
- //一般信息文件路径
- prefixMap.insert(QtInfoMsg, "info_");
- //一般的警告文件路径
- prefixMap.insert(QtWarningMsg, "warn_");
- //严重错误文件路径
- prefixMap.insert(QtCriticalMsg, "critical_");
- //致命错误文件路径
- prefixMap.insert(QtFatalMsg, "fail_");
- for(QtMsgType type : prefixMap.keys()) {
- //调试信息文件路径
- QString filePath = dir.absoluteFilePath(prefixMap.value(type) + fileName);
- QFile* file = new QFile(filePath);
- Log::levelPaths.insert(type, file);
- }
- Log::printSystemLog("info", "已设置分日志级别输出,构建分日志文件成功");
- }
- }
- // 日志注册函数
- void Log::messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
- {
- // 加载日志和写入相关联配置
- Log::loadLogSwitchoverSetting();
- // 下面开始解析信息
- QString txtMessage = "";
- QString nowTime = QDateTime::currentDateTime().toString(Log::timeFormat.trimmed().isEmpty() ? "yyyy-MM-dd hh:mm:ss:zzz" : Log::timeFormat);
- if(Log::msgTypeMap.contains(type)) {
- QPair<QString, LogOutType> infoPair = Log::msgTypeMap.value(type, Log::msgTypeMap.value(QtInfoMsg));
- // 格式化信息
- txtMessage = !Log::isContainInfoFormat() ? QString("%1 [%2] --- [%3:%4] %5: %6")
- .arg(Log::INFO_FORMAT_TIME, Log::INFO_FORMAT_LEVEL, Log::INFO_FORMAT_CODE_FILE,
- Log::INFO_FORMAT_CODE_LINE, Log::INFO_FORMAT_CODE_FUNCTION, Log::INFO_FORMAT_CODE_MSG)
- : infoFormat;
- txtMessage = Log::replace(txtMessage, Log::INFO_FORMAT_TIME, nowTime);
- txtMessage = Log::replace(txtMessage, Log::INFO_FORMAT_LEVEL, infoPair.first);
- txtMessage = Log::replace(txtMessage, Log::INFO_FORMAT_CODE_FILE, context.file);
- txtMessage = Log::replace(txtMessage, Log::INFO_FORMAT_CODE_LINE, QString::number(context.line));
- txtMessage = Log::replace(txtMessage, Log::INFO_FORMAT_CODE_FUNCTION, context.function);
- txtMessage = Log::replace(txtMessage, Log::INFO_FORMAT_CODE_MSG, msg);
- // 根据不同日志级别设置字体样式
- QString txtFontMessage = ConsoleFont::setConsoleFont(Log::levelFontMap.value(type, {ConsoleFont::DEFAULT}), txtMessage);
- // 根据输出日志类型选择输出到标准流或者是标准错误流
- if(infoPair.second == LogOutType::STANDARD_OUTPUT) {
- std::cout << txtFontMessage.toLocal8Bit().constData() << std::endl;
- } else {
- std::cerr << txtFontMessage.toLocal8Bit().constData() << std::endl;
- }
- // 写入到文件中
- writeLog(txtMessage, type);
- // 回调函数
- for(CallBackInfo callBack : Log::pCallbacks.getList()) {
- LogInfoCallBackHandler hander = callBack.hander;
- hander(type, context, msg, txtMessage, callBack.context);
- }
- if(type == QtFatalMsg) {
- Log::printSystemLog("error", "致命错误,立即终止:"+ msg);
- // 致命错误立即终止
- abort();
- }
- } else {
- std::cout << msg.toLocal8Bit().constData() << std::endl;
- }
- }
- // 注册回调函数
- LogInfoCallBackHandler Log::registLogInfoCallBack(QString unique, LogInfoCallBackHandler hander, void *context)
- {
- // 如果已经存在已经注册过的回调函数,则不在进行注册
- for(CallBackInfo info : pCallbacks.getList()) {
- if(info.unique == unique) {
- Log::printSystemLog("warn", "已经注册过该日志回调函数:" + unique+",不在进行注册操作");
- return hander;
- }
- }
- CallBackInfo callBackInfo(unique, hander, context);
- Log::pCallbacks.add(callBackInfo);
- Log::printSystemLog("info", "注册日志回调函数:" + unique + "成功");
- return hander;
- }
- // 初始化不同日志级别的输出级别标识和输出流
- QMap<QtMsgType,QPair<QString, LogOutType>> Log::initMsgTypeMap()
- {
- QMap<QtMsgType,QPair<QString, LogOutType>> msgTypeMap;
- //调试信息提示
- msgTypeMap.insert(QtDebugMsg,QPair<QString, LogOutType>("Debug", LogOutType::STANDARD_OUTPUT));
- //一般信息提示
- msgTypeMap.insert(QtInfoMsg,QPair<QString, LogOutType>("Info", LogOutType::STANDARD_OUTPUT));
- //一般的警告提示
- msgTypeMap.insert(QtWarningMsg,QPair<QString, LogOutType>("Waring", LogOutType::STANDARD_OUTPUT));
- //严重错误提示
- msgTypeMap.insert(QtCriticalMsg,QPair<QString, LogOutType>("Critical", LogOutType::STANDARD_ERROR_OUTPUT));
- //致命错误提示
- msgTypeMap.insert(QtFatalMsg,QPair<QString, LogOutType>("Fatal", LogOutType::STANDARD_ERROR_OUTPUT));
- return msgTypeMap;
- }
- // 初始化不同日志级别的字体样式参数
- QMap<QtMsgType, std::initializer_list<int>> Log::initLevelFonts()
- {
- QMap<QtMsgType, std::initializer_list<int>> levelColorMap;
- //调试信息字体样式
- levelColorMap.insert(QtDebugMsg,{ConsoleFont::FORE_GROUND_GREEN});
- //一般信息字体样式
- levelColorMap.insert(QtInfoMsg,{ConsoleFont::DEFAULT});
- //一般的警告信息字体样式
- levelColorMap.insert(QtWarningMsg,{ConsoleFont::FORE_GROUND_ORANGE});
- //严重错误字体样式
- levelColorMap.insert(QtCriticalMsg,{ConsoleFont::FORE_GROUND_RED, ConsoleFont::UNDER_LINE});
- //致命错误字体样式
- levelColorMap.insert(QtFatalMsg,{ConsoleFont::FORE_GROUND_RED, ConsoleFont::BOLD});
- return levelColorMap;
- }
- // 初始化备份类型与字符的映射
- QMap<LogSwitchoverType, QString> Log::initLogSwitchoverTypeMap()
- {
- QMap<LogSwitchoverType, QString> logSwitchoverTypeMap = QMap<LogSwitchoverType, QString>();
- logSwitchoverTypeMap.insert(LogSwitchoverType::ALL_DAY, "all_day");
- logSwitchoverTypeMap.insert(LogSwitchoverType::TIME_PERIOD, "time_period");
- logSwitchoverTypeMap.insert(LogSwitchoverType::FILE_SIZE, "file_size");
- return logSwitchoverTypeMap;
- }
- // 写入文件
- void Log::writeLog(QString str, QtMsgType msgType)
- {
- // 判断是否进行备份切换
- if(Log::logSwitchoverType == LogSwitchoverType::ALL_DAY || Log::logSwitchoverType == LogSwitchoverType::TIME_PERIOD) {
- // 如果当前时间超过了切换时间,则进行切换
- if(QDateTime::currentDateTime().operator >(Log::switchoverTime)) {
- // 备份日志文件
- Log::copyLogOutFile(msgType);
- }
- } else {
- long long fileSize = 0;
- if(Log::isDistinguishLevel) {
- // 计算所有日志文件大小之和
- for(QtMsgType type: Log::levelPaths.keys()) {
- QFile* msgFile = Log::levelPaths.value(type);
- fileSize = fileSize + msgFile->size();
- }
- } else {
- fileSize = Log::outLogFile->size();
- }
- // 当文件大小达到配置限制,则备份文件,因为size返回的是byte,而switchoverNum的单位是kb,所以需要乘以1024
- if(fileSize > (Log::switchoverNum*1024)) {
- // 备份日志文件
- Log::copyLogOutFile(msgType);
- }
- }
- // 写入日志到相应文件
- if(Log::isDistinguishLevel) {
- QFile* file = Log::levelPaths.value(msgType);
- if(!file->isOpen()) {
- file->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);
- }
- file->write((str+"\n").toUtf8());
- file->flush();
- } else {
- if(!Log::outLogFile->isOpen()) {
- Log::outLogFile->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);
- }
- Log::outLogFile->write((str+"\n").toUtf8());
- Log::outLogFile->flush();
- }
- }
- // 备份日志文件
- void Log::copyLogOutFile(QtMsgType msgType)
- {
- QString nowTimeStr = QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz");
- QList<bool> copyStatus;
- QList<QtMsgType> msgTypes;
- if(Log::isDistinguishLevel) {
- // 创建备份文件夹
- QFile* file = Log::levelPaths.value(msgType);
- QFileInfo fileInfo = QFileInfo(file->fileName());
- QDir dir = fileInfo.absoluteDir();
- QString copyDirPath = dir.absoluteFilePath(nowTimeStr+"log");
- if(!dir.exists(copyDirPath)) {
- dir.mkdir(copyDirPath);
- }
- QDir copyDir(copyDirPath);
- // 将日志文件备份到备份文件夹下
- for(QtMsgType type: Log::levelPaths.keys()) {
- QFile* msgFile = Log::levelPaths.value(type);
- QFileInfo fileInfo = QFileInfo(msgFile->fileName());
- bool isSucceed = Log::copy(fileInfo.absoluteFilePath(), copyDir.absoluteFilePath(fileInfo.fileName()));
- copyStatus.append(isSucceed);
- if(isSucceed) {
- msgTypes.append(type);
- }
- Log::printSystemLog("info", "拷贝文件:"+fileInfo.absoluteFilePath() + "到"+ copyDir.absoluteFilePath(fileInfo.fileName())+(isSucceed ? "成功":"失败"));
- }
- } else {
- // 创建备份文件夹
- QFileInfo fileInfo = QFileInfo(Log::outLogFile->fileName());
- QDir dir = fileInfo.absoluteDir();
- QString copyDirPath = dir.absoluteFilePath(nowTimeStr+"log");
- if(!dir.exists(copyDirPath)) {
- dir.mkdir(copyDirPath);
- }
- QDir copyDir(copyDirPath);
- // 将日志文件备份到备份文件夹下
- bool isSucceed = Log::copy(fileInfo.absoluteFilePath(), copyDir.absoluteFilePath(fileInfo.fileName()));
- copyStatus.append(isSucceed);
- Log::printSystemLog("info", "拷贝文件:"+fileInfo.absoluteFilePath() + "到"+ copyDir.absoluteFilePath(fileInfo.fileName())+(isSucceed ? "成功":"失败"));
- }
- // 备份成功与否提示信息
- if(!copyStatus.contains(false)) {
- Log::printSystemLog("info", "备份日志文件成功");
- } else {
- Log::printSystemLog("error", "备份部分日志文件失败!");
- }
- // 如果备份全部成功,则清空日志文件和写入新的切换时间到日志参数配置文件
- if(Log::isDistinguishLevel) {
- for(QtMsgType type: msgTypes) {
- QFile* msgFile = Log::levelPaths.value(type);
- QFileInfo fileInfo = QFileInfo(msgFile->fileName());
- if(msgFile->resize(0)) {
- Log::printSystemLog("info", "清空日志文件内容成功:"+fileInfo.absoluteFilePath());
- } else {
- Log::printSystemLog("error", "清空日志文件内容失败:"+fileInfo.absoluteFilePath());
- }
- }
- } else {
- if(!copyStatus.contains(false)) {
- QFileInfo fileInfo = QFileInfo(Log::outLogFile->fileName());
- if(Log::outLogFile->resize(0)) {
- Log::printSystemLog("info", "清空日志文件内容成功:"+fileInfo.absoluteFilePath());
- } else {
- Log::printSystemLog("error", "清空日志文件内容失败:"+fileInfo.absoluteFilePath());
- }
- }
- }
- // 备份完成之后更新再次需要备份的时间,并写入备份参数配置文件中
- Log::writeLogParamJson();
- }
- // 加载备份策略的设置
- void Log::loadLogSwitchoverSetting()
- {
- if(Log::isLoadLogSwitchoverSetting) {
- return;
- }
- logSwitchoverSettingHander();
- Log::isLoadLogSwitchoverSetting = true;
- // 如果需要分日志输出,则先创建分日志文件
- if(Log::isDistinguishLevel) {
- for(QtMsgType type: Log::levelPaths.keys()) {
- QFile* file = Log::levelPaths.value(type);
- // 如果文件所在文件夹不存在则创建文件夹
- QFileInfo fileInfo = QFileInfo(file->fileName());
- QDir dir = fileInfo.absoluteDir();
- if(!dir.exists()) {
- dir.mkdir(dir.absolutePath());
- }
- file->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);
- }
- } else {
- // 如果文件所在文件夹不存在则创建文件夹
- QFileInfo fileInfo = QFileInfo(Log::outLogFile->fileName());
- QDir dir = fileInfo.absoluteDir();
- if(!dir.exists()) {
- dir.mkdir(dir.absolutePath());
- }
- Log::outLogFile->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);
- }
- }
- // 备份参数处理,并同步更新json文件中的数据到内存,或将设置参数写入参数文件
- void Log::logSwitchoverSettingHander()
- {
- if(!Log::logParamJsonFile->exists()) { // 文件不存在则创建日志备份参数json文件并将参数写入文件
- Log::writeLogParamJson();
- } else {
- if(Log::logParamJsonFile->open(QIODevice::ReadWrite | QIODevice::Text)) { // 打开文件成功则读取json文件中的配置到内存中
- QByteArray json = Log::logParamJsonFile->readAll().trimmed();
- Log::logParamJsonFile->close();
- QJsonParseError jsonError;
- QJsonDocument jsonDoc(QJsonDocument::fromJson(json, &jsonError));
- if(jsonError.error == QJsonParseError::NoError)
- {
- QJsonObject rootObj = jsonDoc.object();
- QString logSwitchoverTypeStr = rootObj.value("logSwitchoverType").toString("");
- QString switchoverNumberStr = rootObj.value("switchoverNum").toString("");
- long long switchoverNumber = switchoverNumberStr.trimmed().isEmpty() ? 1: switchoverNumberStr.toLongLong();
- QString switchoverTimeStr = rootObj.value("switchoverTime").toString("");
- LogSwitchoverType switchoverType;
- QDateTime switchoverTime;
- for(LogSwitchoverType type: Log::logSwitchoverTypeMap.keys()) {
- if(Log::logSwitchoverTypeMap.value(type) == logSwitchoverTypeStr) {
- switchoverType = type;
- if(type == LogSwitchoverType::ALL_DAY) {
- switchoverTime = QDateTime::fromString(switchoverTimeStr, "yyyy-MM-dd");
- } else if(type == LogSwitchoverType::TIME_PERIOD) {
- switchoverTime = QDateTime::fromString(switchoverTimeStr, "yyyy-MM-dd hh:mm:ss");
- }
- break;
- }
- }
- Log::printSystemLog("info", "读取转换备份配置Json文件成功:"+logParamJsonFile->fileName()+",内容是:"+QString(json));
- // 如果不和默认的一样,则拷贝一份,将默认的参数写入文件,这么做的目的是用户在之前设置过日志切换类型和时间或大小,后面又修改代码后又没有进行相应的设置,则需要用到默认设置
- if(switchoverType != Log::logSwitchoverType || switchoverNumber != Log::switchoverNum) {
- Log::printSystemLog("warn", "读取配置和设置的设置过日志切换类型和时间或大小不同,写入最新配置:"+logParamJsonFile->fileName());
- Log::writeLogParamJson();
- } else {
- Log::logSwitchoverType = switchoverType;
- Log::switchoverNum = switchoverNumber;
- Log::switchoverTime = switchoverTime;
- }
- } else { // 解析失败,则将内存中日志备份参数写入文件
- Log::printSystemLog("error", "转换备份配置Json文件失败:"+logParamJsonFile->fileName()+",已转为默认配置");
- Log::writeLogParamJson();
- }
- } else { // 打开失败,则将内存中日志备份参数写入文件
- Log::printSystemLog("error", "打开备份配置Json文件失败:"+logParamJsonFile->fileName()+",已转为默认配置");
- Log::writeLogParamJson();
- }
- }
- }
- // 写入备份参数到日志备份配置json文件中
- void Log::writeLogParamJson()
- {
- QDateTime nowTime = QDateTime::currentDateTime();
- QString switchoverTimeStr = "";
- if(Log::logSwitchoverType == LogSwitchoverType::ALL_DAY) {
- // 指定天数之后
- Log::switchoverTime = nowTime.addDays(Log::switchoverNum);
- switchoverTimeStr = switchoverTime.toString("yyyy-MM-dd");
- } else if(Log::logSwitchoverType == LogSwitchoverType::TIME_PERIOD) {
- // 指定秒之后
- Log::switchoverTime = nowTime.addSecs(Log::switchoverNum);
- switchoverTimeStr = nowTime.toString("yyyy-MM-dd hh:mm:ss");
- }
- QJsonObject jsonObject;//构建json对象json
- jsonObject.insert("logSwitchoverType", Log::logSwitchoverTypeMap.value(Log::logSwitchoverType, ""));
- jsonObject.insert("switchoverNum", QString::number(Log::switchoverNum));
- jsonObject.insert("switchoverTime", switchoverTimeStr);
- QJsonDocument document;
- document.setObject(jsonObject);
- QString jsonStr(document.toJson(QJsonDocument::Indented));
- // 如果文件所在文件夹不存在则创建文件夹
- QFileInfo fileInfo = QFileInfo(Log::logParamJsonFile->fileName());
- QDir dir = fileInfo.absoluteDir();
- if(!dir.exists()) {
- dir.mkdir(dir.absolutePath());
- }
- if(Log::logParamJsonFile->open(QIODevice::WriteOnly | QIODevice::Text)) {
- Log::logParamJsonFile->write(jsonStr.toUtf8());
- Log::logParamJsonFile->flush();
- Log::logParamJsonFile->close();
- printSystemLog("info", "写入备份日志参数到"+fileInfo.absoluteFilePath()+",成功;参数:"+jsonStr);
- } else {
- printSystemLog("error", "写入备份日志参数到"+fileInfo.absoluteFilePath()+",失败");
- }
- }
- // 拷贝文件
- bool Log::copy(QString srcFilepPath, QString targetFilePath)
- {
- QFile srcFile(srcFilepPath);
- QFile targetFile(targetFilePath);
- if(srcFile.exists()) {
- if(targetFile.exists()) {
- targetFile.remove();
- }
- return srcFile.copy(targetFilePath);
- }
- Log::printSystemLog("error", "需要备份文件不存在:" + srcFilepPath);
- return false;
- }
- // 替换字符串中的子字符串
- QString Log::replace(QString src, QString before, QString after)
- {
- if(src.isEmpty()) {
- return src;
- }
- if(!src.contains(before)) {
- return src;
- }
- QString repalceAfter = src;
- while (repalceAfter.contains(before)) {
- repalceAfter = repalceAfter.replace(src.indexOf(before), before.size(), after);
- }
- return repalceAfter;
- }
- // 是否包含必要的格式化信息
- bool Log::isContainInfoFormat(QString mInfoFormat)
- {
- QString infoFormat = Log::infoFormat;
- if(!mInfoFormat.trimmed().isEmpty()) {
- infoFormat = mInfoFormat;
- }
- if(infoFormat.trimmed().isEmpty()) {
- return false;
- }
- if(!infoFormat.contains(Log::INFO_FORMAT_CODE_MSG)) {
- return false;
- }
- return true;
- }
- // 日志系统信息样式及打印
- void Log::printSystemLog(QString level, QString msg)
- {
- if(level.trimmed().toLower() == "info") {
- QString info = ConsoleFont::setConsoleFont({ConsoleFont::FORE_GROUND_BLUE,ConsoleFont::BACK_GROUND_CYAN,ConsoleFont::BOLD}, msg);
- std::cout << info.toLocal8Bit().constData() << std::endl;
- } else if(level.trimmed().toLower() == "warn") {
- QString info = ConsoleFont::setConsoleFont({ConsoleFont::FORE_GROUND_ORANGE,ConsoleFont::BACK_GROUND_PURPLE,ConsoleFont::BOLD}, msg);
- std::cout << info.toLocal8Bit().constData() << std::endl;
- } else if(level.trimmed().toLower() == "error") {
- QString info = ConsoleFont::setConsoleFont({ConsoleFont::FORE_GROUND_RED,ConsoleFont::BACK_GROUND_GREEN,ConsoleFont::BOLD}, msg);
- std::cout << info.toLocal8Bit().constData() << std::endl;
- } else {
- QString info = ConsoleFont::setConsoleFont({ConsoleFont::FORE_GROUND_BLACK,ConsoleFont::BACK_GROUND_CYAN,ConsoleFont::BOLD}, msg);
- std::cout << info.toLocal8Bit().constData() << std::endl;
- }
- }
|