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

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

纯头文件实现。

log.h:

#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.dtcms.com/a/289875.html

相关文章:

  • 响应式编程入门教程第七节:响应式架构与 MVVM 模式在 Unity 中的应用
  • SEO中关于关键词分类与布局的方法有那些
  • 【实战1】手写字识别 Pytoch(更新中)
  • Codes 通过创新的重新定义 SaaS 模式,专治 “原教旨主义 SaaS 的水土不服
  • 一文速通《二次型》
  • 复盘与导出工具最新版V27.0版本更新-新增财联社涨停,自选股,表格拖拽功能
  • Agentic-R1 与 Dual-Strategy Reasoning
  • Raspi4 切换QNX系统
  • cmake语法学习笔记
  • 模电基础-开关电路和NE555
  • 【2025西门子信息化网络化决赛】模拟题+技术文档+实验vrrp standby vxlan napt 智能制造挑战赛 助力国赛!
  • Linux之conda安装使用
  • 【数据结构】栈和队列(接口超完整)
  • 实践教程:基于RV1126与ZeroTier的RTSP摄像头内网穿透与远程访问
  • InfluxDB 数据模型:桶、测量、标签与字段详解(一)
  • iptables -m connlimit导致内存不足
  • 数据存储方案h5py
  • jdk9 -> jdk17 编程方面的变化
  • Product Hunt 每日热榜 | 2025-07-20
  • Feign远程调用
  • LWJGL教程(2)——游戏循环
  • VMware中mysql无法连接端口3306不通
  • 暑假训练之动态规划---动态规划的引入
  • PrimeTime:高级片上变化(AOCV)
  • 1948. 删除系统中的重复文件夹
  • 16.TaskExecutor启动
  • Windows批量修改文件属性方法
  • pyhton基础【27】课后拓展
  • 【华为机试】169. 多数元素
  • C++ STL中迭代器学习笔记