简单好用的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…

【操作系统】操作系统实验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;通过申请香港…

哪个城市的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 的设计具有很强的…

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

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

【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 是一个分布式协调服…

自动驾驶#芯片-1

概述 汽车是芯片应用场景之一&#xff0c;汽车芯片需要具备车规级。  车规级芯片对加工工艺要求不高&#xff0c;但对质量要求高。需要经过的认证过程&#xff0c;包括质量管理标准ISO/TS 16949、可靠性标准 AEC-Q100、功能安全标准ISO26262等。  汽车内不同用途的芯片要求…

如何卸载windows系统自带游戏

为了清晰地指导如何卸载Windows系统自带游戏&#xff0c;我们可以参考以下步骤进行&#xff1a; 方法一&#xff1a;通过控制面板卸载 打开控制面板进入程序和功能在控制面板中&#xff0c;找到并点击“程序和功能”。在程序列表中&#xff0c;找到你想要卸载的自带游戏。 方…

AI一键生成PPT工具:AIPPT网站分享

PowerPoint演示文稿作为商业沟通、教育培训以及日常汇报的重要工具&#xff0c;一份精美的ppt可以帮助我们提升演示效果以及显示我们的专业性。为了提升ppt的制作效率&#xff0c;我们可以使用AI一键智能生成ppt工具&#xff0c;这样我们就可以快速制作出高大上的PPT了。下面小…

Web攻防:SQL注入 - MySQL 盲注

SQL注入 - MySQL 盲注 1. 基于布尔 SQL 盲注1.1 LEFT() 函数1.1.1 介绍&#xff1a;1.1.2 注入语法&#xff1a;1.1.3 案例 (SQLi-Labs&#xff1a;Less-8) 1.2 ASCII() 函数 SUBSTR() 函数1.2.1 介绍&#xff1a;1.2.2 注入语法&#xff1a;1.2.3 案例 (SQLi-Labs&#xff1a…

Java——可变参数

一、可变参数 1、介绍 Java的可变参数&#xff08;Varargs&#xff09;是一种语法特性&#xff0c;允许一个方法接受不定数量的参数。可变参数的使用通过在参数类型后面添加省略号&#xff08;...&#xff09;实现。这使得方法在调用时可以传入不同数量的参数&#xff0c;而不…

Android device/xxx/system/common/overlay编译产物

MTK 如下代码编译的产物在 framework-res.apk 编译配置文件在device/mediatek/system/common/目录下的Android.bp device/mediatek/system/common/overlay/telephony/frameworks/base/core/res/res/values-mcc655-mnc01/config.xml 在Android U上面还在overlay目录中进行了产…

python是TIOBE编程语言排名第一的编程语言,它有什么优点?它的使用场景有哪些?用python打印数字1--100,用python打印九九乘法表怎么写?

Python是TIOBE编程语言排行榜排名第一的编程语言 。 python是一种解释性、交互式、面向对象的跨平台的语言。 python设计者及名称由来 Guido van Rossum 荷兰人---吉多范罗苏姆&#xff0c;是 Python 编程语言的最初设计者&#xff0c;在 Python 社区一直担当终身仁慈独裁者&…