简单好用的C++日志库spdlog使用示例

文章目录

  • 前言
  • 一、spdlog的日志风格
    • fmt风格
    • printf风格
  • 二、日志格式pattern
  • 三、sink,多端写入
  • 四、异步写入
  • 五、注意事项
  • 六、自己封装了的代码
    • usespdlog.h
    • 封装代码解释
    • 使用示例


前言

C++日志库有很多,glog,log4cpp,easylogging++, easylogger, plog,spdlog等等。每个都大致了解过,看过github代码,看下来还是觉得spdlog用起来最方便最简单,head-only。别看easylogging++只有2个文件,但是可读性有点差, plog虽然也比较简单,但是没有异步写日志。
spdlog地址:https://github.com/gabime/spdlog
本项目完整代码github地址


一、spdlog的日志风格

fmt风格

与printf风格不同,spdlog采用的是fmt格式,也就是类似于:

fmt::print("我是{} 我有{}万",小明,1000)

fmt风格比较安全,多一个参数少一个参数都会抛异常,printf是可能会直接内存错误的。

printf风格

虽然spdlog本身只支持fmt风格,但是我们可以自己按printf风格解析然后按无参的形式写入spdlog。

二、日志格式pattern

通过pattern我们可以控制日志的格式,例如以下是一个常用格式:

%^[%Y-%m-%d %H:%M:%S.%e] [%-8l] [%s:%#] %v%$
[2024-06-18 16:27:08.778] [warning ] [Config.cpp:50] 这是一条日志消息

pattern支持日期时间、日志等级显示、代码行数、控制台颜色等常用格式,详细的可以看它github介绍,挺清晰的。上面这个pattern就是时间精确到毫秒,日志等级字段占8个字符左对齐,显示源文件和代码行数,在控制台中按照日志等级显示颜色。
在这里插入图片描述

三、sink,多端写入

sink在其它库里面可能叫appender,就是日志怎么写入终端,写到哪个终端。比如一条日志消息可以同时写入控制台、文件、tcp等等。一般常用的就是写到控制台和文件,文件按日期保存或者按log1.txt,log2.txt切割。

四、异步写入

spdlog中有普通的logger和async_logger,使用异步logger时需要事先初始化一个线程池。

五、注意事项

  1. 普通的logger就是阻塞主线程的,可以使用async_logger异步写日志。
  2. 如果想要打印出源码文件名和序号,必须是用宏才可以,spdlog自带的宏是SPDLOG
  3. 如果用spdlog自带的宏打印,注意它有一个全局日志等级宏SPDLOG_ACTIVE_LEVEL,默认应该是info等级,可以在cmake中加一句话开启所有等级:
add_compile_definitions(SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_TRACE)

六、自己封装了的代码

usespdlog.h

#pragma once
#include "spdlog/spdlog.h"
#include "spdlog/fmt/ostr.h"
#include "spdlog/fmt/bundled/printf.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/sinks/daily_file_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/async.h"
//是否使用fmt格式
//#define USE_FMT_LOG
class useSpdlog {
private:useSpdlog() = default;useSpdlog(const useSpdlog&) = delete;useSpdlog& operator=(const useSpdlog&) = delete;
public:static useSpdlog* config() {static useSpdlog a;return &a;}std::string global_debug_logger_name = "global_debug_logger";std::string global_info_logger_name = "global_info_logger";std::string global_error_logger_name = "global_error_logger";std::string global_debug_logger_path = "cvlogs/vm_global_debug.log";std::string global_info_logger_path = "cvlogs/vm_global_info.log";std::string global_error_logger_path = "cvlogs/vm_global_error.log";std::string default_pattern = "%^[%Y-%m-%d %H:%M:%S.%e] [%-8l] [%s:%#] %v%$";static std::shared_ptr<spdlog::logger> createAsyncRotatingFileLogger(spdlog::level::level_enum level, const std::string& logName = "spdlog", const std::string& logPath = "logs/spdlog.log", bool enableConsole = true, bool enableFile = true, const std::string& pattern = useSpdlog::config()->default_pattern){assert(enableConsole || enableFile);auto p_logger = std::make_shared<spdlog::async_logger>(spdlog::async_logger(logName, {}, spdlog::thread_pool(), spdlog::async_overflow_policy::block));//auto p_logger = std::make_shared<spdlog::logger>(spdlog::logger(logName, {}));if (enableConsole){auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();p_logger->sinks().push_back(console_sink);}if (enableFile){auto file_sink = std::make_shared<spdlog::sinks::daily_file_sink_mt>(logPath, 0, 0, false, 15);p_logger->sinks().push_back(file_sink);}p_logger->set_level(level);p_logger->set_pattern(pattern);return p_logger;}static void initSpdlog(spdlog::level::level_enum level, bool enableconsole = true, bool enableFile = true){//初始化线程池spdlog::init_thread_pool(100, 4);//专门记录trace和debugauto g_debug_logger = createAsyncRotatingFileLogger(spdlog::level::trace, useSpdlog::config()->global_debug_logger_name, useSpdlog::config()->global_debug_logger_path, enableconsole, enableFile);//专门记录infoauto g_info_logger = createAsyncRotatingFileLogger(spdlog::level::info, useSpdlog::config()->global_info_logger_name, useSpdlog::config()->global_info_logger_path, enableconsole, enableFile, "%^[%Y-%m-%d %H:%M:%S.%e] [%-8l] %v%$");//专门记录 warn error cirtialauto g_error_logger = createAsyncRotatingFileLogger(spdlog::level::warn, useSpdlog::config()->global_error_logger_name, useSpdlog::config()->global_error_logger_path, enableconsole, enableFile);spdlog::register_logger(g_debug_logger);spdlog::register_logger(g_info_logger);spdlog::register_logger(g_error_logger);//每三秒刷新一下文件spdlog::flush_every(std::chrono::seconds(3));//设置全局日志等级spdlog::set_level(level);}static void register_AsyncRotatingFileLogger(spdlog::level::level_enum level, const std::string& logName, const std::string& logPath, bool enableConsole = true, bool enableFile = true, const std::string& pattern = useSpdlog::config()->default_pattern){auto p_logger = createAsyncRotatingFileLogger(level, logName, logPath, enableConsole, enableFile, pattern);spdlog::register_logger(p_logger);}static void spd_printf_log(std::shared_ptr<spdlog::logger> logger, spdlog::level::level_enum level, char* file, int line, char* func, char* format, ...){va_list args;va_start(args, format);char buff[1024];vsnprintf(buff, sizeof(buff), format, args);va_end(args);std::string msg = buff;logger->log(spdlog::source_loc{file, line, func}, level, msg);}static void set_level(spdlog::level::level_enum level){spdlog::set_level(level);}
};
//printf格式
#define MODULE_LOG_TRACE_PRINTF(name,...) useSpdlog::spd_printf_log(spdlog::get(name),spdlog::level::level_enum::trace, __FILE__,__LINE__,__FUNCTION__, __VA_ARGS__)
#define MODULE_LOG_DEBUG_PRINTF(name,...) useSpdlog::spd_printf_log(spdlog::get(name),spdlog::level::level_enum::debug, __FILE__,__LINE__,__FUNCTION__, __VA_ARGS__)
#define MODULE_LOG_INFO_PRINTF(name,...) useSpdlog::spd_printf_log(spdlog::get(name),spdlog::level::level_enum::info, __FILE__, __LINE__, __FUNCTION__,__VA_ARGS__)
#define MODULE_LOG_WARN_PRINTF(name,...) useSpdlog::spd_printf_log(spdlog::get(name),spdlog::level::level_enum::warn, __FILE__, __LINE__,__FUNCTION__, __VA_ARGS__)
#define MODULE_LOG_ERROR_PRINTF(name,...) useSpdlog::spd_printf_log(spdlog::get(name),spdlog::level::level_enum::err, __FILE__, __LINE__, __FUNCTION__,__VA_ARGS__)
#define MODULE_LOG_CRITICAL_PRINTF(name,...) useSpdlog::spd_printf_log(spdlog::get(name),spdlog::level::level_enum::critical, __FILE__, __LINE__, __FUNCTION__,__VA_ARGS__)//fmt格式
#define MODULE_LOG_TRACE_FMT(name,...) (spdlog::get(name))->log(spdlog::source_loc{__FILE__, __LINE__, SPDLOG_FUNCTION}, spdlog::level::level_enum::trace, __VA_ARGS__)
#define MODULE_LOG_DEBUG_FMT(name,...) (spdlog::get(name))->log(spdlog::source_loc{__FILE__, __LINE__, SPDLOG_FUNCTION}, spdlog::level::level_enum::debug, __VA_ARGS__)
#define MODULE_LOG_INFO_FMT(name,...) (spdlog::get(name))->log(spdlog::source_loc{__FILE__, __LINE__, SPDLOG_FUNCTION}, spdlog::level::level_enum::info, __VA_ARGS__)
#define MODULE_LOG_WARN_FMT(name,...) (spdlog::get(name))->log(spdlog::source_loc{__FILE__, __LINE__, SPDLOG_FUNCTION}, spdlog::level::level_enum::warn, __VA_ARGS__)
#define MODULE_LOG_ERROR_FMT(name,...) (spdlog::get(name))->log(spdlog::source_loc{__FILE__, __LINE__, SPDLOG_FUNCTION}, spdlog::level::level_enum::err, __VA_ARGS__)
#define MODULE_LOG_CRITICAL_FMT(name,...) (spdlog::get(name))->log(spdlog::source_loc{__FILE__, __LINE__, SPDLOG_FUNCTION}, spdlog::level::level_enum::critical, __VA_ARGS__)//fmt和printf格式选择
#ifndef USE_FMT_LOG
#define MODULE_LOG_TRACE(name,...) MODULE_LOG_TRACE_PRINTF(name, __VA_ARGS__)
#define MODULE_LOG_DEBUG(name,...) MODULE_LOG_DEBUG_PRINTF(name, __VA_ARGS__)
#define MODULE_LOG_INFO(name,...) MODULE_LOG_INFO_PRINTF(name, __VA_ARGS__)
#define MODULE_LOG_WARN(name,...) MODULE_LOG_WARN_PRINTF(name, __VA_ARGS__)
#define MODULE_LOG_ERROR(name,...) MODULE_LOG_ERROR_PRINTF(name, __VA_ARGS__)
#define MODULE_LOG_CRITICAL(name,...) MODULE_LOG_CRITICAL_PRINTF(name, __VA_ARGS__)
#else
#define MODULE_LOG_TRACE(name,...) MODULE_LOG_TRACE_FMT(name, __VA_ARGS__)
#define MODULE_LOG_DEBUG(name,...) MODULE_LOG_DEBUG_FMT(name, __VA_ARGS__)
#define MODULE_LOG_INFO(name,...) MODULE_LOG_INFO_FMT(name, __VA_ARGS__)
#define MODULE_LOG_WARN(name,...) MODULE_LOG_WARN_FMT(name, __VA_ARGS__)
#define MODULE_LOG_ERROR(name,...) MODULE_LOG_ERROR_FMT(name, __VA_ARGS__)
#define MODULE_LOG_CRITICAL(name,...) MODULE_LOG_CRITICAL_FMT(name, __VA_ARGS__)
#endif#define LOG_TRACE(...) MODULE_LOG_TRACE(useSpdlog::config()->global_debug_logger_name, __VA_ARGS__)
#define LOG_DEBUG(...) MODULE_LOG_DEBUG(useSpdlog::config()->global_debug_logger_name, __VA_ARGS__)
#define LOG_INFO(...) MODULE_LOG_INFO(useSpdlog::config()->global_info_logger_name, __VA_ARGS__)
#define LOG_WARN(...) MODULE_LOG_WARN(useSpdlog::config()->global_error_logger_name, __VA_ARGS__)
#define LOG_ERROR(...) MODULE_LOG_ERROR(useSpdlog::config()->global_error_logger_name, __VA_ARGS__)
#define LOG_CRITICAL(...) MODULE_LOG_CRITICAL(useSpdlog::config()->global_error_logger_name, __VA_ARGS__)

封装代码解释

  1. 我们用一个单例类usespdlog封装,这么做是为了能在头文件中方便的定义一些参数变量。
  2. initSpdlog初始化全局日志器,我们主要记录debug,info,error三种日志,将trace、debug合并,warn、error、critial合并。可以选择控制台显示或者记录到文件。文件是按日期保存,保存15天的日志,之后会回滚,删除最早的一个。
  3. createAsyncRotatingFileLogger 创建一个可以同时显示到控制台或者记录到文件的日志创建器,注册到spdlog,就可以用名字全局使用了。
  4. 自己定义了一些宏,不再使用spdlog自带的宏,通过USE_FMT_LOG开关可以选择使用FMT或printf风格写日志。不带MODUILE前缀的LOG_INFO等使用定义的全局日志记录器写日志,带MODULE前缀的MODULE_LOG_INFO等通过指定日至器写入日志。

使用示例

//初始化全局日志器
useSpdlog::initSpdlog(spdlog::level::level_enum::debug);		
//创建一个只在控制台显示的日志器
auto console_debug = useSpdlog::createAsyncRotatingFileLogger(spdlog::level::level_enum::debug, "console_debug", "", true, false, "[console debug] %v");spdlog::register_logger(console_debug);
LOG_INFO("123 %.2f",3.0);
MODULE_LOG_INFO("console_debug", "123 %s","33333");

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/30060.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在金仓数据库中导入sql文件,解决中文数据乱码问题

先确定数据库服务端编码方式是UTF8&#xff0c;如果不是&#xff0c;那就先解决这个问题。操作&#xff1a;当连接数据库之后&#xff0c;执行show server_encoding 用Notepad打开&#xff0c;目的&#xff1a;确定文件编码是UTF-8格式 在sql文件前面加上set NAMES utf8; …

kotlin区间

1、创建 fun main() {// 全闭区间val intRange 1..3 // int 区间val charRange a..c // 字符区间// 打印println(intRange.joinToString()) // 1,2,3println(charRange.joinToString()) // a,b,c// 左闭右开区间val intRangeExclusive 1 until 3// 倒叙全闭区间val intDown…

瞬间将模型改为原来的60-200倍小

目录 代码解释随机版本 代码 import paddle import faiss from new_model_13 import GPT as GPT13import pandas as pd from sklearn.preprocessing import normalize import json import math from collections import Counter from tqdm import tqdm import numpy as np# 3…

现网中交换机生成树优化思路

现象&#xff1a;交换机启动后等一段时间才可以接入网络&#xff0c;使用一段期间后访问其他主机速度才能加快&#xff0c;一段时间不用后&#xff0c;再使用速度又会慢下来 分析&#xff1a;这台交换机是一台网管交换机。所以&#xff0c;为了避免网络中的拓扑环引起网络瘫痪&…

faiss 简单使用

Faiss&#xff08;Facebook AI Similarity Search&#xff09;是一个由Facebook AI Research开发的库&#xff0c;用于高效相似性搜索和稠密向量聚类。它提供了多种算法来处理大规模的向量搜索问题&#xff0c;支持多种距离度量&#xff08;例如欧氏距离、内积等&#xff09;&a…

【操作系统】操作系统实验04-文件系统扩展

题目要求&#xff1a; 对【程序5_9】进行扩展&#xff0c;要求参数为目录名&#xff0c;且其下至少有三层目录&#xff0c;分别用深度遍历及广度遍历两种方法对此目录进行遍历&#xff0c;输出此目录下所有文件的大小及修改时间。 1. 程序代码&#xff08;注意程序格式&#…

解决 Visual C++ 17.5 __cplusplus 始终为 199711L 的问题

目录 软件环境问题描述查阅资料解决问题参考文献 软件环境 Visual Studio 2022, Visual C, Version 17.5.4 问题描述 在应用 https://github.com/ToniLipponen/cpp-sqlite 的过程中&#xff0c;发现源代码文件 sqlite.hpp 中&#xff0c;有一处宏&#xff0c;和本项目的 C L…

2024香港人才引进计划有哪些?申请条件、政策、利弊一次性说清楚

2024香港人才引进计划有哪些&#xff1f; 拥有香港身份&#xff0c;不仅可以享受到优质的教育资源、税收优惠、以及国际化的商业环境&#xff0c;还能在金融、商业、法律保障和生活品质等方面获得显著的好处。 而这&#xff0c;也是很多内地精英人群&#xff0c;通过申请香港…

threejs 头疼事情之一事件01

在做threejs相关开发的时候&#xff0c;或者封装成三维可视化引擎的时候&#xff0c;应用到项目中&#xff0c;总会和事件打交道&#xff0c;因为项目肯定有交互。但是 threejs 对事件又不友好&#xff0c;反正折腾来折腾去&#xff0c;疼痛。 在Three.js中&#xff0c;Object…

JS-页面截图下载为pdf

这个需要两个 js 库支持&#xff0c;html2canvas 和 jspdf。 下载&#xff1a; npm install html2canvas --save npm install jspdf–save 引用&#xff1a; import { jsPDF } from ‘jspdf’; import html2canvas from ‘html2canvas’; 直接上代码&#xff1a; const downlo…

哪个城市的Delphier最多?Delphier平均年龄多大了?

先来看看哪个城市的Delphier最多&#xff1a; 北上广深不是白叫的&#xff0c; 大家想换工作&#xff0c;就去这些大城市&#xff0c;机会多。 有人会觉得奇怪&#xff0c;怎么才这么几个人&#xff1f; 因为以上数据统计基数为2000人&#xff0c; 根据微信公众号和QQ群得出…

Linux1(介绍与基本命令1)

目录 一、初始Linux 1. Linux的起源 2. Linux是什么&#xff1f; 3. Linux内核版本 4. Linux的应用 5. 终端 6. Shell 7. Linux目录结构 二、基本命令 1. 基本的命令格式 2. shutdown 关机命令 3. pwd 当前工作目录 4. ls 查看目录内容 5. cd 改变工作目录 …

国际荐酒师携手各国际荐酒师专业委员会深化2024年度合作

国际荐酒师&#xff08;香港&#xff09;协会携手广东海上丝绸之路文化促进会及广东省城镇化发展研究会&#xff0c;深化2024年度合作&#xff0c;共同打造品荐与传播大师班培养荐酒师专业人材 近日&#xff0c;国际荐酒师&#xff08;香港&#xff09;协会、广东海上丝绸之路…

学会python——制作一款天气查询工具(python实例七)

目录 1、认识Python 2、环境与工具 2.1 python环境 2.2 Visual Studio Code编译 3、天气查询工具 3.1 代码构思 3.2 代码示例 3.3 运行结果 4、总结 1、认识Python Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的…

Redis在微服务架构中的角色:服务间通信与数据共享

I. 引言 A. 介绍微服务架构的概念和特点 微服务架构是一种设计模式,它将一个大型的单体应用分解成一组小的服务,每个服务都运行在其自身的进程中,独立地进行部署和扩展。这些服务之间通过轻量级的通信机制(如HTTP RESTful API)进行交互,每个服务都围绕一个特定的业务功…

打造精致UI界面:字体设计的妙招

字体设计是UI设计的关键模块之一。字体设计是否有效可能直接实现或破坏整个UI界面。那么&#xff0c;界面设计的字体设计有哪些规范呢&#xff1f;如何设计细节字体&#xff1f;本文将解释字体设计规范的可读性、可读性和可用性&#xff0c;并介绍UI界面中的字体设计技巧。 如…

二级造价工程师建设工程造价管理试题

1、根据《建设工程质量管理条例》&#xff0c;在正常使用条件下&#xff0c;供热与供冷系统的最低保修期限是( )个采暖期、供冷期。 A.1 B.2 C.3 D.4 [答案]B 2、关于甲级工程造价咨询企业的资质标准&#xff0c;叙述错误的是( )。 A.企业与专职专业人员签订劳动合同&…

【Python】JSON

json 一、JSON1.1 概述1.2 数据结构1.3 值1.4 字符串1.5 数值 二、编程语言与JSON2.1 JavaScript与JSON2.2 Python与JSON 一、JSON 1.1 概述 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式&#xff0c;易于人阅读和编写。同时也易于机器解析和生成。 JSON采…

如何用大模型+知识库打造微信群里的AI问答神器!

想象一下&#xff0c;你的微信群或公众号中&#xff0c;有一个AI问答专家随时待命&#xff0c;帮助你和你的朋友们解答各种问题&#xff0c;是不是很酷&#xff1f; 现在&#xff0c;让我们来看看这个项目的技术框架&#xff0c;一步步了解它是如何构建的&#xff1a; 基础起…

zookeeper学习、配置文件参数详解

zookeeper学习、配置文件参数详解 zookeeper 配置文件参数详解tickTime 、session 的过期时间、maxSessionTimeout 三者之间的关系initLimit&#xff0c;syncLimit什么区别minSessionTimeout 默认值,**他的单位是ms** zookeeper 配置文件参数详解 ZooKeeper 是一个分布式协调服…