当前位置: 首页 > news >正文

简洁高效的C++终端日志工具类

纯头文件实现。

#ifndef _DEBUG_H_
#define _DEBUG_H_#include <iostream>
#include <sstream>
#include <iomanip>
#include <cstring>
#include <ctime>
#include <sys/time.h>// 获取文件名
#define __FILENAME__ (strrchr(__FILE__, '/') ? (strrchr(__FILE__, '/') + 1) : __FILE__)// ANSI 颜色定义
#define LOG_COLOR_RESET "\033[0m"
#define LOG_COLOR_RED "\033[31m"
#define LOG_COLOR_YELLOW "\033[33m"
#define LOG_COLOR_GREEN "\033[32m"
#define LOG_COLOR_CYAN "\033[36m"// 日志等级
enum class LogLevel
{Error = 1,Warn,Info,Debug
};#ifndef LOG_LEVEL
#define LOG_LEVEL LogLevel::Info
#endif#define LOG_LEVEL_VALUE(lvl) static_cast<int>(lvl)// Logger类
class Logger
{
public:Logger(LogLevel level, const char *file, int line, const char *func): enabled_(LOG_LEVEL_VALUE(LOG_LEVEL) >= LOG_LEVEL_VALUE(level)),level_(level){if (enabled_){stream_ << "[" << getTimestamp() << "] "<< getLogColor(level_)<< "[" << std::left << std::setw(5) << getLogTag(level_) << "] "<< LOG_COLOR_RESET<< "[" << file << ":" << line << " " << func << "()] - ";}}~Logger(){if (enabled_){stream_ << std::endl;// 在 C++11 及其后续的标准中,std::cout << xxx 单次调用是线程安全的,但是链式调用不是std::cout << stream_.str();}}template <typename T>Logger &operator<<(const T &val){if (enabled_){stream_ << val;}return *this;}Logger &operator<<(std::ostream &(*manip)(std::ostream &)){if (enabled_){manip(stream_);}return *this;}private:bool enabled_;LogLevel level_;std::ostringstream stream_;// 获取颜色字符串static const char *getLogColor(LogLevel level){switch (level){case LogLevel::Error:return LOG_COLOR_RED;case LogLevel::Warn:return LOG_COLOR_YELLOW;case LogLevel::Info:return LOG_COLOR_GREEN;case LogLevel::Debug:return LOG_COLOR_CYAN;default:return LOG_COLOR_RESET;}}// 获取标签名static const char *getLogTag(LogLevel level){switch (level){case LogLevel::Error:return "ERROR";case LogLevel::Warn:return "WARN";case LogLevel::Info:return "INFO";case LogLevel::Debug:return "DEBUG";default:return "LOG";}}static std::string getTimestamp(){struct timeval tv;gettimeofday(&tv, nullptr);struct tm tm_info;localtime_r(&tv.tv_sec, &tm_info);char buffer[20]; // "%Y-%m-%d %H:%M:%S" + '\0'strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tm_info);char timestamp[25]; // "yyyy-mm-dd hh:mm:ss.mmm" + '\0'snprintf(timestamp, sizeof(timestamp), "%s.%03d", buffer, (int)(tv.tv_usec / 1000));return std::string(timestamp);}
};// 简化调用的宏
#define LOG_DEBUG Logger(LogLevel::Debug, __FILENAME__, __LINE__, __func__)
#define LOG_INFO Logger(LogLevel::Info, __FILENAME__, __LINE__, __func__)
#define LOG_WARN Logger(LogLevel::Warn, __FILENAME__, __LINE__, __func__)
#define LOG_ERROR Logger(LogLevel::Error, __FILENAME__, __LINE__, __func__)#define LOG_NOOP ((void)0) ///< 什么也不做
#define unlikely(x) __builtin_expect(!!(x), 0)/*** @brief 调用函数并检查其返回int值,若非0则报错并执行action。* @param func_call  要调用的函数(需返回int类型),返回0表示成功,非0表示失败。* @param action     失败时执行的操作*/
#define CHECK_RET_INT(func_call, action)                   \do                                                     \{                                                      \int _ret = (func_call);                            \if (unlikely(_ret))                                \{                                                  \LOG_ERROR << #func_call << " error: " << _ret; \action;                                        \}                                                  \} while (0)/*** @brief 调用函数并检查其返回指针,若为NULL则报错并执行action。* @param func_call  要调用的函数(需返回指针类型),返回NULL表示失败。* @param action     失败时执行的操作*/
#define CHECK_RET_PTR(func_call, action)               \do                                                 \{                                                  \void *_ret = (void *)(func_call);              \if (unlikely(_ret == NULL))                    \{                                              \LOG_ERROR << #func_call << " error: NULL"; \action;                                    \}                                              \} while (0)#endif // _DEBUG_H_

http://www.xdnf.cn/news/1157905.html

相关文章:

  • 2.组合式API知识点(1)
  • Dev-C++——winAPI贪吃蛇小游戏
  • Softhub软件下载站实战开发(十九):软件信息展示
  • 让不符合要求的任何电脑升级Windows11
  • 2025.7.20总结-实战演讲
  • 2025年03月20日中软(外包中控)
  • 30天打牢数模基础-卷积神经网络讲解
  • 《P3398 仓鼠找 sugar》
  • 基于深度学习的目标检测:从基础到实践
  • JavaScript 语言基础详解
  • 050_Set接口(HashSet / TreeSet / LinkedHashSet)
  • leetcode75【经典动态规划】之:最长公共子序列
  • imx6ull-系统移植篇11——U-Boot 移植(下)
  • 【Java源码阅读系列57】深度解读Java MethodHandle 类源码
  • 神经网络:池化层
  • jQuery多库共存
  • SQL189 牛客直播各科目同时在线人数
  • c/c++-memory-management
  • 【PTA数据结构 | C语言版】是不是堆
  • SpringBoot集成Skywalking链路跟踪
  • 2025年渗透测试面试题总结-2025年HW(护网面试) 59(题目+回答)
  • 奥比中光双目摄像头实现物品抓取的机器人系统
  • 【Lua】多脚本引用
  • 数据结构 | 栈:构建高效数据处理的基石
  • Docker Compose
  • LeetCode 198 打家劫舍 LeetCode 213.打家劫舍II
  • Kotlin函数式接口
  • 力扣:动态规划java
  • kotlin Flow快速学习2025
  • 算法训练营DAY36 第九章 动态规划part04