/*-------------------------------------------------------------------------- * 基于此我们就可以写出我们自定义的日志系统了,我写的这个日志系统具有以下特点: 1、支持设置日志输出路径 2、支持日志打印格式设置 3、支持不同日志级别的不同样式设置 4、支持3种日志备份策略,采用延迟策略,不是用定时器实现周期备份,而是在具体打印内容时才触发,这么做的目的是减少定时的开销 5、支持分日志类型备份日志 6、支持备份策略参数的json文件地址存储自定义 7、支持回调函数注册,便于一些想将日志输出到自己项目界面展示 --------------------------------------------------------------------------------*/ #include "log.h" #include #include #include #include #include #include #include #include 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 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> Log::msgTypeMap = Log::initMsgTypeMap(); // 日志类型与日志标识、输出类型映射 QMap> Log::levelFontMap = Log::initLevelFonts(); // 日志类型与字体样式设置映射 QMap Log::logSwitchoverTypeMap = Log::initLogSwitchoverTypeMap(); // 初始化备份类型与字符的映射 QFile* Log::outLogFile = new QFile("logs/system.log");// 日志输出文件 QMap Log::levelPaths = QMap();// 不同级别的日志输出路径 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 levelFont) { Log::levelFontMap.insert(type, levelFont); Log::printSystemLog("info", "设置日志级别"+msgTypeMap.value(type, QPair()).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 prefixMap = QMap(); 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 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> Log::initMsgTypeMap() { QMap> msgTypeMap; //调试信息提示 msgTypeMap.insert(QtDebugMsg,QPair("Debug", LogOutType::STANDARD_OUTPUT)); //一般信息提示 msgTypeMap.insert(QtInfoMsg,QPair("Info", LogOutType::STANDARD_OUTPUT)); //一般的警告提示 msgTypeMap.insert(QtWarningMsg,QPair("Waring", LogOutType::STANDARD_OUTPUT)); //严重错误提示 msgTypeMap.insert(QtCriticalMsg,QPair("Critical", LogOutType::STANDARD_ERROR_OUTPUT)); //致命错误提示 msgTypeMap.insert(QtFatalMsg,QPair("Fatal", LogOutType::STANDARD_ERROR_OUTPUT)); return msgTypeMap; } // 初始化不同日志级别的字体样式参数 QMap> Log::initLevelFonts() { QMap> 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 Log::initLogSwitchoverTypeMap() { QMap logSwitchoverTypeMap = QMap(); 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 copyStatus; QList 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; } }