c++如何实现简单的日志系统_c++输出日志到文件【实战】

8次阅读

std::ofstream 直接写文件不适合做日志系统,因其频繁i/o性能差、线程不安全、缺乏时间戳和级别标识;可靠方案需支持线程安全、异步/缓冲写入、格式化、级别控制与自动轮转,推荐用spdlog。

c++如何实现简单的日志系统_c++输出日志到文件【实战】

为什么 std::ofstream 直接写文件不适合做日志系统

直接用 std::ofstream 每次 open()write()close(),会触发频繁磁盘 I/O,性能差;多线程下不加锁会乱序甚至崩溃;没时间戳、级别标识,查问题时根本分不清哪条是 Error 哪条是 DEBUG。真正能用的日志系统,至少得支持:线程安全、异步写入(或缓冲)、格式化输出、级别控制、自动轮转。

spdlog 三行接入,避免自己造轮子

自己写带缓冲、线程安全、支持滚动的文件日志,两周都调不完。spdlogc++ 里最轻量又可靠的日志库,头文件即用,无需编译依赖(启用 SPDLOG_COMPILED_LIB 才需链接)。实战中推荐这样初始化:

#include <spdlog/spdlog.h> #include <spdlog/sinks/rotating_file_sink.h> <p>auto logger = spdlog::rotating_logger_mt("file_logger", "app.log", 1048576 * 5, 3); logger->set_level(spdlog::level::debug); logger->info("startup ok");

说明:rotating_logger_mt 表示多线程安全 + 自动轮转;参数 "app.log" 是基础文件名,1048576 * 5 是单文件上限(5MB),3 是最多保留 3 个历史文件(app.log.1, app.log.2…)。

不用第三方库?手写最小可行日志类要注意什么

如果项目限制不能引入外部依赖,可封装一个极简线程安全文件日志类,但必须守住三条底线:

立即学习C++免费学习笔记(深入)”;

  • std::mutex 锁住 write() 全过程,而不是只锁 std::ofstream::write() —— 否则格式化字符串拼接(如 std::to_string())可能被并发打断
  • 不要每次写都 open()/close(),而应复用 std::ofstream 对象,并在构造时用 std::ios::app 模式打开,否则日志会被覆盖
  • 手动添加时间戳需用 std::chrono + std::put_time,避免 ctime() 返回静态缓冲区(多线程下会冲突)

关键片段示例(仅核心逻辑):

class SimpleFileLogger {     std::ofstream file_;     mutable std::mutex mtx_; public:     SimpleFileLogger(const char* path) : file_(path, std::ios::app) {}     void log(const char* level, const char* msg) const {         std::lock_guard<std::mutex> lk(mtx_);         auto now = std::chrono::system_clock::now();         auto time_t = std::chrono::system_clock::to_time_t(now);         std::stringstream ss;         ss << std::put_time(std::localtime(&time_t), "%Y-%m-%d %H:%M:%S")             << " [" << level << "] " << msg << " ";         file_ << ss.str();         file_.flush(); // 确保立即落盘,否则可能卡在缓冲区     } };

日志输出到文件却看不到内容?检查这三点

常见“写了日志但文件空”或“只有第一条”的问题,基本集中在:

  • std::ofstream 构造失败没检查:if (!file_.is_open()) { /* 报错 */ },路径不存在或权限不足时静默失败
  • 忘记调用 flush()close(),尤其程序异常退出时,缓冲区内容直接丢失
  • windows 下路径用了反斜杠 "C:logspp.log",未转义成 "C:logsapp.log" 或用原始字符串 R"(C:logspp.log)",导致路径解析错误

真实项目里,日志系统的健壮性往往体现在这些细节上——不是功能多炫,而是崩了还能留下最后一句错误。

text=ZqhQzanResources