C++实现的单例模式日志类

2024-05-26 08:28:39 浏览数 (2)

在实际生产中,日志是非常重要的调试工具,日志内容至少需要包括时间戳、日志级别、日志内容

推荐的日志库有:

google/glog: C implementation of the Google logging module (github.com)

Apache Log4cxx: Apache Log4cxx

自己实现的话, 日志内容应该包括,精确到微秒的时间戳,日志级别(DEBUG / INFO / WARN / ERROR / FATAL),日志写入时的代码文件名,代码行号和函数名,例如

代码语言:javascript复制
2024-05-25 23:46:07.998429 [FATAL] This is a fatal message (File=C:/Users/Yezi/Desktop/Logger/main.cpp Function=main Line=9)

并且我希望日志是这样使用的

代码语言:javascript复制
#include "logger.h"

int main() {
    Logger::InitLogger("logfile.txt");
    LOG(LogLevel::DEBUG, "This is a debug message");
    LOG(LogLevel::INFO, "This is an info message");
    LOG(LogLevel::WARN, "This is a warning message");
    LOG(LogLevel::ERROR, "This is an error message");
    LOG(LogLevel::FATAL, "This is a fatal message");
    return 0;
}

而不是这样使用的

代码语言:javascript复制
int main() {
    Logger logger("logfile.txt");

    // 示例使用
    LOG(logger, LogLevel::DEBUG, "This is a debug message");
    LOG(logger, LogLevel::INFO, "This is an info message");
    LOG(logger, LogLevel::WARN, "This is a warning message");
    LOG(logger, LogLevel::ERROR, "This is an error message");
    LOG(logger, LogLevel::FATAL, "This is a fatal message");

    return 0;
}

这意味着我们需要一个单例模式的实现,需要将类实例静态化,由一个静态函数返回类实例的引用,由于静态变量只会初始化一次,所以每次返回的都是同一个实例 同时我们希望能够保留可以更改类实例初始化的参数,例如日志文件名,因此需要一个初始化的静态函数来进行类实例的初始化

代码语言:javascript复制
//
// Created by YEZI on 2024/5/25.
//

#ifndef LOGGER_H
#define LOGGER_H

#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <chrono>
#include <ctime>
#include <iomanip>
#include <sstream>

// 定义日志级别
enum class LogLevel { DEBUG, INFO, WARN, ERROR, FATAL };

class Logger {
private:
    int fd_ = -1;
    // 获取当前时间戳
    static std::string getCurrentTime() {
        // 获取当前时间点
        auto now = std::chrono::system_clock::now();
        // 将时间点转换为time_t
        auto now_time_t = std::chrono::system_clock::to_time_t(now);
        // 获取tm结构体
        std::tm time_info = *std::localtime(&now_time_t);
        // 构造时间字符串
        std::ostringstream oss;
        oss << std::put_time(&time_info, "%Y-%m-%d %H:%M:%S"); // 格式化时间
        // 获取微秒部分
        auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(
                                now.time_since_epoch()) % 1000000;
        oss << "." << std::setfill('0') << std::setw(6) << microseconds.count(); // 微秒部分
        return oss.str();
    }

    // 私有化构造函数
    explicit Logger(const char *filename) {
        // 打开日志文件
        fd_ = open(filename, O_WRONLY | O_CREAT | O_APPEND, 0666);
        if (fd_ == -1) {
            std::cerr << "Failed to open log filen";
        }
    }

public:
    ~Logger() {
        // 关闭日志文件
        if (fd_ != -1) {
            close(fd_);
        }
    }

    //初始化日志文件
    static void InitLogger(const char *filename) {
        getInstance(filename);
    }

    // 禁用拷贝构造函数和赋值运算符
    Logger(const Logger &) = delete;

    Logger &operator=(const Logger &) = delete;

    // 获取 Logger 实例的静态方法
    static Logger &getInstance(const char *filename = nullptr) {
        // 静态变量只会初始化一次
        static Logger instance(filename);
        return instance;
    }

    // 写日志函数
    void log(LogLevel level, const char *message, const char *file, int line, const char *function) const {
        std::string logLevelStr;
        switch (level) {
            case LogLevel::DEBUG:
                logLevelStr = "DEBUG";
                break;
            case LogLevel::INFO:
                logLevelStr = "INFO";
                break;
            case LogLevel::WARN:
                logLevelStr = "WARN";
                break;
            case LogLevel::ERROR:
                logLevelStr = "ERROR";
                break;
            case LogLevel::FATAL:
                logLevelStr = "FATAL";
                break;
        }

        // 构建日志消息
        std::string logMessage = getCurrentTime()   " ["   logLevelStr   "] "   message  
                                 " (File="   file   " Function="   function   " Line="   std::to_string(line)   ")n";

        // 写入日志到文件
        write(fd_, logMessage.c_str(), logMessage.size());
    }
};

// 宏定义简化日志调用
#define LOG(level, message) Logger::getInstance().log(level, message, __FILE__, __LINE__, __FUNCTION__)

#endif //LOGGER_H

代码维护在GitHub

MaolinYe/Logger: C 实现的日志类,记录日志写入时的时间,可选的日志级别(DEBUG / INFO / WARN / ERROR / FATAL),日志内容,日志写入时的代码文件,代码行号和函数名 (github.com)

0 人点赞