日志的艺术:深入理解 spdlog

news2024/9/29 13:17:48

目录

1. 为什么需要日志?

2. 同步日志 vs. 异步日志

3. spdlog 的核心组成部分

4. 如何创建一个Logger

5. 如何选择输出目标(Sink)

6. 个性化你的日志格式

7. 异步日志的魔法

8. 刷新策略:何时将日志写入

9. 调整线程池:根据需要定制

10. 完整的异步日志示例

总结


1. 为什么需要日志?

想象一下,你在烹饪一顿大餐,每一步都详细记录下来。这样,即使哪道菜出了问题,你也能迅速找到问题所在。日志在编程中的作用就像是厨房里的菜谱,帮助你:

  • 追踪程序的每一步:了解程序在干什么,执行到哪一步。
  • 定位问题:当程序出错时,日志会告诉你哪里出了问题。
  • 优化性能:通过日志分析,发现程序的瓶颈,进行优化。

2. 同步日志 vs. 异步日志

spdlog中,你可以选择两种方式来记录日志,就像选择不同的烹饪方法:

  • 同步日志:就像你一边炒菜一边看菜谱,每次记录日志都会立即写入。这种方式简单可靠,但在高频率记录时可能会稍微影响程序的性能。

    spdlog::info("这是一个同步日志");
    
  • 异步日志:好比你把菜谱放在一边,专心炒菜,等一会儿再统一查看。这种方式不会阻塞你的主程序,性能更高,但需要一些额外的配置来确保日志的安全性和顺序性。

    #include <spdlog/spdlog.h>
    #include <spdlog/async.h>
    #include <spdlog/sinks/basic_file_sink.h>
    
    int main() {
        // 初始化一个日志线程池
        spdlog::init_thread_pool(8192, 1);
        auto async_logger = spdlog::basic_logger_mt<spdlog::async_factory>("async_logger", "logs/async_log.txt");
        
        async_logger->info("这是一个异步日志");
        async_logger->flush(); // 确保日志写入
        return 0;
    }
    

3. spdlog 的核心组成部分

让我们来看看spdlog是由哪些“食材”组成的:

  1. Registry(注册表)

    • 作用:就像厨房的调料架,管理所有的Logger(日志记录器),确保每个模块都能使用同一个Logger。
    • 使用方法:通过spdlog::register_logger()将Logger注册进去,方便随时调用。
  2. Logger 和 Async Logger

    • Logger:负责接收日志消息并将其分发到不同的“容器”(Sink)中。同步Logger会立即处理日志。
    • Async Logger(异步 Logger):将日志消息放入队列,由后台线程异步处理,提高性能。
  3. Thread Pool(线程池)

    • 作用:在异步日志中,线程池就像厨房里的助理,负责处理日志消息的写入工作。
    • 使用方法:通过spdlog::init_thread_pool()来初始化,设置队列大小和线程数量。
  4. Sink 和 Formatter

    • Sink(输出目标):日志最终的存放地,可以是文件、控制台,甚至是自定义的地方。
    • Formatter(格式化器):负责将日志消息整理成指定的格式,比如加上时间戳、日志级别等信息。

4. 如何创建一个Logger

创建Logger就像选择烹饪的锅具,根据需要选择不同的“锅”来记录日志:

  • 手动创建

    #include <spdlog/spdlog.h>
    #include <spdlog/sinks/stdout_color_sinks.h>
    
    int main() {
        auto console_logger = spdlog::stdout_color_mt("console");
        console_logger->info("手动创建的 logger");
        return 0;
    }
    
  • 注册 Logger

    #include <spdlog/spdlog.h>
    #include <spdlog/sinks/basic_file_sink.h>
    
    int main() {
        auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/logfile.txt", true);
        auto file_logger = std::make_shared<spdlog::logger>("file_logger", file_sink);
        spdlog::register_logger(file_logger);
        file_logger->info("注册的 logger 写入文件");
        return 0;
    }
    

5. 如何选择输出目标(Sink)

选择日志的“存放地”就像决定你的菜是放在盘子里还是碗里。spdlog提供了多种内置的Sink,也支持你自己动手创建:

  • 内置 Sink

    auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/logfile.txt", true);
    auto file_logger = stddlog::logger>("file_logger", file_sink);
    file_logger->info("日志写入文件 Sink");
    
  • 自定义 Sink

    #include <spdlog/spdlog.h>
    #include <spdlog/sinks/sink.h>
    #include <iostream>
    
    class my_sink : public spdlog::sinks::sink {
    public:
        void log(const spdlog::details::log_msg& msg) override {
            std::cout << "自定义 Sink: " << msg.payload << std::endl;
        }
    
        void flush() override {}
    };
    
    int main() {
        auto custom_sink = std::make_shared<my_sink>();
        auto custom_logger = std::make_shared<spdlog::logger>("custom_logger", custom_sink);
        spdlog::register_logger(custom_logger);
        custom_logger->info("这是一个自定义的 Sink");
        return 0;
    }
    

6. 个性化你的日志格式

想让你的日志更有个性,就像为你的菜品加上独特的装饰。spdlog允许你自定义日志的格式:

#include <spdlog/spdlog.h>

int main() {
    auto logger = spdlog::stdout_color_mt("console");
    // 设置日志格式:时间、日志级别、线程 ID、日志消息
    logger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] [%t] %v");
    logger->info("这是一条格式化的日志");
    return 0;
}

常用的格式化标识包括:

  • %Y-%m-%d %H:%M:%S:日期和时间
  • %l:日志级别
  • %t:线程 ID
  • %v:日志消息

7. 异步日志的魔法

如果你的程序需要频繁记录日志,异步日志就像是一个高效的助理,帮你处理繁重的日志任务:

#include <spdlog/spdlog.h>
#include <spdlog/async.h>
#include <spdlog/sinks/basic_file_sink.h>

int main() {
    // 初始化线程池,队列大小为8192,线程数为1
    spdlog::init_thread_pool(8192, 1);

    // 创建一个异步文件日志器
    auto async_logger = spdlog::basic_logger_mt<spdlog::async_factory>("async_logger", "logs/async_log.txt");

    // 记录异步日志
    async_logger->info("这是一条异步日志消息");

    // 强制刷新日志到文件
    async_logger->flush();

    return 0;
}

8. 刷新策略:何时将日志写入

就像决定什么时候把食物从锅里盛出来,刷新策略决定了何时将日志写入到目标位置:

  • 手动刷新

    logger->flush();
    
  • 条件刷新(比如遇到错误级别的日志时刷新):

    logger->flush_on(spdlog::level::err);
    
  • 定时刷新(每隔一段时间自动刷新):

    spdlog::flush_every(std::chrono::seconds(5)); // 每5秒刷新一次日志
    

9. 调整线程池:根据需要定制

如果你需要处理更多的日志,就像需要更多的厨具和助手一样,可以调整线程池的大小和溢出策略:

  • 调整队列大小和线程数量

    spdlog::init_thread_pool(16384, 2); // 队列大小为16384,线程数为2
    
  • 设置溢出策略(当日志队列满了怎么办):

    • 阻塞:等待有空余位置。
    • 丢弃最旧的日志:保留最新的日志。
    auto async_logger = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_file.txt");
    async_logger->set_overflow_policy(spdlog::async_overflow_policy::overrun_oldest);
    

10. 完整的异步日志示例

让我们来看一个完整的例子,看看如何一步步搭建一个高效的异步日志系统:

#include <spdlog/spdlog.h>
#include <spdlog/async.h>
#include <spdlog/sinks/basic_file_sink.h>

int main() {
    // 1. 初始化线程池,队列大小为8192,线程数为1
    spdlog::init_thread_pool(8192, 1);

    // 2. 创建一个异步文件日志器
    auto async_logger = spdlog::basic_logger_mt<spdlog::async_factory>("async_logger", "logs/async_log.txt");

    // 3. 设置日志格式
    async_logger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] [%t] %v");

    // 4. 记录日志
    async_logger->info("这是一条异步日志消息");

    // 5. 强制刷新日志到文件
    async_logger->flush();

    return 0;
}

总结

spdlog就像是你编程中的一位得力助手,帮你高效、灵活地记录和管理日志。无论是简单的控制台输出,还是复杂的异步文件记录,spdlog都能轻松应对。通过合理配置,你可以让日志系统既高效又易用,为你的项目保驾护航。

参考

0voice · GitHubicon-default.png?t=O83Ahttps://github.com/0voice

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

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

相关文章

强化学习入门——Pybullet初体验

Pybullet 最近一直在想如何进行RL的学习&#xff0c;在学习RL的过程中&#xff0c;好的模拟仿真平台是非常重要的。除了Gym&#xff0c;还了解到Pybullet模块可以简便快捷地创建仿真环境&#xff0c;所以学习一下。 1.简介 PyBullet 是一个用于机器人学、游戏开发和图形研究…

mycat读写分离中间件

5、部署Mycat读写分离中间件服务 5.1安装Mycat服务 将Mycat服务的二进制软件包Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz上传到Mycat虚拟机的/root目录下&#xff0c;并将软件包解压到/use/local目录中 5.2赋予解压后的mycat目录权限 5.3向/etc/profile系统变量…

PyQt5与Html的关于地图位置显示的动态交互

PyQt5与Html的关于地图位置显示的动态交互 1 前言2 python部分3 HTML代码4 注意总结 1 前言 上篇本是放弃关于Folium的动态显示&#xff0c;但是在仔细对比Folium在python的直接应用与Html中的写法&#xff0c;其实两者没有什么区别&#xff0c;都是基于Leaflet上建立区域&…

[大语言模型-论文精读] 词性对抗性攻击:文本到图像生成的实证研究

[大语言模型-论文精读] 词性对抗性攻击&#xff1a;文本到图像生成的实证研究 目录 文章目录 [大语言模型-论文精读] 词性对抗性攻击&#xff1a;文本到图像生成的实证研究目录文章研究背景 文章标题摘要1 引言2 相关工作3 数据集创建3.1 数据收集3.2 目标提示生成3.3 数据集注…

[ACS_C]:以 H2和 O2等离子体处理的 Al2O3为载体的 Pt 催化剂用于液态有机氢载体对二苄基甲苯和全氢二苄基甲苯的加氢和脱氢

摘要&#xff1a;二苄基甲苯 (DBT) 是一种很有前途的液态有机氢载体 (LOHC)&#xff0c;理论储氢量为 6.2 wt%&#xff0c;可与可再生能源发电系统耦合。本工作采用一种方便、环保的等离子体处理方法改性氧化铝表面羟基和表面氧空位 (SOV)。通过浸渍处理后的氧化铝制备了不同的…

如何修复变砖的手机并恢复丢失的数据

您可能之前听说过“变砖”&#xff0c;但您知道什么是变砖手机吗&#xff1f;正如许多论坛中经常提出的问题一样&#xff0c;我如何知道我的手机是否变砖了&#xff1f;好吧&#xff0c;手机变砖主要有两种类型&#xff0c;即软件变砖和硬变砖。软变砖手机意味着重启后您仍然可…

MATLAB guide选择图片和全局变量使用

文章目录 前言一、按键选取文件二、全局化变量使用全局华使用 总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 项目需要&#xff1a; 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、按键选取文件 [filename,pathname]…

想要编辑 PDF 文件?使用这 10 种最佳 PDF 编辑工具

您是否遇到过利益干系人要求您对 PDF 文件进行细微更改的情况&#xff1f; 通常我们会这样做&#xff01; 但是&#xff0c;对你来说&#xff0c;做出要求的改变有多难呢&#xff1f; 好吧&#xff0c;当您没有用于创建 PDF 文件的源文件时&#xff0c;问题就来了。是的&…

如何选购适合自己的内衣洗衣机?五款热门卓越型号测评推荐

相信不少小伙伴都跟我一样&#xff0c;一方面&#xff0c;认为内裤、袜子与大件的上衣、裤子放一块清洗&#xff0c;会感觉很不卫生&#xff0c;而且穿在身上也不安心。但是另一方面&#xff0c;本身又很懒惰&#xff0c;也不想自己用手洗&#xff0c;不但经常会遗漏一些污渍&a…

探索 DaPy:Python 中的 AI 数据处理新贵

文章目录 探索 DaPy&#xff1a;Python 中的 AI 数据处理新贵背景介绍DaPy 是什么&#xff1f;如何安装 DaPy&#xff1f;DaPy 的简单函数使用方法加载数据数据筛选数据聚合数据可视化自定义函数 DaPy 在实际场景中的应用数据预处理数据分析数据处理与集成 常见 Bug 及解决方案…

蓝牙资讯|2024可穿戴市场的手表将出现下滑,耳机和戒指将增长

市场调查机构 IDC 发布博文&#xff0c;预测 2024 年全球可穿戴设备出货量达到 5.379 亿台&#xff0c;同比增长 6.1%。IDC 预计新兴市场的进一步普及和成熟市场的更新周期的开始将推动听力设备的发展&#xff0c;因为消费者希望更换大流行病时期购买的产品。 IDC 预估 2024 …

VS2017安装Installer Projects制作Setup包

下载安装扩展包 VS2017默认未安装Installer Projects Package&#xff0c;需要联机下载&#xff1a; 也可网页上下载离线InstallerProjects.vsix文件&#xff1a; https://visualstudioclient.gallerycdn.vsassets.io/extensions/visualstudioclient/microsoftvisualstudio20…

Spring Boot 进阶-Spring Boot 如何实现自定义的过滤器详解

在上一篇文章中我们讲解了关于拦截器的相关内容,并且通过一个防抖的例子来讲解了拦截器在实际开发中的使用。这篇文章我们为大家带来的就是关于过滤器的相关内容的分享。下面我们首先来介绍一下什么是过滤器。 什么是过滤器? 过滤器Filter,是Servlet技术中最常用的技术,开…

K8S精进之路-控制器DaemonSet -(3)

介绍 DaemonSet就是让一个节点上只能运行一个Daemonset Pod应用&#xff0c;每个节点就只有一个。比如最常用的网络组件&#xff0c;存储插件&#xff0c;日志插件&#xff0c;监控插件就是这种类型的pod.如果集群中有新的节点加入&#xff0c;DaemonSet也会在新的节点创建出来…

【Router】路由功能之DMZ(Demilitarized Zone)功能介绍及实现

DMZ&#xff08;Demilitarized Zone&#xff09; DMZ&#xff08;非军事化区域&#xff09;是一个位于内部网络和外部网络之间的分段区域。在一个网络中&#xff0c;DMZ通常包含运行公共服务的服务器或其他设备。 DMZ是一个位于内部网络和外部网络之间的分段区域&#xff0c;用…

wpa_cli支持EAP-TLS认证运行设计

wpa_cli支持EAP-TLS认证运行设计 1 输入 1.1启动wpa_supplicant 和 wpa_cli 在OpenHarmony开发板或华为开发机的命令行中输入 wpa_supplicant -Dnl80211 -c/data/service/el1/public/wifi/wpa_supplicant/wpa_supplicant.conf -gabstract:/data/service/el1/public/wifi/sock…

【笔记】Java 栈 java.util.Stack

目标:了解Java编程语言里栈和队列是什么样的。 概念 在Java中,Stack 类表示一个后进先出(LIFO,Last-In-First-Out)的对象栈。它继承自 Vector 类,并提供了五个操作,允许将向量(Vector)视为栈来处理。这些操作包括常用的: 压栈(push)出栈(pop)操作用于查看栈顶元…

物理加密机的高性能操作

物理加密机&#xff0c;也被称为硬件安全模块(HSM)或加密锁&#xff0c;是一种用于保护敏感数据和软件应用的物理设备。以下是关于物理加密机的详细介绍&#xff1a; 一、定义与功能 物理加密机通过提供强大的加密功能和访问控制&#xff0c;确保数据在存储、处理和传输过程中的…

GIS--为研究区准备数据

一、实验目的 掌握空间数据的分幅组织方法&#xff0c;掌握常用的空间数据处理技术 二、实验内容 计算图幅号&#xff1b;空间配准、投影定义、投影转换&#xff1b;拼接、裁切&#xff0c;获取研究区内的土地利用数据 三、实验原理与方法 实验原理&#xff1a;空间数据组…

【火狐浏览器 - 数据同步】使用Mozilla账户登录

不要使用火狐通行证 解决方法 在国内下载 开发版本的firefox, 即可数据同步 https://www.mozilla.org/zh-CN/firefox/all/ 登录成功 其他 如果还不同步, 试下这个插件 http://mozilla.com.cn/thread-343905-1-1.html