功能拆分需求分析

流程图


开发环境工具:vs2022,HeidiSQL,mysql-8.0.31-winx64
层级:

.h文件
#pragma once
#include <string>
#include <fstream>
#include <vector>
#include <mysql.h>
// 定义宏,方便写入日志,使用可变长参数列表
#define LOGGER_INFO(fmt, ...) Logger::WriteLogger(__FILE__, __FUNCTION__, __LINE__, "INFO", fmt, ##__VA_ARGS__)
#define LOGGER_ERROR(fmt, ...) Logger::WriteLogger(__FILE__, __FUNCTION__, __LINE__, "ERROR", fmt, ##__VA_ARGS__)
#define LOGGER_WARNING(fmt, ...) Logger::WriteLogger(__FILE__, __FUNCTION__, __LINE__, "WARNING", fmt, ##__VA_ARGS__)
#define LOGGER_FATAL(fmt, ...) Logger::WriteLogger(__FILE__, __FUNCTION__, __LINE__, "FATAL", fmt, ##__VA_ARGS__)
#define LOGGER_DEBUG(fmt, ...) Logger::WriteLogger(__FILE__, __FUNCTION__, __LINE__, "DEBUG", fmt, ##__VA_ARGS__)
class Logger {
public:
// 写入日志的函数
static void
WriteLogger(const char* file_name, const char* function_name, int line_number, const char* Log_level, const char* fmt, ...);
// 设置查询者的ID
static void SetUserID(int userID);
static void InsertLogIntoDatabase(const std::string& user_name, const std::string& date,
const std::string& function_name, int line_number, const std::string& Log_level,
const std::string& description ,const std::string& file_name);
static int GetUserID()
{
return userID;
}
Logger(const std::string& databaseConnectionString);
~Logger();
// 写入日志到文件
void WriteLogger(const std::string& log_info, int userID);
private:
// 获取当前时间的函数
static std::string GetCurrentTime_(const std::string& fmt);
// 获取日志输出文件夹下的所有日志文件的函数
static std::vector<std::string> GetLogFiles();
// 生成新的日志文件名的函数
static std::string GenLogFileName();
// 字节换算单位
static const int BYTE_UNIT = 1024;
// 最大的日志文件个数
static const int LOG_FILE_MAX_NUM = 4;
// 日志文件最大大小
static const int LOG_FILE_MAX_SIZE = 10 * BYTE_UNIT * BYTE_UNIT;
// 日志可变长参数的长度
static const int LOG_MSG_MAX_LEN = 512;
// 一条完整的日志最大长度
static const int LOG_FULL_MSG_MAX_LEN = 1024;
// 日志中时间字符串的长度
static const int LOG_TIME_BUFFER_LEN = 32;
// 日志写入文件流
static std::ofstream s_ofs;
// 项目名称
static std::string s_projectName;
// 日志输出的文件夹路径
static std::string s_logDirPath;
// 日志输出的文件夹名称
static std::string s_logDirName;
// 检查并处理日志数量限制的函数定义
static void CheckAndHandleLogLimitation(int maxLogs);
// 记录查询者的ID
static int userID;
static const int maxLogCount = 10;
static int ExecuteCountQuery(MYSQL* mysql, const std::string& query);
static void ExecuteDeleteQuery(MYSQL* mysql, const std::string& query);
static void ExecuteInsertQuery(MYSQL* mysql, const std::string& query);
MYSQL* mysql; // MySQL连接对象
};
cpp源文件
#include "yejing_log.h"
#include <vector>
#include <cstdarg>
#include <ctime>
#include <algorithm>
#include <sys/stat.h>
#include <io.h>
#include <mysql.h>
#include <iostream>
#include <sys/stat.h>
#include <direct.h>
using namespace std;
ofstream Logger::s_ofs; // 静态成员变量的初始化
string Logger::s_projectName("yejingmianbanchang"); // 项目名称
string Logger::s_logDirPath; // 日志输出的文件夹路径
string Logger::s_logDirName("output"); // 日志输出的文件夹名称
int Logger::userID = 0;
// 写入日志的函数的实现
void Logger::WriteLogger(const char* file_name, const char* function_name, int line_number, const char* Log_level, const char* fmt, ...)
{
// 获取当前的日志文件夹路径
string currentFilePath = __FILE__; // __FILE__是预定义宏,表示当前文件的路径
size_t pos = currentFilePath.find_last_of("/\\"); // 找到最后一个路径分隔符
s_logDirPath = currentFilePath.substr(0, pos) + "/" + s_logDirName; // 构造日志文件夹路径
if (!s_ofs.is_open()) { // 如果日志文件还没有打开
struct stat dirInfo {}; // 用于存储文件夹信息的结构体
string logFileName; // 日志文件名
// 判断日志文件夹是否存在,如果不存在,则创建一个文件夹
if (stat(s_logDirPath.c_str(), &dirInfo) != 0) { // stat函数用于获取文件信息,返回0表示成功
_mkdir(s_logDirPath.c_str()); // 如果文件夹不存在,则创建一个新的文件夹
logFileName = const_cast<char*>(GenLogFileName().c_str()); // 生成新的日志文件名
}
else { // 如果文件夹已经存在
const vector<string>& files = GetLogFiles(); // 获取所有的日志文件
if (files.empty()) { // 如果没有日志文件,则创建一个新的
logFileName = const_cast<char*>(GenLogFileName().c_str());
}
else { // 如果有日志文件,则找到最近的那个日志文件
logFileName = files.back();
}
}
s_ofs.open(s_logDirPath + "/" + logFileName, ios::app); // 打开日志文件,以追加的方式写入
}
// 解析可变长参数
va_list vaList;
va_start(vaList, fmt); // 初始化可变长参数列表
char logMsg[LOG_MSG_MAX_LEN] = { 0 }; // 存储日志信息的缓冲区
vsprintf_s(logMsg, fmt, vaList); // 格式化日志信息
va_end(vaList); // 结束可变长参数列表
// (1)构造一条完整的日志
// 2023-10-19 10:06:32 [login.c] [LoginCheck:50] [INFO] user admin login success
char* logFileName = const_cast<char*>(GenLogFileName().c_str());
char* p = const_cast<char*>(strrchr(file_name, '\\'));// 找到文件名中最后一个路径分隔符
char filePath[256];
strcpy_s(filePath, sizeof(filePath), file_name);
//char* p = strrchr(filePath, '\\');
if (p == nullptr) { // 如果没有找到,则找最后一个反斜杠
p = strrchr(filePath, '\\');
}
// (2)获取当前的时间
string currentTime = GetCurrentTime_("%Y-%m-%d %H:%M:%S"); // 获取当前时间
char fullMsg[LOG_FULL_MSG_MAX_LEN] = { 0 }; // 存储完整日志信息的缓冲区
sprintf_s(fullMsg, "%s [%s] [%s:%d] [%s] %s", currentTime.c_str(), p + 1, function_name, line_number, Log_level, logMsg); // 格式化完整日志信息
// 判断文件大小,如果超过最大大小,则把上个文件关闭,重新打开文件
if (s_ofs.tellp() >= LOG_FILE_MAX_SIZE) { // tellp函数用于获取当前写入指针的位置
s_ofs.close(); // 关闭当前日志文件
// 打开新的文件之前,要判断文件的个数,如果最大个数,则删除最远的那个日志文件
const vector<string>& files = GetLogFiles(); // 获取所有的日志文件
if (files.size() >= LOG_FILE_MAX_NUM) { // 如果已经达到最大数量,则删除最远的那个日志文件
string delFilePath = s_logDirPath + "/" + files.front();
remove(delFilePath.c_str());
}
st

最低0.47元/天 解锁文章
&spm=1001.2101.3001.5002&articleId=134313926&d=1&t=3&u=1b2406dfe58d4deabd8efca2a7f3d12d)
4086

被折叠的 条评论
为什么被折叠?



