【C++ Linux编程进阶 从0实现muduo库系列】第五讲:实现C++日记库 ...

打印 上一主题 下一主题

主题 1659|帖子 1659|积分 4977

重点内容


视频解说:《C++Linux编程进阶:从0实现muduo C++网络框架系列》-第5讲.实现C++日记库
代码改动

lesson5代码


  • 实现:base/LogStream.h/cc
  • 实现:base/Logging.h/cc
  • examples/test_basic_log.cc
  • examples/test_logging.cc
特别要注意CMakeLists.txt的 宏定义改动,debug模式时,lesson4声明的DEBUG宏定义和日记库的Debug日记级别符号有冲突,如果不修改会产买卖想不到的编译报错。




1. 日记体系整体架构

1.1 日记体系整体架构

LOG_DEBUG << "debug log test";
LOG_INFO << "info log test";


1.2 模块详细作用

1.2.1 日记宏 (LOG_XXX)

比如LOG_DEBUG, LOG_INFO等
提供简洁易用的接口,自动捕获文件名和行号,根据当前日记级别决定是否记录日记,创建临时Logger对象并返回流式接口


利用范例:
  1. LOG_DEBUG << "debug log test";
  2. LOG_INFO << "int: " << 42;
复制代码
1.2.2 Logger 类

日记体系核心类,管理日记生命周期,提供静态方法控制全局日记行为(级别、输出方式),根据日记级别和上下文创建日记实例,析构时完成日记输出。
LOG_INFO << "info log test"; 现实调用
  1. if (mymuduo::Logger::logLevel() <= mymuduo::Logger::INFO) \
  2.   mymuduo::Logger(__FILE__, __LINE__).stream() << "info log test";
复制代码
1.2.3 Logger::Impl 类



日记格式化分为两大模块:


Logger的内部实现类,封装日记格式化逻辑,管理时间戳和源文件信息,处理日记的详细格式,添加行号、文件名等上下文信息。
比如日记格式:20250324 09:08:15.248185 WARN warn 输出 - test_basic_log.cc:26


  • 20250324 09:08:15.248185 时间戳
  • WARN 日记级别打印
  • test_basic_log.cc 文件名
  • :26 行号








1.2.4 LogStream 类

提供流式接口(<<操作符),管理内部缓冲区,实现各种数据范例的格式化转换,特别优化了数值转换效率,支持链式调用。
包括Logger::impl类里的时间戳 日记级别 文件名 行号的缓存,
这里我们重点讲流式接口 <<操作符,范例如下所示:
  1. mymuduo::LogStream logstream;
  2. logstream << "LogStream 输出" << 78 << "abc";
  3. std::cout << "cout: " << logstream.buffer().toString() << std::endl;
复制代码
输出:
cout: LogStream 输出78abc
1.2.5 FixedBuffer 类

预分配固定大小的内存缓冲区,避免动态内存分配,提供高效的追加、重置等基本操作,作为LogStream的内部存储。
1.2.6 输出函数 (OutputFunc/FlushFunc)

日记终极写入的目标地,函数指针范例(OutputFunc和FlushFunc),允许自定义日记输出目标和革新方式,可以是控制台、文件、网络套接字或自定义设备,由OutputFunc和FlushFunc控制,支持灵活配置。
1.2.7 日记级别 (LogLevel)

定义日记的严峻水平(TRACE、DEBUG、INFO、WARN、ERROR、FATAL),控制日记过滤,配合宏实现条件记录,支持运行时调解。
1.2.8 Fmt 格式化类

联合C风格格式化字符串的灵活性和C++范例安全性,预格式化数据到内部缓冲区,通过<<操作符集成到LogStream中。
  1.   // 测试整数格式化
  2.     Fmt intFmt("%d", 42);
  3.     std::cout << "整数格式化: " << intFmt.data() << std::endl;
  4.    
  5.     // 测试浮点数格式化
  6.     Fmt floatFmt("%.2f", 3.14159);
  7.     std::cout << "浮点数格式化: " << floatFmt.data() << std::endl;
复制代码
打印输出:
   整数格式化: 42 浮点数格式化: 3.14
  1.2.9 SourceFile 类

高效处理源文件路径,从完整路径中提取文件名,避免运行时重复盘算,优化日记性能,存储在Logger::Impl中提供位置信息。
  1. // 测试不同路径形式
  2. std::cout << "原始的文件名获取:" << __FILE__ << std::endl;
  3. const char* paths[] = {
  4.     "/home/user/project/file.cpp",
  5.     "src/file.cpp",
  6.     "file.cpp"
  7. };
  8. for (const char* path : paths)
  9. {
  10.     Logger::SourceFile sf(path);
  11.     std::cout << "原始路径: " << path << "\n";
  12.     std::cout << "提取文件名: " << sf.data_ << "\n";
  13.     std::cout << "文件名长度: " << sf.size_ << "\n\n";
  14. }
复制代码
打印输出
   原始的文件名获取:/home/lqf/long/spark_muduo/lesson5/examples/test_basic_log.cc 原始路径: /home/user/project/file.cpp 提取文件名: file.cpp 文件名长度: 8 原始路径: src/file.cpp 提取文件名: file.cpp 文件名长度: 8 原始路径: file.cpp 提取文件名: file.cpp 文件名长度: 8
  2 格式化日记输出LogStream类

2.1 核心计划理念

LogStream 的核心计划理念是提供一个高效、范例安全、易用的日记流式接口,主要体现在:
1.流式语法计划:
通过重载 << 操作符,实现雷同 std::cout 的链式调用语法
并重载不同的数据范例


  • self& operator<<(short);
  • self& operator<<(unsigned short);
  • self& operator<<(const char* str)
  • self& operator<<(const std::string& v)
每个 << 操作符返回自身引用(self&),支持链式表达式,比如LOG_INFO << "int: " << 42;
2.高效内存管理(计划FixedBuffer类):


  • 利用预分配的固定大小缓冲区而非动态内存分配
  • 避免了频繁的内存分配/释放操作,淘汰内存碎片
2.2 计划框架图



2.3 核心实现分析

2.3.1 内存管理战略

LogStream 通过 FixedBuffer 模板类管理内存,采用两种预定义大小:
  1. // 在detail命名空间中定义两种常用缓冲区大小
  2. const int kSmallBuffer = 4000;         // 4KB,用于一般日志消息
  3. const int kLargeBuffer = 4000*1000;    // 4MB,用于特别长的日志消息
  4. // 定义LogStream使用的缓冲区类型
  5. typedef detail::FixedBuffer<detail::kSmallBuffer> Buffer;
复制代码
FixedBuffer 的核心在于预分配内存并利用指针跟踪当前位置:
  1. template<int SIZE>
  2. class FixedBuffer : noncopyable {
  3. private:
  4.     char data_[SIZE];  // 固定大小的字符数组
  5.     char* cur_;        // 当前写入位置
  6.    
  7. public:
  8.     FixedBuffer() : cur_(data_) {}
  9.    
  10.     void append(const char* buf, size_t len) {
  11.         if (avail() > static_cast<int>(len)) {
  12.             memcpy(cur_, buf, len);
  13.             cur_ += len;
  14.         }
  15.     }
  16.    
  17.     // 其他辅助方法...
  18. };
复制代码
这种计划避免了动态内存分配,特别适合短生命周期、高频调用的日记场景。
2.3.2 优化的数值转换算法

LogStream 对数值转换做了专门优化,利用自定义的转换算法替代标准库函数:
  1. // Wilson的高效整数转字符串算法
  2. template<typename T>
  3. size_t convert(char buf[], T value) {
  4.     T i = value;
  5.     char* p = buf;
  6.     do {
  7.         int lsd = static_cast<int>(i % 10);
  8.         i /= 10;
  9.         *p++ = zero[lsd];  // 使用预定义的字符表  查表获取数字
  10.     } while (i != 0);
  11.     if (value < 0) {
  12.         *p++ = '-';
  13.     }
  14.     *p = '\0';
  15.     std::reverse(buf, p);  // 反转得到正确顺序
  16.     return p - buf;
  17. }
  18. // 十六进制转换算法,用于指针
  19. size_t convertHex(char buf[], uintptr_t value) {
  20.     // 类似实现...
  21. }
复制代码
这些算法直接操作字符数组,避免了格式化函数的开销和临时对象创建。
2.3.3 流式接口实现

LogStream 通过大量的操作符重载实现流式接口:
  1. // 将不同类型的数据格式化写入缓冲区
  2. LogStream& LogStream::operator<<(int v) {
  3.     formatInteger(v);
  4.     return *this;  // 返回自身引用,支持链式调用
  5. }
  6. LogStream& LogStream::operator<<(const char* str) {
  7.     if (str) {
  8.         buffer_.append(str, strlen(str));
  9.     }
  10.     else {
  11.         buffer_.append("(null)", 6);
  12.     }
  13.     return *this;
  14. }
  15. // 其他类型的重载...
复制代码
关键是每个操作符都返回自身引用(*this),使得多个 << 操作可以连续调用。
2.4 范例安全与格式化

LogStream 通过模板和静态断言提供范例安全保证:
  1. // 将所有整数类型统一处理
  2. template<typename T>
  3. void LogStream::formatInteger(T v) {
  4.     // 实现整数格式化...
  5. }
  6. // Fmt类使用静态断言确保类型安全
  7. template<typename T>
  8. Fmt::Fmt(const char* fmt, T val) {
  9.     // 编译期类型检查
  10.     static_assert(std::is_arithmetic<T>::value == true,
  11.                  "Must be arithmetic type");
  12.    
  13.     // 格式化...
  14. }
复制代码
3 章节总结

1.重点内容:

  • 理解如何利用日记级别控制日记是否记录
  • 理解LogStream如何利用输出操作符 以C++ cout方式格式化日记。
2.扩展:

  • 异步日记支持:
  • 将 LogStream 与异步日记体系集成,提高性能
  • 计划双缓冲机制,支持高并发场景
  • 日记压缩与滚动:
  • 支持日记文件自动滚动和压缩
  • 实现日记清理战略,避免磁盘占用过多

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

玛卡巴卡的卡巴卡玛

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表