日志生成封装导出备份及存入数据库(xx面板厂监控项目)

功能拆分需求分析

流程图

开发环境工具: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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值