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

server/2024/9/24 6:48:41/

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

推荐的日志库有:

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

 Apache Log4cxx: Apache Log4cxx

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

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)

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

#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;
}

而不是这样使用的

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;
}

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

//
// 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_tauto 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 file\n";}}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)


http://www.ppmy.cn/server/43034.html

相关文章

算法提高之线段树

算法提高之线段树 存储方式 线段树除了最后一层叶子节点以外是一个满二叉树类似堆的形式 因此可以用堆来存储线段树同时注意到 数组是可以模拟堆的 因此我们可以用一位数组来存储线段树 节点编号为u&#xff0c;对应左子树编号为2 * u&#xff0c;右子树编号为2 * u 1装逼一…

如何用 MoonBit 实现 diff?

你使用过 Unix 下的小工具 diff 吗&#xff1f; 没有也没关系&#xff0c;简而言之&#xff0c;它是一个比对两个文本文件之间有什么不同之处的工具。它的作用不止于此&#xff0c;Unix 下还有一个叫 patch 的小工具。 时至今日&#xff0c;很少有人手动为某个软件包打补丁了…

【全开源】答题考试系统源码(FastAdmin+ThinkPHP+Uniapp)

答题考试系统源码&#xff1a;构建高效、安全的在线考试平台 引言 在当今数字化时代&#xff0c;在线考试系统已成为教育机构和企业选拔人才的重要工具。一个稳定、高效、安全的答题考试系统源码是构建这样平台的核心。本文将深入探讨答题考试系统源码的关键要素&#xff0c;…

Golang | Leetcode Golang题解之第101题对称二叉树

题目&#xff1a; 题解&#xff1a; func isSymmetric(root *TreeNode) bool {u, v : root, rootq : []*TreeNode{}q append(q, u)q append(q, v)for len(q) > 0 {u, v q[0], q[1]q q[2:]if u nil && v nil {continue}if u nil || v nil {return false}if …

外卖系统关于redis使用解决高并发情况

1、如何配置redis 在java中操作redis 操作步骤&#xff1a; 1、导入Spring Data Redis的maven坐标 2、配置Redis数据源 3、编写配置类&#xff0c;创建RedisTemplate对象 4、通过RedisTemplate对象操作Redis 2、Redis结合Lua脚本 减少网络开销&#xff1a;使用Lua脚本&#xf…

leetcode 239. 滑动窗口最大值、347.前 K 个高频元素

leetcode 239. 滑动窗口最大值、347.前 K 个高频元素 leecode 239. 滑动窗口最大值 题目链接 &#xff1a;https://leetcode.cn/problems/sliding-window-maximum/description/ 题目 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的…

Linux-命令上

at是一次性的任务&#xff0c;crond是循环的定时任务 如果 cron.allow 文件存在&#xff0c;只有在文件中出现其登录名称的用户可以使用 crontab 命令。root 用户的登录名必须出现在 cron.allow 文件中&#xff0c;如果这个文件存在的话。系统管理员可以明确的停止一个用户&am…

【文末附gpt升级方案】亚马逊与Hugging Face合作:定制芯片低成本运行AI模型的创新探索

亚马逊与Hugging Face合作&#xff1a;定制芯片低成本运行AI模型的创新探索 摘要 本文探讨了亚马逊云部门与人工智能初创公司Hugging Face的合作&#xff0c;旨在通过定制计算芯片Inferentia2在亚马逊网络服务&#xff08;AWS&#xff09;上更低成本地运行数千个AI模型。文章首…