一个简洁的 C++ 日志模块实现

一个简洁的 C++ 日志模块实现

1. 引言

日志功能在软件开发中扮演着至关重要的角色,它帮助开发者追踪程序执行过程、诊断问题以及监控系统运行状态。本文介绍一个使用 C++ 实现的轻量级日志模块,该模块支持多日志级别、线程安全,并提供了简洁易用的接口。

2. 代码实现

2.1 主程序 (main.cpp)

#include "log.h"int main(int argc, char *argv[])
{Log::GetInstance().Init("./log");Log::GetInstance().WriteLog(ERROR, "error");Log::GetInstance().WriteLog(WARNING, "warning");Log::GetInstance().WriteLog(DEBUG, "debug");Log::GetInstance().WriteLog(INFO, "info");return 0;
}

2.2 头文件 (log.h)

#ifndef LOG_H
#define LOG_H#include <iostream>
#include <pthread.h>
#include <cstdio>using namespace std;// 日志级别枚举
typedef enum {ERROR = 0,WARNING,DEBUG,INFO,LEVEL_MAX
} LogLevel_en;// 日志状态枚举
typedef enum {LOG_INIT_STATE,LOG_READY_STATE,LOG_INVALID_STATE
} LogState_en;#define LOG_NUM 255Uclass Log {
private:char m_log_buf[LOG_NUM];        // 日志缓冲区pthread_mutex_t m_mutex;        // 互斥锁,保证线程安全FILE *m_log_fd;                 // 日志文件指针LogState_en m_log_state;        // 日志模块状态public:static Log& GetInstance(void);  // 获取单例实例void Init(const char *dir_file_name);  // 初始化日志系统void WriteLog(LogLevel_en log_level, const char* format, ...);  // 写日志接口private:Log(void) {m_log_state = LOG_INVALID_STATE;};~Log(void) = default;
};#endif

2.3 实现文件 (log.cpp)

#include "log.h"
#include <ctime>
#include <cstring>
#include <cstdarg>// 获取日志单例实例
Log& Log::GetInstance(void)
{static Log instance;return instance;
}// 初始化日志系统
void Log::Init(const char *dir_file_name)
{if(nullptr != dir_file_name){m_log_state = LOG_INIT_STATE;cout << "Log file: " << dir_file_name << endl;m_log_fd = fopen(dir_file_name, "a");if (m_log_fd != nullptr) {m_log_state = LOG_READY_STATE;}}
}// 写入日志信息
void Log::WriteLog(LogLevel_en log_level, const char* format, ...)
{// 参数有效性检查if((LEVEL_MAX <= log_level) || (nullptr == format)) {return;}// 日志状态检查if (LOG_READY_STATE != m_log_state) {return;}// 设置日志级别字符串char buffer_log_level[16] = {0};switch (log_level) {case ERROR:strcpy(buffer_log_level, "[error]:");break;case WARNING:strcpy(buffer_log_level, "[warning]:");break;case DEBUG:strcpy(buffer_log_level, "[debug]:");break;case INFO:strcpy(buffer_log_level, "[info]:");break;default:cout << "Invalid log level" << endl;return;}// 设置时间戳字符串time_t time_val = time(nullptr);struct tm *p_tm_val = localtime(&time_val);char buffer_time[48] = {0};snprintf(buffer_time, 48, "%.4d-%.2d-%.2d-%.2d-%.2d-%.2d:", p_tm_val->tm_year + 1900,p_tm_val->tm_mon + 1,p_tm_val->tm_mday,p_tm_val->tm_hour,p_tm_val->tm_min,p_tm_val->tm_sec);// 加锁保证线程安全pthread_mutex_lock(&m_mutex);// 组装日志前缀memset(m_log_buf, 0, sizeof(m_log_buf));u_int8_t log_len = strlen(buffer_log_level) + strlen(buffer_time) + 1;int n = snprintf(m_log_buf, log_len, "%s%s", buffer_log_level, buffer_time);if(n > 0) {// 处理可变参数va_list variable_list;va_start(variable_list, format);int m = vsnprintf(m_log_buf + n, LOG_NUM - n - 1, format, variable_list);va_end(variable_list);if(m > 0) {// 输出到控制台和文件cout << m_log_buf << endl;m_log_buf[n + m] = '\n';m_log_buf[n + m + 1] = '\0';fputs(m_log_buf, m_log_fd);fflush(m_log_fd);  // 确保数据写入磁盘} else {cout << "vsnprintf error!" << endl;}} else {cout << "snprintf error!" << endl;}// 释放锁pthread_mutex_unlock(&m_mutex);
}

2.4 Makefile 构建配置

# 目标程序名称
TGT := appCUR_DIR := $(shell pwd)# 源文件设置
SRC := $(wildcard *.cpp)
OBJ := $(patsubst %.cpp,%.o,$(SRC))# 编译选项设置
CPPFLAGS := -I.
CPPFLAGS += -pthread
CPPFLAGS += -I${CUR_DIR}/include# 编译器标志
CXXFLAGS := -Wall -O2# 默认构建目标
all: $(TGT)@echo "Build successful"$(TGT): $(OBJ)$(CXX) -std=c++11 $(CPPFLAGS) $(CXXFLAGS) $^ -o $@%.o: %.cpp$(CXX) -std=c++11 $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@# 清理构建文件
clean:
ifneq ($(wildcard $(OBJ)),)@rm $(OBJ)
else@echo "No object files to remove"
endif
ifneq ($(wildcard $(TGT)),)@rm $(TGT) 
else@echo "No target executable to remove"
endif# 仅清理对象文件
obj_clean:
ifneq ($(wildcard $(OBJ)),)@rm $(OBJ)
else@echo "No object files to remove"
endif.PHONY: obj_clean clean all

3. 编译与运行结果

执行构建命令:

$ make
g++ -std=c++11 -I. -pthread -I/mnt/code/01_comprehensive/log_demo/include -Wall -O2 -c log.cpp -o log.o
g++ -std=c++11 -I. -pthread -I/mnt/code/01_comprehensive/log_demo/include -Wall -O2 -c main.cpp -o main.o
g++ -std=c++11 -I. -pthread -I/mnt/code/01_comprehensive/log_demo/include -Wall -O2 log.o main.o -o app
Build successful

运行程序:

$ ./app 
Log file: ./log
[error]:2024-06-29-11-33-03:error
[warning]:2024-06-29-11-33-03:warning
[debug]:2024-06-29-11-33-03:debug
[info]:2024-06-29-11-33-03:info

查看生成的日志文件:

$ cat log
[error]:2024-06-29-11-23-43:error
[warning]:2024-06-29-11-23-43:warning
[debug]:2024-06-29-11-23-43:debug
[info]:2024-06-29-11-23-43:info

4. 设计特点

  1. 单例模式:确保整个应用程序中只有一个日志实例
  2. 线程安全:使用互斥锁保护共享资源,支持多线程环境
  3. 多日志级别:支持 ERROR、WARNING、DEBUG、INFO 四种级别
  4. 时间戳:每条日志都包含精确到秒的时间信息
  5. 双重输出:日志同时输出到控制台和文件
  6. 格式化支持:支持 printf 风格的格式化输出

这个日志模块虽然简洁,但提供了基本日志功能所需的核心特性,适合在中小型项目中使用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/94275.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/94275.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言---数据类型

文章目录数据类型分类1. 基本类型 (Basic Types)a. 整数类型 (Integer Types)char (字符型)int (整型)short (短整型)long (长整型)long long (C99标准引入)图片汇总b. 浮点类型 (Floating-Point Types)float (单精度浮点型)double (双精度浮点型)long double (长双精度浮点型)…

本搭建乌云漏洞库

1.下载镜像站文件&#xff0c;并拖入虚拟机 2.将bugs.rar解压至网站根目录下 /var/www/html 3.配置bugs/conn.php 4.在bugs下创建upload目录&#xff0c;将10-14、15-a、15-b、16压缩包文件解压到该upload目录 5.把wooyun.rar解压到 /mysql/data/wooyun目录下 6.配置hosts文件后…

Vmware虚拟机 处理器配置选项配置介绍

1. 处理器配置选项好&#x1f44c;&#xff0c;我来帮你逐一解读 VMware 里 虚拟机处理器 这些选项的含义。 你截的图里&#xff0c;主要有三块内容&#xff1a; 处理器数量 每个处理器的内核数量 ©虚拟化引擎1️⃣ 处理器数量 这是分配给虚拟机的 逻辑 CPU 插槽数。一般…

day40-tomcat

1.每日复盘与今日内容1.1复盘keepalived高可用配置抢占式与非抢占式脑裂keepalived处理Nginx挂掉1.2今日内容部署、安装、配置tomcat(systemctl)Tomcat主配置文件部署静态页部署zrlog&#x1f35f;&#x1f35f;&#x1f35f;&#x1f35f;&#x1f35f;接入负载均衡挂载到NFS2…

【RA-Eco-RA4E2-64PIN-V1.0 开发板】步进电机的串口控制

【RA-Eco-RA4E2-64PIN-V1.0 开发板】步进电机的串口控制 本文介绍了 RA-Eco-RA4E2-64PIN-V1.0 开发板通过串口指令实现 28BYJ-48 步进电机旋转角度和速度的精确控制的项目设计。 项目介绍 硬件连接&#xff1a;28BYJ-48 步进电机、ULN2003 驱动板、Jlink 调试器、供电电源等&am…

PiscCode基于 Mediapipe 的人体多模态关键点检测与可视化系统 —— HumanMultiLandmarker 深度解析

一、引言 在计算机视觉领域&#xff0c;人体关键点检测&#xff08;Human Pose Estimation&#xff0c;HPE&#xff09;一直是研究和应用的热点方向之一。随着深度学习与实时图像处理技术的发展&#xff0c;人体姿势估计已经从传统的 2D 检测走向了 3D 空间建模&#xff0c;并…

文献阅读笔记【物理信息机器学习】:Physics-informed machine learning

文献阅读笔记&#xff1a;Physics-informed machine learningSummaryResearch ObjectiveBackground / Problem Statement问题背景研究现状需解决的问题问题出现的原因分析问题解决思路Method(s)问题建模作者解决问题的方法/算法1. 观测偏差&#xff08;Observational Biases&am…

Linux服务环境搭建指南

实验拓扑概述**实验拓扑&#xff1a; APPSRV&#xff1a; 主机名&#xff1a;appsrv.example.com ip地址&#xff1a;192.168.100.10 网关&#xff1a;192.168.100.254 网卡为NAT模式 STORAGESRV&#xff1a; 主机名&#xff1a;storagesrv.example.com ip地址&#xff1a;192.…

[特殊字符] 数据库知识点总结(SQL Server 方向)

一、数据库基础概念数据库&#xff08;Database&#xff09;&#xff1a;存储和管理数据的容器。数据表&#xff08;Table&#xff09;&#xff1a;以行和列形式组织数据。行&#xff08;Row&#xff09;&#xff1a;一条记录。列&#xff08;Column&#xff09;&#xff1a;字…

【PSINS工具箱】MATLAB例程,二维平面上的组合导航,EKF融合速度、位置和IMU数据,4维观测量

文章目录关于工具箱程序简介代码概述核心功能与步骤运行结果MATLAB代码关于工具箱 本文所述的代码需要基于PSINS工具箱&#xff0c;工具箱的讲解&#xff1a; PSINS初学指导&#xff1a;https://blog.csdn.net/callmeup/article/details/137087932 本文为二维平面上的定位&am…

MiMo-VL 技术报告

摘要 我们开源了 MiMo-VL-7B-SFT 和 MiMo-VL-7B-RL 两个强大的视觉语言模型,它们在通用视觉理解和多模态推理方面均展现出最先进的性能。MiMo-VL-7B-RL 在 40 项评估任务中的 35 项上优于 Qwen2.5-VL-7B,并在 OlympiadBench 上获得 59.4 分,超越了参数量高达 780 亿的模型。…

CTFshow Pwn入门 - pwn 19

先看main函数&#xff1a;fclose(_bss_start) fclose(stdout) 关闭了默认fd1的输出&#xff0c;所以system的结果无法直接看到。 思路&#xff1a; 输出重定向。 ls 1>&0 ls >&0 ls >&2 ###三种写法均可将输出重定向到能回显的终端并获得一个新的交互…

Redis(以Django为例,含具体操作步骤)

简介Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的内存数据结构存储系统&#xff0c;支持多种数据结构&#xff08;如字符串、哈希、列表、集合、有序集合等&#xff09;&#xff0c;可用作数据库、缓存或消息队列。其核心特点包括&#xff1a;高性能&am…

浏览器解析网址的过程

问题浏览器解析网址的过程我的回答当你在浏览器地址栏输入一个URL&#xff08;比如www.example.com&#xff09;并按下回车后&#xff0c;会发生以下一系列步骤&#xff1a;首先&#xff0c;浏览器会解析URL结构&#xff0c;确定要访问的协议、域名和路径。如果你没有输入协议部…

NVIDIA Nsight Systems性能分析工具

* 性能分析 NVIDIA Nsight Systems (推荐)&#xff1a; 这是 NVIDIA 官方推荐的更现代、功能更强大的分析工具。 安装 Nsight Systems在 Docker 容器中启动程序&#xff1a;# 确保你在启动容器时挂载了/usr/local/cuda/targets/x86_64-linux/lib/ 和 /usr/local/nvidia/lib64 #…

后台管理系统-14-vue3之tag标签页的实现

文章目录 1 tag静态实现 1.1 CommonTag.vue(el-tag) 1.2 Main.vue(普通组件标签) 2 tag通过pinia管理 2.1 CommonAside.vue(菜单点击事件) 2.2 stores/index.js(selectMenu()和tags) 2.3 CommonTag.vue(计算属性tags) 3 点击tag之后跳转到指定页面 3.1 views/Mail.vue(商品) 3.…

CMake2: CMakeLists.txt的常用命令

参考链接: 爱编程的大丙 | CMake教程 CMakeLists指令以及常用方法 现代 CMake 教程 文章目录1. cmake_minimum_required( )2. project( )3. add_executable( )4. set()5. aux_source_directory( )6. file( )7. include_directories( )8. add_library( )9. link_libraries()与li…

Ansible入门:自动化运维基础

Ansible 基础概念与安装1. 自动化动机 (Motivation for Automation)概念解释&#xff1a; 指为什么要用Ansible等工具来替代手动管理服务器。核心动机包括&#xff1a;效率与速度&#xff1a; 同时在上百甚至上千台服务器上执行任务&#xff0c;秒级完成&#xff0c;远非人工可…

【测试】基于博客系统的测试报告

前言 本篇博客对简易的博客系统做的测试总结一份测试报告&#xff0c;包含功能测试&#xff0c;自动化测试&#xff0c;性能测试 &#x1f493; 个人主页&#xff1a;zkf ⏩ 文章专栏&#xff1a;测试 若有问题 评论区见&#x1f4dd; &#x1f389;欢迎大家点赞&#x1f44d;…

Oracle:配置让插入语句时id自动输入

Oracle:配置让插入语句时id自动输入无需手动指定&#xff0c;核心是利用 序列&#xff08;Sequence&#xff09; 或 自增列&#xff08;Identity Column&#xff09; 来自动生成唯一值。以下是两种常用方案&#xff1a;方案 1&#xff1a;使用序列&#xff08;Sequence&#xf…