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

muduo网络库(三):日志输出

muduo网络库(三):日志输出

  • muduo网络库(三):日志输出
    • 总体介绍
    • 单例模式的实现
      • 为什么不直接构造而用单例
    • 利用宏函数输出日志信息
    • 时间戳的设计精髓

muduo网络库(三):日志输出

总体介绍

本项目日志输出涉及 4 个文件:

  • Logger.h/Logger.cc:定义日志记录器类Logger

    • Timestamp.h/Timestamp.cc:定义时间戳类Timestamp
      Logger是最核心的类,负责记录日志信息。它只有一个成员变量logLevel_,用于存储当前日志级别。构造函数是私有的,只能通过instance()获取唯一实例。对外提供两个接口:
  • setLogLevel(int level):设置日志级别

    • func_Log(string msg):输出日志信息
      输出日志时,func_Log()会自动调用Timestamp::now().toString()获取当前时间,将时间戳和日志消息一起输出。

单例模式的实现

classLogger:noncopyable{public:staticLogger&instance();// 获取日志实例voidsetLogLevel(intlevel);// 设置日志级别voidfunc_Log(string msg);// 输出日志信息private:LogLevel logLevel_;// 当前日志级别Logger(){};// 私有构造,禁止外部创建};``` ```cpp Logger&Logger::instance(){staticLogger logger;// 局部静态变量实现单例returnlogger;}

instance()中定义了一个局部静态变量logger。局部静态变量的特点是:第一次执行到该语句时才初始化,之后一直存在直到程序结束。这保证了两个关键特性:

  1. 线程安全:C++11 起保证局部静态变量初始化是线程安全的,多个线程同时调用instance()不会创建多个实例
  2. 懒加载:只有第一次调用时才创建,避免启动时不必要的开销
    使用方式很简单:Logger& logger = Logger::instance(),无论在哪里调用,拿到的都是同一个对象。

为什么不直接构造而用单例

如果构造函数是公有的,每个人都能Logger logger1;创建自己的实例,日志级别等状态就不一致了。把构造函数设为私有后,只能通过instance()获取实例,而instance()内部的static Logger logger保证了全局唯一。

同时Logger继承了noncopyable,和私有构造函数形成双重保险,确保实例不会被复制。

利用宏函数输出日志信息

#defineLOG_INFO(Logmessage,...)\do{\Logger&logger=Logger::instance();\Logger::instance().setLogLevel(Logger::kInfo);\charbuf[1024]={0};\snprintf(buf,1024,Logmessage,##__VA_ARGS__);\logger.func_Log(buf);\}while(0)``` 这个宏函数做的事情很直白:1.通过 `instance()` 获取单例2.2.调用 `setLogLevel(kInfo)` 设置日志级别3.3.用 `snprintf` 把格式字符串和可变参数格式化到 `buf` 中4.4.调用 `logger.func_Log(buf)` 输出 几个关键点:-`##__VA_ARGS__` 是 C99 特性,当没有可变参数时会自动去掉前面的逗号--`do{...}while(0)` 保证宏在任何上下文(如if-else)中都能安全展开为单条语句--日志级别有5个:`kDebug`、`kInfo`、`kWarn`、`kError`、`kFatal`,对应 `LOG_DEBUG`、`LOG_INFO` 等宏 使用起来就是一个增强版的 `printf`: ```cppLOG_INFO("server started on port %d",port);LOG_ERROR("connection failed: %s",strerror(errno));

简洁、统一、零额外开销。

时间戳的设计精髓

Logger.cc中,输出日志时会调用Timestamp::now().toString()来获取当前时间的字符串表示。

classTimestamp{public:Timestamp():microSecondsSinceEpoch_(0){}explicitTimestamp(int64_tmicroSecondsSinceEpoch):microSecondsSinceEpoch_(microSecondsSinceEpoch_){}staticTimestampnow();std::stringtoString()const;private:int64_tmicroSecondsSinceEpoch_;// 微秒级时间戳};

Timestamp只有一个int64_t成员变量:
一、explicit修饰单参数构造函数,禁止int64_tTimestamp的隐式转换。否则函数参数为Timestamp类型时,传入一个整数会被悄悄转换,容易产生难以察觉的 bug。

二、now()设计为静态成员函数。获取当前时间是一个与具体实例无关的操作,如果设计为非静态,就得先Timestamp t1; t1.now();,白白创建和析构一个无用的中间对象。设计为static后,直接Timestamp::now()即可,返回的临时对象会自动析构。

三、用int64_t存储微秒级时间,而非struct timeval(秒+微秒两个字段)。好处是时间比较和差值计算都变成简单的整数运算,内存也更紧凑。

注:C++11 中Timestamp::now()返回的临时对象会优先使用移动构造或 RVO 优化,避免了拷贝开销。这也是Timestamp不需要显式声明析构函数的原因——只有一个int64_t,没有需要释放的资源。

http://www.jsqmd.com/news/1199040/

相关文章:

  • AO3镜像站完全指南:解锁全球同人创作宝库的实用方案
  • 面试官抬头:“你说你用Claude写代码,你说说你怎么维护CLAUDE.md”,我:“啊。。这是啥?”,面试官:“今天面试就到这吧”
  • 公考面试培训水有多深:从天价班到模板化教学,我花了五万块才看清的真相
  • 注意事项捏
  • ChatGPT for Excel:智能公式生成与数据分析实战指南
  • SQLite 默认设置问题多,借鉴 Rust 版本机制更新能否解决?
  • 当Agent和机器开始代表人类行动,我们需要一份怎样的公共契约?
  • 2026 邯郸黄金回收完整攻略|7 月最新金价 884 元 / 克,6 家 24 小时正规门店地址电话汇总 - 不晚生活号
  • C++随机数生成:从rand()重复到<random>库的完整解决方案
  • isula-build 多架构支持:x86_64 与 AArch64 跨平台构建终极指南 [特殊字符]
  • 计算机毕业设计之基于springboot和vue3的校园招聘系统
  • 2026太原暴雨窗户飘窗渗水漏雨怎么办?专业窗边渗漏根治找宅安选房屋修缮 - 宅安选房屋修缮
  • CVPR 2026 SubspaceAD:单样本 97.1% AUROC,无需训练即达少样本异常检测新 SOTA
  • 3分钟搞定GitHub界面中文化:中文开发者的效率神器
  • TVM 0.22 手动编译实战:AI编译器构建原理与硬件适配指南
  • 防浪涌PCB设计指南
  • Bowring-Hirvonen迭代法:高效实现大地坐标与空间直角坐标转换的C++实践
  • SQLiteGo 适配银河麒麟:打造信创场景下轻量大数据分析最优解
  • 线性表中的链表概述
  • Spring Boot 配置双雄:bootstrap.yml 与 application.yml 的深度解析与实战指南
  • 濮阳人注意!旧金饰别乱卖,这6家正规黄金回收店,覆盖全市不踩雷 - 清奢黄金上门回收
  • 《汉明码(海明码)》:从“分组侦探”到“纠错神探”的实战推演
  • 从零到出活:我用飞算JavaAI一小时搭了套门店抽检整改系统
  • 挺意外的,大模型的底层设施里,还藏着一家国产具身模型公司
  • Unity跨平台摄像头开发全解析:WebCamTexture原理、多平台适配与性能优化
  • 《Java 100 天进阶之路》第4.1篇:Java基础语法易混淆概念对比集(2026版)
  • 刷题APP测评:哪款真正好用?我用半年时间对比了主流公考刷题软件
  • 3步解锁全球同人创作:AO3镜像站完全访问解决方案
  • Android密钥证明测试失败排查:从证书链验证到硬件安全分析
  • 主神空间平台:规则引擎与实时协作系统的架构实践