文章目录

  • 前言
  • spdlog的基本使用
  • spdlog日志库的封装

前言

编码过程中,日志是必要的一个组件,我们选择使用哪个日志库呢?

参考:15 best C++ Logging libraries in 2022

C++ 日志库用于在用 C++ 编写的应用程序中记录信息。日志记录可以在不同的粒度级别、不同的日志类型和不同的输出目标上完成。一个好的日志库是任何应用程序的关键组件。它允许您执行各种调试任务,例如跟踪错误、监控性能甚至跟踪用户操作。日志记录是一种跟踪程序正在做什么的方法。在收集统计数据、分析性能问题,甚至只是为了大致了解应用程序内部发生的情况时,日志也很有用。有几个流行的 C++ Logging 开源库可供开发人员使用: spdlog - 快速 C 日志记录库;glog - Google 日志模块的 C 实现;easyloggingpp - 单头 C 日志库。

随大流,选择使用人数多,商业友好的spdlog


spdlog的基本使用

见官方文档:spdlog


spdlog日志库的封装

在一个多人合作的项目中,日志库封装的越顺手,程序员在代码中越多的使用日志语句,给后续的分析bug带来便利。

第一种封装方式,是只封装一个日志库。好处是封装起来较为容易,从而封装的效果也比较好;坏处是不便于替换使用其他日志库。

第二种封装方式,以相同的接口,同时封装多种日志库,在编译的时候,使用编译选项决定使用哪种日志库。好处是可以替换使用日志库。缺点是增大了封装的难度,在程序员水平一定的时候,封装的效果不大好。

spdlog直接拿过来不太好用。比如,我想在一个进程的任何地方,都可以使用同一个logger。这是一个比较合理的要求,只用初始化一次,只输出到一个日志文件。我们可以在main中初始化一日志,在进程的其他地方,使用 spdlog::get线程安全的访问记录器。这样做的缺点是,使用日志库的所有程序员都需要知道spdlog库api的使用方式。

所以,我们需要对日志库进行封装,屏蔽掉细节,以保证日志库被方便安全的被使用

在封装的时候,我在考虑要不要将其封装成单例模式。在整个进程中使用同一个logger,似乎是可以封装成单例模式,或者全局变量?。但是如果此时,在一个进程中,希望可以有两个或者多个功能的logger,则不应该使用单例模式。

最后,我选择使用单例模式。因为,如果有在一个进程中使用多种logger,那似乎可以将程序分为多进程。

因日志库,而不得不拆分程序为多进程,似乎是不应该的。先写成单例模式吧,日志有需要再修改。

boost1.46曾有过Singleton的类模板,本打算借鉴借鉴,但这个类被移除了。参考下面两个链接,使用static来实现单例。(文中讨论的单例模式的缺点,没看懂,懵~)

  • Modern C++ Singleton Template
  • What are drawbacks or disadvantages of singleton pattern

下面是对日志库的封装。这个封装的使用,可参考da1234cao/FreeFile:

#pragma once// 参考1:https://blog.csdn.net/gongjianbo1992/article/details/113279632
// 参考2:https://techartlife.com/%E8%AE%A1%E7%AE%97%E6%9C%BA/%E7%BC%96%E7%A8%8B/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/cpp/%E5%B0%81%E8%A3%85spdlog%E5%BA%93/
// 参考3:https://github.com/SergiusTheBest/plog/blob/master/include/plog/Log.h#include "exception.hpp"
#include <memory>
#include <string>
#include <algorithm>
#include <spdlog/spdlog.h>
#include <spdlog/sinks/rotating_file_sink.h>namespace Log {struct log_execption : virtual base_exception {};class SPDLOG {
private:SPDLOG() = default;
private:std::shared_ptr<spdlog::logger> logger_ptr_;void setLogLevel(const std::string& level);public:static SPDLOG& getInstance() {static SPDLOG instance;return instance;}// 初始化一个默认日志文件logger: 日志路径;logger name; 日志等级;单个日志文件最大大小;回滚日志文件个数;日志是否线程安全;void init(std::string log_file_path,std::string logger_name, std::string level, size_t max_file_size, size_t max_files, bool mt_security = false); std::shared_ptr<spdlog::logger> logger() { return logger_ptr_; }
}; // SPDLOG class#define LOG_TRACE(...)       SPDLOG::getInstance().logger().get()->trace(__VA_ARGS__)
#define LOG_DEBUG(...)       SPDLOG::getInstance().logger().get()->debug(__VA_ARGS__)
#define LOG_INFO(...)        SPDLOG::getInstance().logger().get()->info(__VA_ARGS__)
#define LOG_WARN(...)        SPDLOG::getInstance().logger().get()->warn(__VA_ARGS__)
#define LOG_ERROR(...)       SPDLOG::getInstance().logger().get()->error(__VA_ARGS__)
#define LOG_CRITICAL(...)    SPDLOG::getInstance().logger().get()->critical(__VA_ARGS__)
} // Log namespacevoid Log::SPDLOG::init(std::string log_file_path, std::string logger_name, std::string level, size_t max_file_size, size_t max_files, bool mt_security)
{try {if (mt_security) {logger_ptr_ = spdlog::rotating_logger_mt(logger_name, log_file_path, max_file_size, max_files);}else {logger_ptr_ = spdlog::rotating_logger_st(logger_name, log_file_path, max_file_size, max_files);}setLogLevel(level);logger_ptr_->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] [%t] [%s %!:%#] %v"); //设置格式:https://spdlog.docsforge.com/v1.x/3.custom-formatting/} catch (const spdlog::spdlog_ex& ex) {BOOST_THROW_EXCEPTION(log_execption()<< err_str("Log initialization failed: " + std::string(ex.what())));}
}void Log::SPDLOG::setLogLevel(const std::string &level)
{char L = toupper(level[0]);if (L == 'T') { // tracelogger_ptr_->set_level(spdlog::level::trace);logger_ptr_->flush_on(spdlog::level::trace);}else if (L == 'D') { // debuglogger_ptr_->set_level(spdlog::level::debug);logger_ptr_->flush_on(spdlog::level::debug);}else if (L == 'I') { // infologger_ptr_->set_level(spdlog::level::info);logger_ptr_->flush_on(spdlog::level::info);}else if (L == 'W') { // warnlogger_ptr_->set_level(spdlog::level::warn);logger_ptr_->flush_on(spdlog::level::warn);}else if (L == 'E') { // errorlogger_ptr_->set_level(spdlog::level::err);logger_ptr_->flush_on(spdlog::level::err);}else if (L == 'C') { // criticallogger_ptr_->set_level(spdlog::level::critical);logger_ptr_->flush_on(spdlog::level::critical);} else {BOOST_THROW_EXCEPTION(log_execption()<< err_str("level set error " + level));}
}

spdlog日志库的封装使用相关推荐

  1. spdlog日志库说明文档(超详细)

    spdlog日志库说明文档(超详细) spdlog是一个开源.快速.只有头文件的C++11日志库,code地址在https://github.com/gabime/spdlog,基础示例在https: ...

  2. spdlog 日志库学习,简易封装

    spdlog wiki:https://github.com/gabime/spdlog/wiki 别人的学习笔记:https://www.cnblogs.com/oucsheep/p/8426548 ...

  3. spdlog日志库使用说明

    安装 git clone https://github.com/gabime/spdlog.git cd spdlog && mkdir build cd build cmake .. ...

  4. spdlog 日志库学习,自定义 sink

    spdlog wiki:https://github.com/gabime/spdlog/wiki 别人的学习笔记:https://www.cnblogs.com/oucsheep/p/8426548 ...

  5. Python日志库logging、loguru、Eliot

    文章目录 简介 初试 日志基础教程 消息格式 日志属性 信息流程 通过配置文件创建 PyCharm日志插件 封装 loguru入门 Eliot入门 参考文献 简介 logging,Python内置库, ...

  6. c++日志库实战——spdlog,是不是感觉log4cxx有点笨重,不妨试一试spdlog

    c++日志库实战--spdlog,是不是感觉log4cxx有点笨重,不妨试一试spdlog 背景 更新记录 spdlog是什么 spdlog快速入门 编译 CMake手动方式 Vcpkg全自动方式(推 ...

  7. go zap日志库的使用,以及封装。

    go zap日志库使用说明 及 封装 1 zap日志的基本使用 1.0 zap简介 1.1 日志介绍 1.2 为什么选择zap日志 1.3 zap的安装 1.4 创建实例-两种类型 1.4.1 Log ...

  8. 服务器开发27:log4c充当服务器跨平台日志库(cmake跨平台编译,配置介绍及代码封装)

    文章目录 一.跨平台编译 1)编译准备 (1)expat编译 2)原生linux编译.安装 3)cmake跨平台编译 二.log4c配置笔记 1)与log4cpp\log4cxx的比较 2)log4c ...

  9. 【c++】SPDLOG动态库和静态库、异步日志库hang 问题、registry核心类

    spdlog 官方支持动态库和静态库 静态库 SPDLOG_COMPILED_LIB SPDLOG_API 这个就是空的 静态库里 SPDLOG_INLINE 也是空的: 动态库: SPDLOG_SH ...

最新文章

  1. 蓝凌ekp开发_新华教育集团战略升级,携手蓝凌量身定制数字化办公平台
  2. HarmonyOS之常用组件WebView的使用
  3. webService学习记录
  4. 浅析软件项目管理中十个误区(来自:http://manager.csdn.net/n/20051213/30907.html)
  5. Linux监控CPU关闭服务器,监控Linux服务器CPU和内存
  6. 论文浅尝 | Convolutional 2D knowledge graph embedding
  7. mysql binlog查看_MySQL--17 配置binlog-server 及中间件
  8. oracle 对两列加唯一性束_oracle中创建unique唯一约束(单列和多列) 。
  9. python利用myqr库生成二维码
  10. 精品资源:40个实用的 PSD 贴纸模板《下篇》
  11. PHP读取Excel数据
  12. 卷积码树状图怎么画_卷积码编码器怎么画 浅谈卷积码编码器设计
  13. HC-05蓝牙模块主从机通信
  14. 按需使用vue-cli-plugin-element插件
  15. wps插入尾注(罗马数字变阿拉伯数字,即i变1)的操作方法
  16. 调用聚合数据新闻头条API
  17. 实验六 配置GVRP协议
  18. [2008-12-12]希捷桌面、笔记本硬盘质保期缩短至3年
  19. 用于520的20年前的图片
  20. 【BZOJ 1196】[HNOI2006]公路修建问题

热门文章

  1. 如何自下而上删除Linux的空文件夹
  2. 浅析web api的json参数校验
  3. 被动FTP虚拟服务器设置,在IIS上设置FTP被动模式的端口范围
  4. 程序员如何通过创作图文项目实现自己的代码价值
  5. 过了这么多年,我终于学会跟Office说再见
  6. 给开发人员培训时的语录
  7. Oracle修改check约束的sql语句
  8. 程序员向暗恋的女神鼓起勇气表白……但这结局猝不及防
  9. 如何用tableau画桑基图(决策树)
  10. 用nodejs写一个简易小爬虫