前言
- 之前介绍过一个C语言日志库 轻量级c语言开源日志库log.c介绍,源代码只有不到200行,使用非常方便。
- 但是也存在很多缺点,比如日志时间只支持打印到秒,没有作多线程处理,不支持日志回滚。在小型项目或者测试demo中使用还可以,在大型项目中,就无法满足需求了。
- 于是又找到了一个C++日志库plog,虽然代码量较多,但使用也非常简单,并且功能非常强大,可以满足在大型项目中的使用需求。
plog简介
- plog 是一个轻量级、跨平台的C++日志库,它设计简洁且易于使用。有以下特点
- 简单易用: plog 提供了直观的API,允许开发者以简洁的方式在代码中添加日志记录功能。例如,通过LOGD, LOGI, LOGW, LOGE等宏定义来分别表示不同级别的日志输出(如debug、info、warning和error)。
- 多线程支持: plog 设计为线程安全的,可以安全地在多线程环境下使用,确保各个线程的日志记录不会相互干扰。
- 多种日志级别: 支持多种日志级别,可以根据需要调整输出的日志详细程度,只显示重要信息或者包括所有调试细节。
- 文件回滚与滚动日志: plog 允许配置日志文件的大小限制和循环策略,当达到一定大小时会自动创建新的日志文件,以实现日志的滚动存储。
- 异步/同步日志写入: 可以根据需求选择同步或异步的方式来写入日志,提高程序性能,尤其是在大量日志产生时。
- 可扩展性: plog 提供了自定义appender的能力,用户可以创建自己的日志接收器,将日志输出到各种不同的目标,如文件、数据库、网络等。
- 跨平台兼容: plog 能够在多个操作系统和编译器下运行,如Windows、Linux、macOS等,并且兼容多种C++标准。
- 体积小巧: plog 的源代码量小,占用资源少,适合嵌入式系统或其他对体积敏感的应用场景
使用步骤
- 下载源代码后,将根目录下include目录下的所有文件拷贝到我们自己的工程下,然后在工程中包含对应的头文件即可。
使用示例
基本功能
- 通过一个示例演示下基本功能。
- 测试代码 : main.cpp
-
#include <plog/Log.h> // Step1: include the header.#include <plog/Initializers/RollingFileInitializer.h>#include <plog/Appenders/ColorConsoleAppender.h>#include <string.h>#include <iostream>#include <iomanip>void polgFunc(){PLOG_DEBUG << "DEBUG join polgFunc func";PLOG_INFO << "DEBUG join polgFunc func";PLOG_ERROR << "DEBUG join polgFunc func";}int main(){// 日志初始化// 参数1 - 日志级别, 参数2 - 日志文件名, 参数3 - 单个日志大小, 参数4 - 日志回滚数// 如果不想实现日志回滚,参数3和参数4可以不填或者填0plog::init(plog::info, "plog.log", 1024, 5);// 同时打印到控制台plog::ColorConsoleAppender<plog::TxtFormatter> consoleAppender;plog::get()->addAppender(&consoleAppender); // Also add logging to the console.int iData = 10020;double fData = 3.141592654; std::string sData = "hello plog";PLOG_DEBUG << "debug hello log!"; LOG_INFO << "info hello log!";PLOG_WARNING << "warning hello log!";PLOG_ERROR << "error hello log!";PLOG_INFO << "int data : " << iData;PLOG_INFO << "int hex data : " << std::hex << iData;PLOG_INFO << "float data : " << fData;PLOG_INFO << "float data : " << std::fixed << std::setprecision(2) << fData;PLOG_INFO << "string data : " << fData;polgFunc();system("pause");return 0;}
- 控制台打印
- 文件打印:在当前目录下会生成一个 plog.log 文件
- 日志回滚 : 文件超出我们设置的大小后,可以自动回滚
进阶功能 - 自定义日志打印格式
- 对测试代码进行修改 main.cpp
-
#include <plog/Log.h> // Step1: include the header.#include <plog/Initializers/RollingFileInitializer.h>#include <plog/Appenders/ColorConsoleAppender.h>#include <string.h>#include <iostream>#include <iomanip>// 自定义日志格式器namespace plog{class MyFormatter{public:static util::nstring header() // This method returns a header for a new file. In our case it is empty.{return util::nstring();}static util::nstring format(const Record& record) // This method returns a string from a record.{util::nostringstream ss;util::Time t;t.time = record.getTime().time;struct tm *ltime = localtime(&t.time);t.millitm = record.getTime().millitm;// 在这里设置日志打印的格式ss << "[plog] ["<<ltime->tm_year + 1900 <<"/"<< std::setfill(PLOG_NSTR('0')) << std::setw(2) << ltime->tm_mon + 1 <<"/"<< std::setfill(PLOG_NSTR('0')) << std::setw(2) << ltime->tm_mday << "_";ss << std::setfill(PLOG_NSTR('0')) << std::setw(2) << ltime->tm_hour << PLOG_NSTR(":") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << ltime->tm_min << PLOG_NSTR(":") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << ltime->tm_sec << ".";ss << std::setfill(PLOG_NSTR('0')) << std::setw(3) <<t.millitm << "] ";ss << std::setw(5) << std::left << std::setfill(PLOG_NSTR(' ')) <<severityToString(record.getSeverity()) <<" [" << record.getTid()<< "]"<<" [" << record.getFunc() << ":" << record.getLine() << "] " << record.getMessage() << "\n";return ss.str();}};}void polgFunc(){PLOG_DEBUG << "DEBUG join polgFunc func";PLOG_INFO << "DEBUG join polgFunc func";PLOG_ERROR << "DEBUG join polgFunc func";}int main(){// 日志初始化// 参数1 - 日志级别, 参数2 - 日志文件名, 参数3 - 单个日志大小, 参数4 - 日志回滚数// 如果不想实现日志回滚,参数3和参数4可以不填或者填0// plog::init(plog::info, "plog.log", 1024, 5);plog::init<plog::MyFormatter>(plog::info, "plogformat.log", 1024, 5); // 同时打印到控制台plog::ColorConsoleAppender<plog::TxtFormatter> consoleAppender;plog::get()->addAppender(&consoleAppender); // Also add logging to the console.int iData = 10020;double fData = 3.141592654; std::string sData = "hello plog";PLOG_DEBUG << "debug hello log!"; LOG_INFO << "info hello log!";PLOG_WARNING << "warning hello log!";PLOG_ERROR << "error hello log!";PLOG_INFO << "int data : " << iData;PLOG_INFO << "int hex data : " << std::hex << iData;PLOG_INFO << "float data : " << fData;PLOG_INFO << "float data : " << std::fixed << std::setprecision(2) << fData;PLOG_INFO << "string data : " << fData;polgFunc();system("pause");return 0;}
- 文件打印:再运行看下文件中的打印
- 可以看到,打印的格式就是我们自定义的格式。
在线程中打印
-
可以在线程中打印
-
main.cpp
-
#include <plog/Log.h> #include <plog/Initializers/RollingFileInitializer.h>#include <string.h>#include <iostream>#include <windows.h>#include <process.h>unsigned int __stdcall ThreadFun(PVOID lpParam) {PLOG_DEBUG << "debug ThreadFun!";LOG_INFO << "info ThreadFun!";PLOG_WARNING << "warning ThreadFun!";PLOG_ERROR << "error ThreadFun!";return 0;}int main(){plog::init(plog::info, "plog.log", 1024, 5);HANDLE handle1 = (HANDLE)_beginthreadex(NULL, 0, ThreadFun, NULL, 0, NULL);HANDLE handle2 = (HANDLE)_beginthreadex(NULL, 0, ThreadFun, NULL, 0, NULL);HANDLE handle3 = (HANDLE)_beginthreadex(NULL, 0, ThreadFun, NULL, 0, NULL);system("pause");return 0;}
-
打印结果
-
可以看到不同线程中的线程id
在多个文件中打印
- 多个文件中如何打印呢?只需要通过 plog::init 在程序入口处初始化,然后在其他文件中包含 #include <plog/Log.h> 头文件直接通过 PLOG_INFO 打印即可,不需要传任何参数,使用非常方便。这里就不演示了。