spdlog介绍与使用

article/2025/6/26 18:16:50

文章目录

    • spdlog的介绍与安装
    • 使用样例
    • 二次封装

spdlog的介绍与安装

spdlog 是一个高性能、超快速、零配置的 C++ 日志库,它旨在提供简洁的 API 和丰富的功能,同时保持高性能的日志记录。它支持多种输出目标、格式化选项、线程安全以及异步日志记录。

特点

高性能:spdlog 专为速度而设计,即使在高负载情况下也能保持良好的性能。

零配置:无需复杂的配置,只需包含头文件即可在项目中使用。

异步日志:支持异步日志记录,减少对主线程的影响。

格式化:支持自定义日志消息的格式化,包括时间戳、线程 ID、日志级别等。

多平台:跨平台兼容,支持 Windows、Linux、macOS 等操作系统。

丰富的 API:提供丰富的日志级别和操作符重载,方便记录各种类型的日志。

安装

centos

sudo yum install -y spdlog-devel

unbuntu

sudo apt-get install libspdlog-dev

源码安装

git clone https://github.com/gabime/spdlog.git
cd spdlog/
mkdir build && cd build
cmake -DCMAKE_INSTALL_PREFIX=/usr ..
make && sudo make install

使用

包含头文件:

在你的 C++ 源文件中包含 spdlog 的头文件:

#include <spdlog/spdlog.h>

日志输出等级枚举

namespace level
{enum level_enum : int{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};
}

日志输出格式自定义:

可以自定义日志消息的格式:

logger->set_pattern("%Y-%m-%d %H:%M:%S [%t] [%-7l] %v");
%t - 线程 ID(Thread ID)。
%n - 日志器名称(Logger name)。
%l - 日志级别名称(Level name),如 INFO, DEBUG, ERROR 等。
%v - 日志内容(message)。
%Y - 年(Year)。
%m - 月(Month)。
%d - 日(Day)。
%H - 小时(24-hour format)。
%M - 分钟(Minute)。
%S - 秒(Second)。

日志记录器类:

创建一个基本的日志记录器,并设置日志级别和输出模式:

namespace spdlog
{class logger{logger(std::string name);logger(std::string name, sink_ptr single_sink);logger(std::string name, sinks_init_list sinks);void set_level(level::level_enum log_level);void set_formatter(std::unique_ptr<formatter> f);template <typename... Args>void trace(fmt::format_string<Args...> fmt, Args &&...args);template <typename... Args>void debug(fmt::format_string<Args...> fmt, Args &&...args);template <typename... Args>void info(fmt::format_string<Args...> fmt, Args &&...args);template <typename... Args>void warn(fmt::format_string<Args...> fmt, Args &&...args);template <typename... Args>void error(fmt::format_string<Args...> fmt, Args &&...args);template <typename... Args>void critical(fmt::format_string<Args...> fmt, Args &&...args);void flush(); // 刷新日志// 策略刷新--触发指定等级日志的时候立即刷新日志的输出void flush_on(level::level_enum log_level);};
}

异步日志记录类:

为了异步记录日志,可以使用 spdlog::async_logger:

class async_logger final : public logger
{async_logger(std::string logger_name,sinks_init_list sinks_list,std::weak_ptr<details::thread_pool> tp,async_overflow_policy overflow_policy =async_overflow_policy::block);async_logger(std::string logger_name,sink_ptr single_sink,std::weak_ptr<details::thread_pool> tp,async_overflow_policy overflow_policy =async_overflow_policy::block);// 异步日志输出需要异步工作线程的支持,这里是线程池类class SPDLOG_API thread_pool{thread_pool(size_t q_max_items,size_t threads_n,std::function<void()> on_thread_start,std::function<void()> on_thread_stop);thread_pool(size_t q_max_items, size_t threads_n,std::function<void()> on_thread_start);thread_pool(size_t q_max_items, size_t threads_n);};
}std::shared_ptr<spdlog::details::thread_pool> thread_pool()
{return details::registry::instance().get_tp();
}
// 默认线程池的初始化接口
inline void init_thread_pool(size_t q_size, size_t thread_count);
auto async_logger = spdlog::async_logger_mt("async_logger","logs/async_log.txt");
async_logger->info("This is an asynchronous info message");

日志记录器工厂类:

using async_factory = async_factory_impl<async_overflow_policy::block>;
template <typename Sink, typename... SinkArgs>
inline std::shared_ptr<spdlog::logger> create_async(std::string logger_name, SinkArgs &&...sink_args);
// 创建一个彩色输出到标准输出的日志记录器,默认工厂创建同步日志记录器
template <typename Factory = spdlog::synchronous_factory>
std::shared_ptr<logger> stdout_color_mt(const std::string &logger_name,color_mode mode = color_mode::automatic);
// 标准错误
template <typename Factory = spdlog::synchronous_factory>
std::shared_ptr<logger> stderr_color_mt(const std::string &logger_name,color_mode mode = color_mode::automatic);
// 指定文件
template <typename Factory = spdlog::synchronous_factory>
std::shared_ptr<logger> basic_logger_mt(const std::string &logger_name,const filename_t &filename,bool truncate = false,const file_event_handlers &event_handlers = {});
// 循环文件
template <typename Factory = spdlog::synchronous_factory>
std::shared_ptr<logger> rotating_logger_mt(const std::string &logger_name,const filename_t &filename,size_t max_file_size,size_t max_files,bool rotate_on_open = false);
namespace spdlog
{namespace sinks{class SPDLOG_API sink{public:virtual ~sink() = default;virtual void log(const details::log_msg &msg) = 0;virtual void flush() = 0;virtual void set_pattern(const std::string &pattern) = 0;virtual voidset_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) = 0;void set_level(level::level_enum log_level);};using stderr_color_sink_mt;using stderr_sink_mt;using stdout_color_sink_mt;using stdout_sink_mt;// 滚动日志文件-超过一定大小则自动重新创建新的日志文件sink_ptr rotating_file_sink(filename_t base_filename,std::size_t max_size,std::size_t max_files,bool rotate_on_open = false,const file_event_handlers &event_handlers ={});using rotating_file_sink_mt = rotating_file_sink<std::mutex>;// 普通的文件落地类sink_ptr basic_file_sink(const filename_t &filename,bool truncate = false,const file_event_handlers &event_handlers ={});using basic_file_sink_mt = basic_file_sink<std::mutex>;using kafka_sink_mt = kafka_sink<std::mutex>;using mongo_sink_mt = mongo_sink<std::mutex>;using tcp_sink_mt = tcp_sink<std::mutex>;using udp_sink_mt = udp_sink<std::mutex>;//*_st:单线程版本,不用加锁,效率更高。//*_mt:多线程版本,用于多线程程序是线程安全的。}
}

全局接口:

// 输出等级设置接口
void set_level(level::level_enum log_level);
// 日志刷新策略-每隔 N 秒刷新一次
void flush_every(std::chrono::seconds interval);
// 日志刷新策略-触发指定等级立即刷新
void flush_on(level::level_enum log_level);

记录日志:

使用日志记录器记录不同级别的日志:

logger->trace("This is a trace message");
logger->debug("This is a debug message");
logger->info("This is an info message");
logger->warn("This is a warning message");
logger->error("This is an error message");
logger->critical("This is a critical message");

使用样例

同步日志输出

#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <iostream>int main()
{// 设置全局的日志输出等级spdlog::set_level(spdlog::level::level_enum::debug);// 设置全局的刷新策略--每隔 N 秒刷新一次spdlog::flush_every(std::chrono::seconds(1));// 遇到debug以上等级日志立即刷新spdlog::flush_on(spdlog::level::level_enum::debug);// 创建同步日志器(标准输出/文件)--工厂模式默认创建的就是同步日志器auto logger = spdlog::stdout_color_mt("default-logger");// auto logger = spdlog::basic_logger_mt("file-logger","sync.log");// 设置日志刷新策略以及设置日志的输出等级// logger->flush_on(spdlog::level::level_enum::debug);// logger->set_level(spdlog::level::level_enum::debug);// 设置日志的输出格式logger->set_pattern("[%n][%H:%M:%S][%t][%-8l] %v");logger->trace("hello {}","world");logger->debug("hello {}","world");logger->warn("hello {}","world");logger->error("hello {}","world");logger->critical("hello {}","world");std::cout << "日志输出完毕" << std::endl;return 0;
}

image-20241215172138846

异步日志输出

#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/async.h>
#include <iostream>int main()
{//设置全局的刷新策略//每秒刷新spdlog::flush_every(std::chrono::seconds(1));spdlog::flush_on(spdlog::level::level_enum::debug);spdlog::set_level(spdlog::level::level_enum::debug);// 初始化异步日志输出线程配置// void init_thread_pool(size_t q_size,size_t thread_count);spdlog::init_thread_pool(3072, 1);// 创建同步日志器(标准输出/文件)--工厂模式默认创建的就是同步日志器auto logger = spdlog::stdout_color_mt<spdlog::async_factory>("async-logger");//设置日志输出格式logger->set_pattern("[%n][%H:%M:%S][%t][%-8l] %v");//进行简单的日志输出logger->trace("你好!{}", "小明");logger->debug("你好!{}", "小明");logger->info("你好!{}", "小明");logger->warn("你好!{}", "小明");logger->error("你好!{}", "小明");logger->critical("你好!{}", "小明");std::cout << "日志输出演示完毕!\n";return 0;
}

image-20241215172200823

二次封装

原因:

1.避免单例的锁冲突,影响直接创建全局的线程安全的日志器进行使用

2.因为日志输出没有文件名和行号,因为使用宏进行二次封装输出日志的文件名和行号

3.封装一个初始化接口,便于使用:调试模式测输出到标准输出,否则则输出到文件中

思想:

封装出一个全局接口,用户进行日志器的创建与初始化

初始化接口接收3个参数:运行模式,输出文件名–用户发布模式,输出日志等级–用于发布模式

对日志输出的接口,进行宏的封装,加入文件名和行号的输出

#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/async.h>
#include <iostream>// mode - 运行模式: true-发布模式; false调试模式
namespace hdp
{std::shared_ptr<spdlog::logger> g_default_logger;void init_logger(bool mode, const std::string &filename, int32_t level){if (mode == false){// 如果是调试模式,则创建标准输出日志器,输出等级为最低g_default_logger = spdlog::stdout_color_mt("default-logger");g_default_logger->set_level(spdlog::level::level_enum::trace);g_default_logger->flush_on(spdlog::level::level_enum::trace);}else{// 如果是发布模式,则创建文件输出日志器,输出等级根据参数而定g_default_logger = spdlog::basic_logger_mt("default-logger", filename);g_default_logger->set_level((spdlog::level::level_enum)level);g_default_logger->flush_on((spdlog::level::level_enum)level);}g_default_logger->set_pattern("[%n][%H:%M:%S][%t][%-8l]%v");}#define LOG_TRACE(format, ...) hdp::g_default_logger->trace(std::string("[{}:{}] ") + format, __FILE__, __LINE__, ##__VA_ARGS__);
#define LOG_DEBUG(format, ...) hdp::g_default_logger->debug(std::string("[{}:{}] ") + format, __FILE__, __LINE__, ##__VA_ARGS__);
#define LOG_INFO(format, ...) hdp::g_default_logger->info(std::string("[{}:{}] ") + format, __FILE__, __LINE__, ##__VA_ARGS__);
#define LOG_WARN(format, ...) hdp::g_default_logger->warn(std::string("[{}:{}] ") + format, __FILE__, __LINE__, ##__VA_ARGS__);
#define LOG_ERROR(format, ...) hdp::g_default_logger->error(std::string("[{}:{}] ") + format, __FILE__, __LINE__, ##__VA_ARGS__);
#define LOG_FATAL(format, ...) hdp::g_default_logger->critical(std::string("[{}:{}] ") + format, __FILE__, __LINE__, ##__VA_ARGS__);
}

测试代码:

#include <gflags/gflags.h>
#include "logger.hpp"DEFINE_int32(run_mode, 0, "程序的运行模式,0-调试,1-发布");
DEFINE_string(log_file, "", "发布模式下,用于指定日志的输出文件");
DEFINE_int32(log_level, 0, "发布模式下,用于指定日志的输出等级");int main(int argc, char *argv[])
{google::ParseCommandLineFlags(&argc, &argv, true);init_logger(FLAGS_run_mode, FLAGS_log_file, FLAGS_log_level);LOG_DEBUG("Hello {}", "World");LOG_INFO("Hello {}", "World");LOG_WARN("Hello {}", "World");LOG_ERROR("Hello {}", "World");LOG_FATAL("Hello {}", "World");return 0;
}

makefile

all:sync async main
sync:sync.ccg++ -o $@ $^ -std=c++17 -lspdlog -lfmt
async:async.ccg++ -o $@ $^ -std=c++17 -lspdlog -lfmt
main:main.ccg++ -o $@ $^ -std=c++17 -lspdlog -lfmt -lgflags.PHONY:clean
clean:rm -rf async sync main

测试结果

NFO(“Hello {}”, “World”);
LOG_WARN(“Hello {}”, “World”);
LOG_ERROR(“Hello {}”, “World”);
LOG_FATAL(“Hello {}”, “World”);
return 0;
}


makefile```makefile
all:sync async main
sync:sync.ccg++ -o $@ $^ -std=c++17 -lspdlog -lfmt
async:async.ccg++ -o $@ $^ -std=c++17 -lspdlog -lfmt
main:main.ccg++ -o $@ $^ -std=c++17 -lspdlog -lfmt -lgflags.PHONY:clean
clean:rm -rf async sync main

测试结果

image-20250109211924885


http://www.hkcw.cn/article/MdXPbqNbZV.shtml

相关文章

w373驾校预约学习系统的设计与实现

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;原创团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339;赠送计算机毕业设计600个选题excel文…

【PCB设计】STM32开发板——产品设计流程及元件选型

一、PCB设计流程 二、产品设计流程 三、需求及方案 四、元器件的选型 1.MCU选型 2.STM32单片机命名规则 根据命名规则及我们的需求&#xff0c;最终选择使用STM32F103VET6的芯片。 3.MCU最小系统 MCU最小系统的电路设计可以参考相关的数据手册。 4.信号接口选型 ADC以及DAC一…

守护进程导致程序kill掉后被重新拉起

ps aux | grep "supervisord" 从上面的命令可以查找到守护进程的配置文件位置&#xff1a; /etc/supervisor/supervisord.conf 从配置信息看&#xff0c;守护进程的配置文件&#xff0c;又加载了/etc/supervisor/conf.d/*.conf的所有相关配置信息&#xff1b; cat /…

【iOS安全】使用LLDB调试iOS App | LLDB基本架构 | LLDB安装和配置

LLDB基本架构 参考&#xff1a; https://crifan.github.io/ios_re_dynamic_debug/website/debug_code/lldb_debugserver.html https://book.crifan.org/books/ios_re_debug_debugserver_lldb/website/ LLDB安装和配置 1. 让iPhone中出现/Developer/usr/bin/debugserver 最初…

RPG19.设置敌人

1.启动项目&#xff0c;创建爱你CharacterBase的子类 2.创建敌人数据资产 3.创建敌人的ASC 4.创建敌人的CombatComponent 5.打开EnemyCharacter&#xff0c; // Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "Core…

ROS 2源换源后GPG错误解决方法

报错形式&#xff1a; 解决&#xff1a; 1. 删除旧的 ROS 密钥 sudo rm /etc/apt/trusted.gpg.d/ros.gpg 2. 重新下载并导入新的 ROS GPG 密钥 sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /etc/apt/trusted.gpg.d/ros.gpg 3. 确…

day 43

应用cnn对kaggle上的图像数据集进行练习 数据集地址&#xff1a;Cat and Dog import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pyplot as plt im…

哈佛蒋雨融自曝初中被霸凌 母校撤宣传引争议

哈佛蒋雨融自曝初中被霸凌母校撤宣传引争议。在哈佛大学毕业典礼上,中国学生蒋雨融作为代表发表演讲,本应是件荣耀的事情,却因各种质疑声陷入舆论漩涡。她自曝初中时期遭受霸凌的经历,更是将事件推向高潮,让她的母校青岛65中成为焦点,学校迅速撤下了此前的相关宣传。蒋雨…

江淮能靠华为“镀金”翻身吗 自身硬实力与华为软实力的乘法效应

江淮能靠华为“镀金”翻身吗 自身硬实力与华为软实力的乘法效应!江淮汽车在卡车领域享有盛名,尤其是轻卡系列。但江淮集团的产品体系非常广泛,涵盖了重、中、轻、微型卡车、多功能商用车、MPV、SUV、轿车、客车以及专用底盘、变速箱、发动机和车桥等核心零部件。江淮汽车在5…

因性侵被拘的湖南机场董事长被除名 新领导已上任

因性侵被拘的湖南机场董事长被除名 新领导已上任!今年4月,湖南省机场管理集团党委书记、董事长,湖南省机场管理局局长邱继兴因涉嫌性侵一女子被警方刑拘,此事引发了广泛关注。6月2日,该集团官网已撤下邱继兴的职务信息,官方微信公众号中大量关于他的内容也已消失。4月18日…

媒体:关税升级 特朗普似乎有些着急 欧盟警告将加快报复措施

6月2日,美股三大指数集体收涨,道指上涨0.08%,纳指上涨0.67%,标普500指数上涨0.41%。热门科技股多数上涨,AMD和Meta涨幅超过3%,超微电脑上涨近3%,博通涨幅超过2%,英伟达上涨超过1%,特斯拉和谷歌跌幅超过1%。热门中概股也多数上涨,纳斯达克中国金龙指数上涨0.53%。百度…

律师解读孙继海青训机构嗨球纠纷 赔偿金额成争议焦点

6月2日,南方周末发布了一篇专题报道,其中一位爱好足球的律师王国良对孙继海青训机构嗨球和家长之间的纠纷进行了分析。王国良不仅是一名律师,还赞助了一支业余足球队,并全程关注了此次事件。他表示,家长们并不是不愿意赔偿,而是认为18万元的赔偿金额过高,这可能是因为双…

迪丽热巴生日工作室发文 撕拉片写真惊艳全场

迪丽热巴生日工作室发文!迪丽热巴工作室在6月3日生日前夕发布了一组质感十足的“撕拉片”写真,瞬间点燃粉丝热情。这组被网友盛赞为“最权威撕拉片”的作品以胶片独特的显影魅力作为生日序曲,主题直指“迪丽热巴0603生日快乐”。官博配文深情:“胶片显影的第8秒,是时间送来…

48岁女子怀孕以为发福已顺产生子:孙子比新出生的儿子大3岁

48岁女子怀孕以为发福已顺产生子 女儿喜迎弟弟!6月2日,广东河源一名48岁的再婚女子在怀孕后仅15分钟就顺利产下一名男婴。她的28岁女儿对此表示非常高兴,并发文称“从此多一个人为妈妈保驾护航了”。这名女子的丈夫提到,他们的孙子比新出生的儿子大3岁。据报道,这位女子发…

php执行后报502,无错误提示的排查和解决

文章目录 一、阐述问题二、开始排查1.执行代码展示2.PHP层面排查问题3.系统层面排查问题1. 分析系统日志2. core dump 分析2.1 core dump 是什么2.2 core dump 配置 并 生成 core 文件2.3 gdb 解析 core 文件 4. 问题解决 三、赠送内容四、总结 一、阐述问题 这个问题花了我起…

灵动相册,助力教学:在线教学场景的图片管理利器——仙盟引渡仙君-智能编程——仙盟创梦IDE

专为在线教学打造的相册工具&#xff0c;以蓝色专业风设计&#xff0c;纯前端实现&#xff0c;不依赖后端。具备图片管理、浏览缩放及上传功能。界面布局合理&#xff0c;交互体验佳&#xff0c;响应式适应多屏。模块化设计易维护扩展&#xff0c;助教师轻松管图&#xff0c;学…

网络攻防技术三:网络脆弱性分析

文章目录 一、影响安全的因素二、计算机网络三、网络体系结构脆弱性1、因特网容易被攻击的特性 四、典型网络协议安全性分析&#xff08;重要&#xff09;1、IPv42、RIP&#xff08;UDP)3、ICMP(UDP)4、ARP5、OSPF(IP数据报&#xff09;6、BGP(TCP)7、UDP8、TCP9、DNS(UDP)10、…

20250602在荣品的PRO-RK3566开发板的Android13下打开关机对话框

20250602在荣品的PRO-RK3566开发板的Android13下打开关机对话框 2025/6/2 15:07 缘起&#xff1a;需要在荣品的PRO-RK3566开发板的Android13下&#xff0c;打开/增加关机对话框这个功能。 因为手机都有。那我们就找资料吧。 参考资料&#xff1a; https://blog.csdn.net/terry_…

mac电脑安装 nvm 报错如何解决

前言 已知&#xff1a;安装nvm成功&#xff1b;终端输入nvm -v 有版本返回 1. 启动全局配置环境变量失败 source ~/.zshrc~ 返回&#xff1a; source: no such file or directory: /Users/你的用户名/.zshrc~2 安装node失败 nvm install 16.13返回&#xff1a; mkdir: /U…

SOC-ESP32S3部分:26-物联网MQTT连云

飞书文档https://x509p6c8to.feishu.cn/wiki/IGCawAgqFibop7kO83KcsDFBnNb ESP-MQTT 是 MQTT 协议客户端的实现&#xff0c;MQTT 是一种基于发布/订阅模式的轻量级消息传输协议。ESP-MQTT 当前支持 MQTT v5.0。 特性 支持基于 TCP 的 MQTT、基于 Mbed TLS 的 SSL、基于 WebSo…