前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >开源库推荐——spdlog

开源库推荐——spdlog

作者头像
程序员的园
发布2024-07-18 13:20:50
发布2024-07-18 13:20:50
27200
代码可运行
举报
运行总次数:0
代码可运行

背景

在软件开发领域,日志记录是一项至关重要的工作。它不仅是程序运行情况的实时记录者,更是故障排查和系统优化的关键依据。然而,随着项目规模的扩大和复杂性的增加,传统的日志管理方式已经难以满足开发者的需求。这时候,一个高效、灵活的日志库就显得尤为重要。在众多的日志库中spdlog以其出色的性能和便捷的使用方式,赢得了广大开发者的青睐。

概述

spdlog,顾名思义,是一款追求速度和性能的日志库。它采用先进的异步日志处理技术,能够在不影响主程序性能的前提下,实现高效、实时的日志记录。同时,spdlog还提供了丰富的日志级别和灵活的日志格式设置,满足不同场景下的日志记录需求。

特性

spdlog的主要特性如下:

  • 高性能:采用异步日志处理技术,将日志记录操作与主程序运行分离,从而避免了日志记录对程序性能的影响。
  • 灵活的日志级别:支持多种日志级别,如DEBUG、INFO、WARN、ERROR等,方便开发者根据不同的需求选择合适的日志级别。
  • 可定制的日志格式:开发者可以根据自己的喜好和项目需求,定制个性化的日志格式,使日志输出更加清晰易读。
  • 强大的扩展性:SPDLOG支持多种输出目标,如文件、控制台、网络等,同时还可以通过插件机制实现与其他系统的集成。
  • 跨平台:在几乎所有支持C++编译器的平台上运行,包括Linux, FreeBSD, OpenBSD, Solaris, AI、Windows (msvc, cygwin)、macOS、Android。

使用方法

下载和编译

源码下载:https://github.com/gabime/spdlog

spdlog为header only的日志库,无需编译,只需添加到项目中即可。

如果需要查看工程中的examples时,需要使用cmake进行编译,关于这部分的资料已经很多了,在此不再赘述。

初级示例

代码语言:javascript
代码运行次数:0
运行
复制
#include "spdlog/sinks/stdout_color_sinks.h"
// or #include "spdlog/sinks/stdout_sinks.h" if no colors needed.
void stdout_logger_example() {
    // Create color multi threaded logger.
    auto console = spdlog::stdout_color_mt("console");
    // or for stderr:
    // auto console = spdlog::stderr_color_mt("error-logger");
    console->debug(__FUNCTION__);
    console->info(__FUNCTION__);
}

int main()
{
    spdlog::set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] \t[%P/%t] %v");
    spdlog::set_level(spdlog::level::debug);
    stdout_logger_example();
}
/*
output:
[2024-03-03 13:48:31.101] [debug]       [17564/27436] stdout_logger_example
[2024-03-03 13:48:31.102] [info]        [17564/27436] stdout_logger_example
*/

由于内部工厂函数不可见,导致看到如上代码时,并不能理解到spdlog的架构。整体架构如下

有上图可知,

1. spdlog拥有全局唯一的管理器(registry),registry用于管理和维护所有的logger实例。它提供了一系列的函数来创建、获取、删除logger实例,并支持对logger的全局配置。

2. 管理器中可以有多个日志记录器(logger/async_logger),日志记录器分为两类:同步日志记录和异步日志记录,logger是spdlog中的基本组件,用于记录日志消息。它提供了一系列的日志记录函数(如debug()、info()、error()等),以及设置日志级别、格式化输出等功能。logger可以输出到多个sink(日志记录器),如控制台、文件、syslog等。async_logger是从logger派生而来的一种特殊logger,用于实现异步的日志记录功能。它使用异步队列来缓冲日志消息,并通过后台线程将消息写入到指定的输出目标中,以提高性能和响应速度。

3. spdlog内有多个种类的日志记录器,日志记录器负责将日志消息发送到指定的输出目标。spdlog提供了多种内置的Sink,如stdout_sink、rotating_file_sink等,以支持不同的日志输出方式。开发者也可以自定义Sink,以满足特定的日志记录需求。

4. 日志格式化器用于将日志消息格式化为指定的字符串形式。可以通过为每个日志记录器(sink)自定义独有/共有的日志格式化器来定制日志消息的输出格式,包括时间格式、日志级别、线程ID等信息。

5. 异步日志记录线程池,负责从异步队列中取出日志消息,并将其写入到指定的输出目标中。它与async_logger配合工作,实现了异步的日志记录功能。。

进阶示例

本文将会结合实际的使用场景来展示spdlog的使用。

场景:在sdk开发中,sdk中的日志不仅需要保存到本地,同时希望通过回调函数的形式,将日志返回给sdk的调用者。日志信息形如“[年-月-日 时:分:秒.毫秒][日志等级][进程id/线程id] message”

分析如上场景可知,需要两个日志记录器,一个用于书写文件,一个用于回调;需要设置日志的格式化器。

常用的日志的格式化器标识符

flag

释义

%Y

四位数的年

%m

%d

%H

%M

%s

%e

毫秒

%n

日志记录器的名字

%l

日志等级

%L

日志等级(短)

%P

进程ID

%t

线程ID

%v

待输出的日志消息

例:"[%Y-%m-%d %H:%M:%S.%e] [%P/%t] [%l] %v"

自定义回调类型的日志记录器

代码语言:javascript
代码运行次数:0
运行
复制
#ifndef MEMORYSINK_H
#define MEMORYSINK_H
#include<mutex>
#include "spdlog/sinks/base_sink.h"
#include "spdlog/details/log_msg.h"

namespace spdlog {

using memory_cb = std::function<void(const std::string&, size_t size)>;
namespace sinks{
 
template<typename Mutex>
class memory_sink final :public base_sink<Mutex> {
public:
    explicit memory_sink(memory_cb callback) : callback_(callback) {}
protected:
    void sink_it_(const spdlog::details::log_msg& msg) override {

        spdlog::memory_buf_t formatted;
        base_sink<std::mutex>::formatter_->format(msg, formatted);
        size_t msg_size = formatted.size();
        auto data = formatted.data();
        std::string clean_log_msg(data, msg_size);
        auto level = msg.level;

        clean_log_msg.erase(std::remove_if(clean_log_msg.begin(), clean_log_msg.end(), [](unsigned char c) { return !isprint(c); }), clean_log_msg.end());

        if (callback_) {
            std::stringstream ss;
            ss << clean_log_msg;
            callback_(ss.str(), msg_size);
        }
    }

    void flush_() override {}

private:
   memory_cb callback_;
};

using memory_sink_mt = memory_sink<std::mutex>;
using memory_sink_st = memory_sink<details::null_mutex>;

}//namespace sinks
}//namespace spdlog

#endif//MEMORYSINK_H

使用多个日志记录器的样例代码

代码语言:javascript
代码运行次数:0
运行
复制
int main()
{
    auto memory_sink = std::make_shared<spdlog::sinks::memory_sink_mt>(
        [](const std::string &log_message, size_t data_size) {
            std::cout << log_message << "\n";  // 此处简写,本应为回调函数给调用方
        });
    auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("d://Garden_for_programmer.txt", true);
    auto m_spdlog_log = std::make_shared<spdlog::logger>(
        "wanos_log", spdlog::sinks_init_list{file_sink, memory_sink});
    m_spdlog_log->set_level(spdlog::level::debug);
    m_spdlog_log->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%P/%t] [%l] %v");
    spdlog::register_logger(m_spdlog_log);//注册到管理类中

    m_spdlog_log->debug("hello world");
    m_spdlog_log->info("this is an info log");
}

总结

spdlog是一个功能强大且易于使用的C++日志库,它具有高性能、灵活性和线程安全等优点。同时,支持自定义日志记录器,极大的方便用户,且扩展了spdlog的使用场景。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-03-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员的园 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档