日志工具spdlog全解析:理论、安装、使用与实践(C++)

news2024/9/28 15:15:42

文章目录

  • 前言
    • spdlog 与 glog
  • spdlog介绍
  • 内容
    • 日志等级
    • 输出格式
  • 使用
    • 步骤
    • 同步日志输出
    • 异步日志输出
    • 封装一个日志输出类
      • 对日志输出类的测试
  • 安装


前言

在编写项目时,通过日志追踪程序错误或其他情况出现的位置是十分重要的,对于不太复杂的场景,可以通过自行编写简单的日志记录文件,但对于大型项目,可以使用较为完善,稳定的日志记录工具;

spdlog 与 glog

一般有两种选择glog 与 spdlog,下面是两者的对比:

特性spdlogglog
性能高性能,支持异步日志性能较好,但主要为同步日志
易用性简洁明了,易于上手API 较复杂,适合 Google 环境
日志格式支持格式化字符串不支持格式化
日志级别Trace、Debug、Info、Warning、Error、CriticalInfo、Warning、Error、Fatal
输出目标控制台、文件、自定义目标默认文件输出
颜色输出支持不支持
依赖几乎没有外部依赖依赖于 gflags
自定义能力高,支持自定义格式和目标较低,主要集中在调试信息
使用场景游戏开发、实时系统等大规模软件开发、调试工具

根据上面的内容,这里我们学习spdlog的使用:

spdlog介绍

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

  • 高性能spdlog 专为速度而设计,即使在高负载情况下也能保持出色的性能。
  • 零配置:使用简单,无需复杂配置,只需包含头文件即可在项目中使用。
  • 异步日志:支持异步日志记录,显著减少对主线程的影响。
  • 格式化:支持自定义日志消息格式化,包括时间戳、线程 ID、日志级别等信息。
  • 多平台兼容:跨平台支持,兼容 Windows、Linux、macOS 等操作系统。
  • 丰富的 API:提供多种日志级别和操作符重载,方便记录不同类型的日志信息。

内容

如果要使用spdlog,首先包含头文件:

#include <spdlog/spdlog.h>

日志等级

通过查阅common.h可以找到spdlog的日志等级枚举:

namespace level {
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
};

输出格式

我们可以自定义spdlog的日志输出格式

logger->set_pattern("%Y-%m-%d %H:%M:%S [%t] [%-7l] %v");
格式符描述
%t线程 ID
%n日志器名称
%l日志级别名称
%v日志内容
%Y
%m
%d
%H小时(24-hour format)
%M分钟
%S

使用

步骤

一般在通过spdlog输出日志往往有以下几个步骤:

  1. 引入 spdlog

确保在项目中包含 spdlog 库的头文件。

#include <spdlog/spdlog.h>
#include <spdlog/sinks/basic_file_sink.h> // 如果需要文件输出
  1. 初始化日志记录器

创建一个日志记录器,可以选择控制台输出或文件输出。

// 控制台输出
auto console = spdlog::stdout_color_mt("console");

// 文件输出
auto file_logger = spdlog::basic_file_sink_mt("logs.txt", true);
  1. 设置日志级别

设置日志的输出级别,以控制哪些信息会被记录。

spdlog::set_level(spdlog::level::info); // 只输出 INFO 及以上级别的日志
  1. 输出日志信息

使用不同的日志级别输出信息。

spdlog::info("This is an info message");
spdlog::debug("This debug message will not be shown"); // 如果级别设置为 INFO,这条不会输出
spdlog::error("This is an error message");
  1. (可选) 自定义日志格式

如果需要,可以设置自定义的日志格式。

spdlog::set_pattern("[%Y-%m-%d %H:%M:%S] [%n] [%l] %v");
  1. 清理资源

在程序结束前,可以选择清理日志资源(虽然 spdlog 会自动处理大部分情况)。

spdlog::shutdown();

同步日志输出

根据上面的内容,下面编写一个代码用于进行 同步的日志输出:

#include <spdlog/spdlog.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <iostream>

int main()
{
    // 1. 设置全局刷新策略
        // 每秒刷新
    spdlog::flush_every(std::chrono::seconds(1));
        //  遇到debug以上等级日志: 立即刷新
    spdlog::flush_on(spdlog::level::level_enum::debug);
    // 2. 设置全局日志输出等级(可以根据每个日志器独立设置)
    spdlog::set_level(spdlog::level::level_enum::debug);
    // 3. 创建同步日治器(标准输出 / 文件) 默认是同步
    auto logger = spdlog::basic_logger_mt("file-logger", "./sync.log");
    // 4. 设置日志器刷新策略
    logger->flush_on(spdlog::level::level_enum::debug);
    logger->set_level(spdlog::level::level_enum::debug);
    // 5. 设置日志输出格式
    logger->set_pattern("[%n][%H:%M:%S][%t][%-8l] %v");
    // 6. 执行日志输出
    logger->trace("trace message");
    logger->debug("debug message");
    logger->info("info message");
    logger->warn("warn message");
    logger->error("error message");
    logger->critical("critical message");
    // 7. 删除日志器
    spdlog::drop("file-logger");
    std::cout << "spdlog测试 | 日志输出完毕" << std::endl;
    return 0;
}

当编译并执行可执行程序后,会生成文件sync.log,其内容为:

在这里插入图片描述


异步日志输出

代码实现上与同步日志输出一致,主要在创建日志器时不同;

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

int main()
{
    // 1. 设置全局刷新策略
        // 每秒刷新
    spdlog::flush_every(std::chrono::seconds(1));
    spdlog::flush_on(spdlog::level::level_enum::debug);
    spdlog::set_level(spdlog::level::level_enum::debug);

    // 2. 初始化异步日志输出 线程配置
    spdlog::init_thread_pool(1145, 1);
    // 3. 创建异步日志器(标准输出/文件) 
    auto logger = spdlog::basic_logger_mt("async_logger", "async.log");
    // 4. 设置日志输出格式
    logger->set_pattern("[%n][%H:%M:%S][%t][%-8l] %v");
    // 5. 进行日志输出
    logger->trace("trace log {}", "hello world");
    logger->debug("debug log {}", "hello world");
    logger->info("info log {}", "hello world");
    logger->warn("warn log {}", "hello world");
    logger->error("error log {}", "hello world");
    logger->critical("critical log {}", "hello world");
    
    return 0;
}

在这里插入图片描述


封装一个日志输出类

如果每次想进行日志输出都需要先经过一系列步骤,在编码上会比较复杂,所以可以先封装一个日志输出类,每次使用前进行初始化:

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

std::shared_ptr<spdlog::logger> default_logger;
// mode: 运行模式
// mode = true: 发布模式 false: 调试模式
void init_logger(bool mode, const std::string& file_name, int level)
{
    if(mode) { // 发布模式: 将日志输出到文件
        default_logger = spdlog::basic_logger_mt("default_logger", file_name);
        default_logger->set_level((spdlog::level::level_enum)level);
        default_logger->flush_on((spdlog::level::level_enum)level);
    } else { // 调试模式: 直接将日志输出到标准输出
        default_logger = spdlog::stdout_color_mt("default-logger");
        default_logger->set_level(spdlog::level::level_enum::trace);
        default_logger->flush_on(spdlog::level::level_enum::trace);
    }
    default_logger->set_pattern("[%n][%H:%M:%S][%t][%-8l]%v");
}

#define LOG_TRACE(format, ...) default_logger->trace(std::string("[{}:{}] ") + format, __FILE__, __LINE__, ##__VA_ARGS__)
#define LOG_DEBUG(format, ...) default_logger->debug(std::string("[{}:{}] ") + format, __FILE__, __LINE__, ##__VA_ARGS__)
#define LOG_INFO(format, ...) default_logger->info(std::string("[{}:{}] ") + format, __FILE__, __LINE__, ##__VA_ARGS__)
#define LOG_WARN(format, ...) default_logger->warn(std::string("[{}:{}] ") + format, __FILE__, __LINE__, ##__VA_ARGS__)
#define LOG_ERROR(format, ...) default_logger->error(std::string("[{}:{}] ") + format, __FILE__, __LINE__, ##__VA_ARGS__)
#define LOG_CRITICAL(format, ...) default_logger->critical(std::string("[{}:{}] ") + format, __FILE__, __LINE__, ##__VA_ARGS__)

对日志输出类的测试

我们编写如下的代码进行测试日志输出类:

#include "logger.hpp"
#include <iostream>
#include <gflags/gflags.h>

DEFINE_bool(run_mode, false, "调试模式下的日志输出");
// DEFINE_string(log_path, "./log", "日志文件路径");
DEFINE_string(log_name, "", "日志文件名称");
DEFINE_int32(log_level, 0, "日志级别");


int main(int argc, char* argv[])
{
    google::ParseCommandLineFlags(&argc, &argv, false);
    init_logger(FLAGS_run_mode, FLAGS_log_name, FLAGS_log_level);

    LOG_TRACE("This is a trace log: {}", "TRACE");
    LOG_DEBUG("This is a debug log: {}", "DEBUG");
    LOG_INFO("This is a info log: {}", "INFO");
    LOG_WARN("This is a warn log: {}", "WARN");
    LOG_ERROR("This is a error log: {}", "ERROR");
    LOG_CRITICAL("This is a critical log: {}", "CRITICAL");

    return -1;
}

此时可以生成可执行程序,并根据以下命令进行运行:

./main --run_mode=true --log_name="my_log" --log_level=2

生成日志文件为:

wqy@wqy-virtual-machine:~/warehouse/gitClone/linux/Project/MIM-System/test/spdlog-test$ cat my_log
[default_logger][08:37:51][6590][info    ][main.cc:18] This is a info log: INFO
[default_logger][08:37:51][6590][warning ][main.cc:19] This is a warn log: WARN
[default_logger][08:37:51][6590][error   ][main.cc:20] This is a error log: ERROR
[default_logger][08:37:51][6590][critical][main.cc:21] This is a critical log: CRITICAL

安装

一般习惯直接通过包管理器进行安装:

  • Ubuntu/Debian:

    sudo apt update
    sudo apt install libspdlog-dev
    
  • Fedora:

    sudo dnf install spdlog-devel
    

当然也可以通过源码进行编译安装:

  1. 安装依赖(确保你已经安装了 CMake 和构建工具):

    sudo apt install cmake g++  # Ubuntu/Debian
    
  2. 克隆 spdlog 的 GitHub 仓库

    git clone https://github.com/gabime/spdlog.git
    cd spdlog
    
  3. 创建构建目录并进入

    mkdir build
    cd build
    
  4. 运行 CMake

    cmake ..
    
  5. 编译和安装

    make
    sudo make install
    

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

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

相关文章

突发:Sam万字长文,OpenAI o1超越人类,o1模型训练原理、微调、能力来源-AI已死,大模型当立

OpenAl o1大模型&#xff1a;原理、突破、前景及影响 北京时间2024年9月13日凌晨&#xff0c;OpenAI正式发布了新的人工智能模型o1&#xff08;o是orion猎户座&#xff0c;1代表从头再来&#xff0c;也意味着后续将出现更多序列&#xff09;&#xff0c;就是此前OpenAI一直在高…

烟雾污染云层检测系统源码分享

烟雾污染云层检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer…

嵌入式学习--LinuxDay04

嵌入式学习--LinuxDay04 shell脚本 1.1数组 1.1.1数组的赋值 1.1.2数组的调用 1.2函数 1.2.1函数的定义方式 1.2.2函数的调用 2.分文件编程 2.1源文件 2.2头文件 3.编译工具 3.1 gcc编译工具 3.2 gdb调试 4.make工具 4.1定义 4.2Makefile格式 4.3Makefile管理多个文件 4.4Makef…

【笔记】X射线的衍射方向

X射线在晶体中的衍射&#xff0c;实质是大量原子散射波互相干涉的结果。 衍射花样有两个特征&#xff1a; 衍射方向&#xff08;衍射线在空间的分布规律&#xff09;&#xff1a;由晶胞的大小、形状和位向决定。 衍射强度&#xff1a;由原子的种类以及它在晶胞中所处的位置决…

56 门控循环单元(GRU)_by《李沐:动手学深度学习v2》pytorch版

系列文章目录 文章目录 系列文章目录门控循环单元&#xff08;GRU&#xff09;门控隐状态重置门和更新门候选隐状态隐状态 从零开始实现初始化模型参数定义模型训练与预测 简洁实现小结练习 门控循环单元&#xff08;GRU&#xff09; 之前我们讨论了如何在循环神经网络中计算梯…

PREDATOR: Registration of 3D Point Clouds with Low Overlap

Abstract 这篇文章介绍了一种新的点云配准模型-Predator。该模型专注于处理低重叠的点云对&#xff0c;它更加关注于重叠区域的处理&#xff0c;其新颖之处在于一个重叠的注意块&#xff0c;作用是用于两个点云的潜在编码之间的早期信息交换。该模型大大提高了低重叠场景下的配…

AI跟踪报道第58期-新加坡内哥谈技术-本周AI新闻: OpenAI动荡时刻和Meta从未如此动人

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

深度学习与数学归纳法

最近发现&#xff0c;深度学习可以分为两个主要的阶段&#xff0c;分别是前向推理以及反向传播&#xff0c;分别对应着网络的推理和参数训练两个步骤。其中推理有时候也称为归纳推理。 在做参数训练的时候&#xff0c;本质上是在利用历史数据求网络参数的先验分布&#xff1b; …

leetcode每日一题day15(24.9.25)——公司命名

思路&#xff1a;首先如果没有相同的后缀&#xff0c;则无论只要不是相同的首字母交换都不会出现重复情况&#xff0c;如果有重复后缀&#xff0c;则还需多增加个不能和&#xff0c;首字符与另一相同后缀字串的首字符相同的字串交换。 主要矛盾已经明确&#xff0c;则可对矛盾…

MySql5.7.26安装和配置

一.下载&#xff1a; 地址MySQL :: Download MySQL Community Server 1、选择版本 根据自己需要选择32位或64位版本&#xff08;这里选择64位&#xff09;点击下载 进入到下载页面按下图操作 2.解压文件放置位置&#xff1a;这边将下载的文件解压到D:Software 下 解压后内部文…

Linux---文件io

1.系统调用 由操作系统实现并提供给外部应用程序的编程接口。(Application Programming Interface&#xff0c;API)。是应用程序同系统之间数据交互的桥梁。 C标准函数和系统函数调用关系。一个helloworld如何打印到屏幕。 man手册中一共有九卷&#xff0c;其中一卷就有讲到系…

快速了解graphql特点

graphql--快速了解graphql特点 1.它的作用2.demo示例2.1依赖引入2.2定义schema2.3定义GrapQL端点2.4运行测试2.5一些坑 今天浏览博客时看到graphQL,之前在招聘网站上第一次接触,以为是图数据查询语言, 简单了解后,发现对graphQL的介绍主要是用作API的查询语言,不仅限于图数据查…

目标检测系列(三)yolov2的全面讲解

YOLOv2&#xff08;论文原名《YOLO9000: Better, Faster, Stronger》&#xff09;作为该系列的第二个版本&#xff0c;对原始YOLO进行了显著的改进&#xff0c;进一步提高了检测速度和准确度。在精度上利用一些列训练技巧&#xff0c;在速度上应用了新的网络模型DarkNet19&…

个性化大语言模型:PPlug——让AI更懂你

在当今数字化转型的时代&#xff0c;大型语言模型&#xff08;LLMs&#xff09;已经成为了不可或缺的工具&#xff0c;它们在自然语言理解、生成和推理方面展现了非凡的能力。然而&#xff0c;这些模型普遍采用的是“一刀切”的方式&#xff0c;即对于相同的输入给予所有用户相…

828华为云征文|部署多功能集成的协作知识库 AFFiNE

828华为云征文&#xff5c;部署多功能集成的协作知识库 AFFiNE 一、Flexus云服务器X实例介绍二、Flexus云服务器X实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置2.4 Docker 环境搭建 三、Flexus云服务器X实例部署 AFFiNE3.1 AFFiNE 介绍3.2 AFFiNE 部署3.3 AFFiNE 使用 四、…

【深度学习】(10)--ResNet残差网络

文章目录 ResNet残差网络1. 传统卷积神经网络的问题1.1 梯度消失和梯度爆炸1.2 退化问题 2. 解决问题2.1 梯度消失与爆炸2.2 退化问题 3. 残差结构结构归纳 4. BN&#xff08;Batch Normalization&#xff09; 总结 ResNet残差网络 ResNet 网络是在 2015年 由微软实验室中的何…

ComfyUI 完全入门:必备插件

前言 大家好&#xff0c;我是每天分享AI应用的月月&#xff01; ComfyUI 是一个基于 Stable Diffusion 的AI绘画创作工具&#xff0c;最近发展势头特别迅猛&#xff0c;但是 ComfyUI 的上手门槛有点高&#xff0c;用户需要对 Stable Diffusion 以及各种数字技术的原理有一定的…

小麦生长状态检测系统源码分享

小麦生长状态检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer…

基于SpringBoot的新冠检测信息管理系统的设计与实现

文未可获取一份本项目的java源码和数据库参考。 国内外在该方向的研究现状及分析 新型冠状病毒肺炎疫情发生以来&#xff0c;中国政府采取积极的防控策略和措施&#xff0c;经过两个多月的不懈努力&#xff0c;有效控制了新发病例的増长&#xff0c;本地传播已经趋于完全控制…

万字面试题大模型面试,最全八股和答案

自ChatGPT开启大模型时代以来&#xff0c;大模型正迎来飞速发展&#xff0c;现在从事大模型开发相关工作可谓是处在时代的风口。那么大模型面试需要哪些技能和技巧呢&#xff0c;本文详细整理了全套的面试问题及答案&#xff0c;希望对大家有所帮助&#xff01; 目录 大模型&a…