一個簡潔的 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
英文地址,請注明出處:http://en.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…