IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++spdlog学习总结 -> 正文阅读

[C++知识库]C++spdlog学习总结

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. 模式标记
flagmeaningexample
%vThe actual text to log(要记录的实际文本)“some user text”
%tThread id“1232”
%PProcess id“3456”
%nLogger’s name“some logger name”
%lThe log level of the message“debug”, “info”, etc
%LThe log level of the message“D”, “I”, etc
%aAbbreviated weekday name(工作日的缩写)“Thu”
%@Source file and line (use SPDLOG_TRACE(…),SPDLOG_INFO(…) etc.)my_file.cpp:123
%sSource 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:测试结果:
    测试
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-16 11:33:49  更:2021-08-16 11:36:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 4:44:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码