C++spdlog学习总结

2023-10-29

spdlog简介

(1)按照官方介绍,是一个高性能的C++日志组件,支持跨平台,兼容 C++11;一款开源的、快速的日志库;
(2)spdlog是个只有头文件的库,只需要将头文件拷贝到你的工程就可以使用了,编译器需要支持C++11
它使用一个类似python的格式API库fmt:

spdlog优点

  1. 配置特别简单,仅包含头文件即可(我暂时没测试成功 在我测试时需要引入静态库)
  2. 写日志方式简单明了;
  3. 可实现自动按日期创建日志文件/定时创建日志文件;
  4. 可自定义日志格式;
  5. 可以输出当前输出日志所在的文件及函数;
  6. 可自定义文档大小;
  7. 可将不同级别的信息输出到不同日志文件;
  8. 多平台等。

一般日志功能设计

一般在实际工作中,日志最好要有以下3个功能:
①:自动按日期创建日志文件;
②:自动定期清理过期日志(spdlog好像没有这个功能…);
③:实时刷新日志。
具体分析:
①:一天只创建一个日志文件(或者将各级别的日志单独创建为一个文件)是为了更加清晰简洁,若程序在每次开启时都创建一个日志文件,可能就会显得很混乱。
②:一般时间较久的日志不再具有参考价值,如果真是现场出现问题,用户也不会等很久才反馈。所以一般保存7天内的日志就足够了。
③:当我们需要查看日志时,但又不能关闭现场程序,那么就需要能实时刷新日志信息。不然我们可能会遇到日志文件打不开或者打开以后日志信息未更新的问题。

spdlog安装

[1] 安装配置测试链接
[2] Vcpkg全自动方式
[3] C++参考手册
[4] 总体概括

spdlog琐碎知识点总结

(1)线程安全:spdlog:: 命名空间下的是线程安全的;类似于:spdlog::set_error_handler(log_err_handler); // or logger->set_error_handler(log_err_handler);
(2)对于sinks,以 _mt 后缀结尾的是线程安全的,比如:daily_file_sink_mt,以_st 后缀结尾的是非线程安全的,比如:daily_file_sink_st
(3)有关异步设置logger – 多线程 – (4)中相关细节也可查看
(4)使用spdlog::get("...")访问loggers缺点:loggers可以在任何地方使用线程安全的spdlog::get("logger_name")来进行访问,返回智能指针;注意:spdlog::get可能会拖慢你的程序,因为它内部维护了一把锁,所以要谨慎使用。比较推荐的用法是保存返回的shared_ptr<spdlog::logger>,直接使用它,至少在频繁访问的代码中。详情参考(3)链接

spdlog程序测试

(一)日志输出控制台

链接中包含cmake文件配置

(1)数据全部输出到控制台

spdlog灵魂所在:自动识别类型,避免%d,%s类型错误,输出不了内容或者崩溃

LogDebug(“cmd_id={},bodyLen={}”, 1, 2);
LogInfo(“user_id={},app_id={},domainId={},ip={},port={}”, 222, 222, 222, “127.0.0.1”, 8888);

#include <iostream>
#include <memory>
#include "spdlog/spdlog.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/sinks/daily_file_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h"
int main01(int argc, char* argv[]) 
{
	/*创建一个控制台对象*/
	auto console = spdlog::stdout_color_mt("ybhy");
	/*在控制台输出以下数据 -- 不同的等级有不同的颜色对应 :info、error、warn、critical*/
	console->info("信息");
	console->warn("警告");
	console->error("错误");
	console->critical("危险");
	/*上面的另一种写法*/
	spdlog::info("信息");
	spdlog::warn("警告");
	spdlog::error("错误");
	spdlog::critical("危险");

	/*根据对象输出到控制台 -- 类似于指定用户那种*/
	console->info("Welcome to spdlog!");
	console->info("Support for floats {:03.2f}", 1.23456);
	console->info("Positional args are {1} {0}..", "too", "supported");
	console->info("{:<30}", "left aligned");
	console->warn("Easy padding in numbers like {:08d}", 12);
	console->error("Some error message with arg{}..", 1);
	console->critical("Support for int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}", 42);
	/*通过 get() 方法获取 相关对象指针 -- 输入相关数据*/
	spdlog::get("ybhy")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name) function");
	/*显示格式*/
	spdlog::set_pattern("[%Y-%m-%d %H:%M:%S] [%l] [%n],%v");
	/*关闭所有logger对象*/
	spdlog::drop_all();
	return 0}

运行结果如下
运行结果

(2)指定某个等级以上的数据到控制台

spdlog::set_level(spdlog::level::warn);

enum level_enum //等级表
{
trace = SPDLOG_LEVEL_TRACE, // 最低
debug = SPDLOG_LEVEL_DEBUG,
info = SPDLOG_LEVEL_INFO,
warn = SPDLOG_LEVEL_WARN,
err = SPDLOG_LEVEL_ERROR,
critical = SPDLOG_LEVEL_CRITICAL, // 最高
off = SPDLOG_LEVEL_OFF,
n_levels
};

#include <iostream>
#include <memory>
#include "spdlog/spdlog.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/sinks/daily_file_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h"
int main01(int argc, char* argv[]) 
{
	/*创建一个控制台对象*/
	auto console = spdlog::stdout_color_mt("ybhy");
	/*设计运行等级 -- 等级以下 不显示 相当于 warn以下的信息不打印*/
	spdlog::set_level(spdlog::level::warn); 
	/*在控制台输出以下数据 -- 不同的等级有不同的颜色对应 :info、error、warn、critical*/
	console->info("信息");
	console->warn("警告");
	console->error("错误");
	console->critical("危险");
	/*上面的另一种写法*/
	spdlog::info("信息");
	spdlog::warn("警告");
	spdlog::error("错误");
	spdlog::critical("危险");
	/*根据对象输出到控制台 -- 类似于指定用户那种*/
	console->info("Welcome to spdlog!");
	console->info("Support for floats {:03.2f}", 1.23456);
	console->info("Positional args are {1} {0}..", "too", "supported");
	console->info("{:<30}", "left aligned");
	console->warn("Easy padding in numbers like {:08d}", 12);
	console->error("Some error message with arg{}..", 1);
	console->critical("Support for int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}", 42);
	/*通过 get() 方法获取 相关对象指针 -- 输入相关数据*/
	spdlog::get("ybhy")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name) function");
	/*显示格式*/
	spdlog::set_pattern("[%Y-%m-%d %H:%M:%S] [%l] [%n],%v");
	return 0}

运行结果如下
运行结果

(二)输出格式的自定义方式

熟悉函数:spdlog::set_pattern("[%Y-%m-%d %H:%M:%S] [%l] [%n],%v");

  1. 模式标记
flag meaning example
%v The actual text to log(要记录的实际文本) “some user text”
%t Thread id “1232”
%P Process id “3456”
%n Logger’s name “some logger name”
%l The log level of the message “debug”, “info”, etc
%L The log level of the message “D”, “I”, etc
%a Abbreviated weekday name(工作日的缩写) “Thu”
%@ Source file and line (use SPDLOG_TRACE(…),SPDLOG_INFO(…) etc.) my_file.cpp:123
%s Source file (use SPDLOG_TRACE(…),SPDLOG_INFO(…) etc.) my_file.cpp
%# Source line (use SPDLOG_TRACE(…),SPDLOG_INFO(…) etc.) 123
%! Source function (use SPDLOG_TRACE(…),SPDLOG_INFO(…) etc. see tweakme for pretty-print) my_func
  1. 对齐
    对齐
  2. 相关程序测试

细节把握
(1)spdlog::set_pattern("[%Y-%m-%d %H:%M:%S] [%l] [%n],%v"); 可以放在最后(显示的时候会根据不同的level显示不同的颜色),可以放在最前(无颜色)
(2)在使用<%@><%s><%#><%!> 不是直接写上就可以,需要调用相对应的函数宏才可实现;目前调研中掌握了两种方法:①通过调用宏函数 ②自己编写一个函数宏来调用本身程序;
(3)具体实现:①通过调用宏函数:引入#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE,在程序中调用对应宏,比如:SPDLOG_LOGGER_INFO(spdlog::get("ybhy"),"faf"); ②自己编写一个函数宏来调用本身程序:如下代码所示:

#include <iostream>
#include <memory>
#include "spdlog/spdlog.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/sinks/daily_file_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h"
/*以下宏函数将信心打印到控制台和文件*/
#define DEBUG(...) SPDLOG_LOGGER_DEBUG(spdlog::default_logger_raw(), __VA_ARGS__);SPDLOG_LOGGER_DEBUG(spdlog::get("daily_logger"), __VA_ARGS__)
#define LOG(...) SPDLOG_LOGGER_INFO(spdlog::default_logger_raw(), __VA_ARGS__);SPDLOG_LOGGER_INFO(spdlog::get("daily_logger"), __VA_ARGS__)
#define WARN(...) SPDLOG_LOGGER_WARN(spdlog::default_logger_raw(), __VA_ARGS__);SPDLOG_LOGGER_WARN(spdlog::get("daily_logger"), __VA_ARGS__)
#define ERROR(...) SPDLOG_LOGGER_ERROR(spdlog::default_logger_raw(), __VA_ARGS__);SPDLOG_LOGGER_ERROR(spdlog::get("daily_logger"), __VA_ARGS__)

int main(int argc, char* argv[])
{
	// 每天2:30 am 新建一个日志文件
	auto logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
	// 遇到warn flush日志,防止丢失
	logger->flush_on(spdlog::level::warn);
	//每三秒刷新一次
	spdlog::flush_every(std::chrono::seconds(10));
	
	//将默认记录器设置为文件记录器
	auto console = spdlog::stdout_color_mt("ybhy");
	spdlog::set_default_logger(console);
	spdlog::set_level(spdlog::level::debug); // Set global log level to debug
	//打印相关信息
	LOG("test info");//将信息打印到控制台和文件
	ERROR("test error");
	WARN("dadasda");
	// %s:文件名
	// %#:行号
	// %!:函数名
	spdlog::set_pattern("[%Y-%m-%d %H:%M:%S] [%l] [%n] - <%@>,%v");
	spdlog::drop_all();
	return 0;
}

运行结果如下

答疑:为什么文件中写进的是“daily_logger”。而控制台是“ybhy”,是因为两者的logger对象不一致’
细节:在写入文件时注意:spdlog::set_level(spdlog::level::err);,如果你设计成“err”,那么文件中也只会保存等级为“error”以上的数据

输出信息

(三)数据输出到文件

(1)三种创建文件的方式

  1. basic_logger_mt
    a:说明:日志文件一直会被写入,不断变大
    b:案例:
    auto my_logger = spd::basic_logger_mt("basic_logger", "logs/basic-log.txt");
    my_logger->info("Some log message");
    
  2. rotating_logger_mt
    a:说明:滚动日志,当日志文件超出规定大小时,会删除当前日志文件中所有内容,重新开始写入
    b:函数原型:rotating_logger_mt(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files)
    c:参数介绍:参数max_files 规定了滚动文件的个数。当logger_name存满时,将其名称更改为logger_name.1,再新建一个logger_name文件来存储新的日志。再次存满时,把logger_name.1改名为logger_name.2,logger_name改名为logger_name.1,新建一个logger_name来存放新的日志。max_files 数量为几,就可以有几个logger_name文件用来滚动。
    d:案例:
    auto rotating_logger = spd::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 256, 2);
    for (int i = 0; i < 10; ++i)
         rotating_logger->info("{} * {} equals {:>10}", i, i, i*i);
    
    e:测试结果
    每个文件内容如下,后缀数字越大,日志内容越早:测试结果
  3. daily_logger_mt
    a:说明:每天会新建一个日志文件,新建日志文件的时间可自己设定
    b:案例:
    	// Create a daily logger - a new file is created every day on 2:30am
        auto daily_logger = spd::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
        // trigger flush if the log severity is error or higher
        daily_logger->flush_on(spd::level::err);
        daily_logger->info(123.44);
    
    c:测试结果:
    测试
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++spdlog学习总结 的相关文章

  • 如何将非静态类成员“std::bind”绑定到 Win32 回调函数“WNDPROC”?

    我正在尝试将非静态类成员绑定到标准WNDPROC http msdn microsoft com en us library ms633573 aspx功能 我知道我可以通过将类成员设为静态来简单地做到这一点 但是 作为一名 C 11 ST
  • 计算 Richtextbox 中所有单词的最有效方法是什么?

    我正在编写一个文本编辑器 需要提供实时字数统计 现在我正在使用这个扩展方法 public static int WordCount this string s s s TrimEnd if String IsNullOrEmpty s re
  • C中的malloc内存分配方案

    我在 C 中尝试使用 malloc 发现 malloc 在分配了一些内存后浪费了一些空间 下面是我用来测试 malloc 的一段代码 include
  • 在 C 中匹配二进制模式

    我目前正在开发一个 C 程序 需要解析一些定制的数据结构 幸运的是我知道它们是如何构造的 但是我不确定如何在 C 中实现我的解析器 每个结构的长度都是 32 位 并且每个结构都可以通过其二进制签名来识别 举个例子 有两个我感兴趣的特定结构
  • 当我们想要返回对象的引用时,为什么我们在赋值运算符中返回 *this 而通常(而不是 this)?

    我正在学习 C 和指针 我以为我理解了指针 直到我看到这个 一方面 asterix 运算符是解引用的 这意味着它返回值所指向的地址中的值 而与号 运算符则相反 它返回值存储的地址记忆 现在阅读有关赋值重载的内 容 它说 我们返回 this因
  • 使用 LINQ2SQL 在 ASP.NET MVC 中的各种模型存储库之间共享数据上下文

    我的应用程序中有 2 个存储库 每个存储库都有自己的数据上下文对象 最终结果是我尝试将从一个存储库检索到的对象附加到从另一个存储库检索到的对象 这会导致异常 Use 构造函数注入将 DataContext 注入每个存储库 public cl
  • 复制目录内容

    我想将目录 tmp1 的内容复制到另一个目录 tmp2 tmp1 可能包含文件和其他目录 我想使用C C 复制tmp1的内容 包括模式 如果 tmp1 包含目录树 我想递归复制它们 最简单的解决方案是什么 我找到了一个解决方案来打开目录并读
  • java.io.Serialized 在 C/C++ 中的等价物是什么?

    C C 的等价物是什么java io Serialized https docs oracle com javase 7 docs api java io Serializable html 有对序列化库的引用 用 C 序列化数据结构 ht
  • qdbusxml2cpp 未知类型

    在使用 qdbusxml2cpp 程序将以下 xml 转换为 Qt 类时 我收到此错误 qdbusxml2cpp c ObjectManager a ObjectManager ObjectManager cpp xml object ma
  • 具有交替类型的可变参数模板参数包

    我想知道是否可以使用参数包捕获交替参数模式 例如 template
  • 如何在 Xaml 文本中添加电子邮件链接?

    我在 Windows Phone 8 应用程序中有一些大文本 我希望其中有电子邮件链接 例如 mailto 功能 这是代码的一部分
  • C#:帮助理解 UML 类图中的 <>

    我目前正在做一个项目 我们必须从 UML 图编写代码 我了解 UML 类图的剖析 但我无法理解什么 lt
  • Azure 辅助角色“请求输入之一超出范围”的内部异常。

    我在辅助角色中调用 CloudTableClient CreateTableIfNotExist 方法 但收到一个异常 其中包含 请求输入之一超出范围 的内部异常 我做了一些研究 发现这是由于将表命名为非法表名引起的 但是 我尝试为我的表命
  • C# 中的合并运算符?

    我想我记得看到过类似的东西 三元运算符 http msdn microsoft com en us library ty67wk28 28VS 80 29 aspx在 C 中 它只有两部分 如果变量值不为空 则返回变量值 如果为空 则返回默
  • AES 128 CBC 蒙特卡罗测试

    我正在 AES 128 CBC 上执行 MCT 如中所述http csrc nist gov groups STM cavp documents aes AESAVS pdf http csrc nist gov groups STM ca
  • 动态添加 ASP.Net 控件

    我有一个存储过程 它根据数据库中存储的记录数返回多行 现在我想有一种方法来创建 div 带有包含该行值的控件的标记 如果从数据库返回 10 行 则 10 div 必须创建标签 我有下面的代码来从数据库中获取结果 但我不知道如何从这里继续 S
  • 将 MQTTNet 服务器与 MQTT.js 客户端结合使用

    我已经启动了一个 MQTT 服务器 就像this https github com chkr1011 MQTTnet tree master例子 该代码托管在 ASP Net Core 2 0 应用程序中 但我尝试过控制台应用程序 但没有成
  • 如何在非控制台应用程序中查看 cout 输出?

    输出到调试窗口似乎相当繁琐 我在哪里可以找到cout如果我正在编写非控制台信息 则输出 Like double i a b cout lt lt b lt lt endl I want to check out whether b is z
  • 调用堆栈中的“外部代码”是什么意思?

    我在 Visual Studio 中调用一个方法 并尝试通过检查调用堆栈来调试它 其中一些行标记为 外部代码 这到底是什么意思 方法来自 dll已被处决 外部代码 意味着该dll没有可用的调试信息 你能做的就是在Call Stack窗口中单
  • 如何部署“SQL Server Express + EF”应用程序

    这是我第一次部署使用 SQL Server Express 数据库的应用程序 我首先使用实体 框架模型来联系数据库 我使用 Install Shield 创建了一个安装向导来安装应用程序 这些是我在目标计算机中安装应用程序所执行的步骤 安装

随机推荐

  • 代码审计-Java项目&JDBC&Mybatis&Hibernate&注入&预编译&写法

    文章目录 Javaweb 数据库操作 模式 写法 预编译等 环境搭建 JDBC 注入分析 关于预编译 Mybatis 注入分析 Hibernate 注入分析 总结 Javaweb 代码审计SQL注入 INXEDU在线网校 Javaweb 数
  • python构建IP代理池(Proxy Pool)

    基本原理 代理实际上指的就是代理服务器 它的功能是代理网络用户去取得网络信息 也可以说它是网络信息的中转站 在我们正常请求一个网站时 是将请求发送给 Web 服务器 Web 服务器把响应传回给我们 如果设置了代理服务器 实际上就是在本机和服
  • 多数据源配置(application.properties或application.yml配置详情)

    1 导入Maven依赖
  • ssh key问题解决

    u r the butter of my bread the breath to my life Julie Julia 某些情况下 原来的ssh连接会失效 比如误删了 ssh下面的东西 这时 需要重新生成key并加入gitlab或gith
  • 列表的基本操作

    描述 在两行中分别输入一个字符串 分别将其转换为列表 a 和 b 按要求完成以下功能 1 输出两个列表的拼接结果 2 输出列表 a 重复3次的结果 3 输出列表 b 中第3个元素和最后一个元素 4 输出列表 a 中序号1至4之间的元素 5
  • git工具下载

    文章目录 下载客户端 git下载教程 git下载地址 Tortoise下载地址 Tortoise下载教程 Git以及Github详细解析教程 码云学习安装视频 下载客户端 git下载教程 https www cnblogs com xuew
  • Android 使用updatefun 来自动更新

    这几天研究了一下APP的自动更新 并且是那种最方便使用的 找了一下 找到一个框架 updatefun 使用方法比较简单 记录一下使用方法和遇到的问题 使用步骤 1 使用Android studio 的依赖方式 dependencies co
  • 快速定位当前页面的Activity

    方法1 通过AndroidStudio的Terminal 利用一个指令可以快速定位当前页面的类名 1 把手机用数据线连到电脑 手机打开到需要的定位的页面 2 打开AndroidStudio 在AndroidStudio底部选择Termina
  • 实现一个简单的python小脚本的一些必要步骤

    1 编写python代码时在开头添上 python27 2 设置环境变量路径 在系统变量path中新建一个你要运行python脚本的文件夹的绝对路径 D python 3 运行方式 a 直接双击xx py文件 b 添加环境变量后 在cmd中
  • 工程有限元(1)

    有限法的基本思想 有限元概述 结构分析问题 有限元法的思路 有限元法的一般步骤 本文内容是整理的 工程有限元 课程内容 便于日后复习以及读者学习 有限元概述 有限元法 Finite Element Anaslysis FEM 是通过数学描述
  • c++继承下

    继承的方式主要分为单继承 多继承 菱形继承 普通单继承 指向派生类的基类指针或者引用 其类型仍然属于基类类型 而不是派生类类型 include
  • for(auto i : v)遍历容器元素

    for auto i v 遍历容器元素 1 auto 2 auto 3 const auto 4 const auto C 11 新增了一种循环 基于范围 range based 的 for 循环 这简化了一种常见的循环任务 对数组 或容器
  • 计算机重新如何连接网络打印机,电脑怎样连接打印机,小编教你电脑如何连接网络打印机...

    打印机是办公室里经常会用到的一种办公设备 由于工作性质的不同 以及其他原因 网络打印机可以实现多台电脑连接 实现资源共享 网络打印机自带ip 只需指定ip就可以快速连接 那电脑如何连接网络打印机 下面 小编给大家讲解电脑连接网络打印机的技巧
  • 基于类帕累托贯序抽样算法求解单目标优化问题附matlab代码

    作者简介 热爱科研的Matlab仿真开发者 修心和技术同步精进 matlab项目合作可私信 个人主页 Matlab科研工作室 个人信条 格物致知 更多Matlab完整代码及仿真定制内容点击 智能优化算法 神经网络预测 雷达通信 无线传感器
  • 智能合约平台开发指南

    随着区块链技术的普及 智能合约平台已经成为了这个领域的一个重要趋势 智能合约可以自动化执行合同条款 大大减少了执行和监督合同条款所需的成本和时间 那么 如何开发一个智能合约平台呢 以下是一些关键步骤 一 选择合适的区块链平台 智能合约通常运
  • pgsql数据库实现导入导出

    pgsql数据库实现导入导出 1 导出表 pg dump h 数据库ip U 用户名 数据库名 t 表名 gt 路径 例 pg dump h 127 0 0 1 U sysdba data center t book gt data boo
  • Prompt入门

    Prompt的范式大抵是两种 续写Prefix 用在GPT2 3那种单向LM预训练模型上 输入 好好学习 翻译成英文 输出 good good study 完形填空 用在BERT那种MLM式预训练模型上 比如情感分类任务可以输入 这个饼不错
  • Idea 中 Git 不提交当前分支修改代码并切换分支

    1 当前分支修改代码切换分支 日常开发中 我们可能会碰到我们正在修改当前 01 分支的代码 突然要去修改另外一个 02 分支的代码情况 而我们 01 分支写的代码还未经过测试 并不能马上提交 这个时候我们切换到 02 分支就会有问题 比如弹
  • dubbo中的Mock实现机制

    Mock是SOA之中的一个很有用的功能 不仅可以用来进行服务降级 也可以用来在测试中模拟服务调用的各种异常情况 dubbo框架里面的mock是在服务使用者这一端实现的 下面对实现机制进行分析 1 Mock的植入 很显然 既然提供了mock机
  • C++spdlog学习总结

    C Spdlog学习笔记 spdlog简介 spdlog优点 一般日志功能设计 spdlog安装 spdlog琐碎知识点总结 spdlog程序测试 一 日志输出控制台 1 数据全部输出到控制台 2 指定某个等级以上的数据到控制台 二 输出格