news 2026/7/16 8:47:57

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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,没有需要释放的资源。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/16 8:45:07

锐捷交换机Trunk端口VLAN过滤策略实战:四种allowed vlan模式详解与应用

1. 锐捷交换机Trunk端口基础概念 Trunk端口是交换机上用于跨设备传输多VLAN数据的关键配置。想象一下Trunk就像高速公路上的多车道,每个车道(VLAN)可以独立传输数据而不会互相干扰。在锐捷交换机中,当我们需要让不同交换机上的相同…

作者头像 李华
网站建设 2026/7/16 8:43:38

Deepseek V4:打破AI代码助手枷锁,提升工程开发效率

上周在调试一个复杂的多模块项目时,我遇到了一个让人头疼的问题:代码逻辑看似正确,但运行时总在某些边界条件下出现难以追踪的异常。尝试了几个主流的大模型助手后,要么是上下文长度不够,要么是对代码逻辑的理解停留在…

作者头像 李华
网站建设 2026/7/16 8:42:09

3分钟解锁AO3镜像站:绕过访问限制的终极免费方案

3分钟解锁AO3镜像站:绕过访问限制的终极免费方案 【免费下载链接】AO3-Mirror-Site 项目地址: https://gitcode.com/gh_mirrors/ao/AO3-Mirror-Site 你是否曾经在深夜打开浏览器,满怀期待地想要阅读心爱的同人作品,却只看到冰冷的&qu…

作者头像 李华
网站建设 2026/7/16 8:41:52

医疗远程会诊系统建设方案:助力多院区协同与专家资源共享

核心摘要医疗远程会诊系统的核心价值,是把三甲医院、区域医疗中心、基层医院连接成统一协作网络,实现远程专家会诊、影像诊断、教学培训、远程查房等业务闭环。对多院区医院而言,建设重点不只是“开视频会议”,而是要打通会诊流程…

作者头像 李华
网站建设 2026/7/16 8:37:56

深耕包装设计领域:东莞视维品牌以视觉赋能产品价值

在东莞的品牌设计领域,广东视维品牌营销咨询有限公司(SIVIBRAND)是一家专注品牌策略与视觉落地的专业机构。自成立以来,视维持续为制造、快消、大健康等多个行业的企业提供品牌全案服务,其中包装设计作为连接品牌与消费…

作者头像 李华
网站建设 2026/7/16 8:37:55

Charles搭配MuMu模拟器抓取HTTPS数据包实战(附疑难排查)

1. 环境准备与工具安装 第一次用Charles抓MuMu模拟器的HTTPS包时,我踩了个大坑——Android 7.0之后系统不再信任用户安装的证书。折腾了整整两天才发现问题根源,后来摸索出这套完整方案。先说说需要准备的家伙: Charles 4.6 (官…

作者头像 李华