【C/C++ 类库】:spdlog 日志库

【CSDN】:spdlog生成日志
【R】:Introduction to RcppSpdlog
【GitHub】:spdlog wiki

1、spdlog 静态库编译

1、spdlog 项目源码下载 github地址
2、cmake 编译配置工具下载 官网地址
3、cmake 构建工程【configer—>generate】

在这里插入图片描述
4、VS 打开 spdlog.sln,编译生成静态库【spdlogd.lib、spdlog.lib】
注意:1.5.0之前版本新建文件需手动,同时库和主程序都用到spdlog时,不会共享注册器信息,需各自操作

2、调用 spdlog 静态库

1、创建配置 Windows 控制台应用【支持C++11】
  C/C++ — 常规 — 附加包含目录:设spdlog-1.x/include文件路径
  链接器 — 常规 — 附加库目录:设spdlog 静态库文件路径
  链接器 — 常规 — 附加依赖项:Debug模式添spdlogd.lib,Release模式添spdlog.lib
  C/C++ — 预处理器 — 预处理器定义:设_SCL_SECURE_NO_WARNINGS

2、GitHub 样例源码

//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

// spdlog usage example

#include <cstdio>

// 定义在spdlog等头文件前,否则覆盖, 调SPDLOG_TRACE等宏失效
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE

void load_levels_example();
void stdout_logger_example();
void basic_example();
void rotating_example();
void daily_example();
void async_example();
void binary_example();
void stopwatch_example();
void trace_example();
void multi_sink_example();
void user_defined_example();
void err_handler_example();
void syslog_example();
void custom_flags_example();

#include "spdlog/spdlog.h"
#include "spdlog/cfg/env.h" // support for loading levels from the environment variable

int main(int, char *[])
{
    // Log levels can be loaded from argv/env using "SPDLOG_LEVEL"
    load_levels_example();

    spdlog::info("Welcome to spdlog version {}.{}.{}  !", SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH);

    spdlog::warn("Easy padding in numbers like {:08d}", 12);          // 占位符, 共8位
    spdlog::critical("Support for int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}", 42);   //进制:10、16、oct 8、2
    spdlog::info("Support for floats {:03.2f}", 1.23456);             //[标志][最小宽度][.精度][类型长度]
    spdlog::info("Positional args are {1} {0}..", "too", "supported");
    spdlog::info("{:>8} aligned, {:<8} aligned", "right", "left");    // 8字符空白位, 设居右or居左

    // Runtime log levels
    // 日志级别从低到高 trace, debug, info, warn, err, critical, off, n_levels
    spdlog::set_level(spdlog::level::info); // Set global log level to info
    spdlog::debug("This message should not be displayed!");    // 日志级别已调高, Debug级不输出
    spdlog::set_level(spdlog::level::trace); // Set specific logger's log level
    spdlog::debug("This message should be displayed..");       // 日志级别已调低, Debug级输出

    // Customize msg format for all loggers
    // https://github.com/gabime/spdlog/wiki/3.-Custom-formatting
    spdlog::set_pattern("[%H:%M:%S %z] [%^%L%$] [thread %t] %v");     // 变更输出格式
    spdlog::info("This an info message with custom format");
    spdlog::set_pattern("%+"); // back to default format              // 返回默认格式
    spdlog::set_level(spdlog::level::info);

    // Backtrace support
    // Loggers can store in a ring buffer all messages (including debug/trace) for later inspection.
    // When needed, call dump_backtrace() to see what happened:
    spdlog::enable_backtrace(10); // create ring buffer with capacity of 10  messages
    for (int i = 0; i < 100; i++)
    {
        spdlog::debug("Backtrace message {}", i); // not logged..
    }
    // e.g. if some error happened:
    spdlog::dump_backtrace(); // log them now!

    try
    {
        stdout_logger_example();
        basic_example();
        rotating_example();
        daily_example();
        async_example();
        binary_example();
        multi_sink_example();
        user_defined_example();
        err_handler_example();
        trace_example();
        stopwatch_example();
        custom_flags_example();

        // Flush all *registered* loggers using a worker thread every 3 seconds.
        // note: registered loggers *must* be thread safe for this to work correctly!
        spdlog::flush_every(std::chrono::seconds(3));          // 默认定时刷日志

        // Apply some function on all registered loggers
        spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->info("End of example."); });

        // Release all spdlog resources, and drop all loggers in the registry.
        // This is optional (only mandatory if using windows + async log).
        spdlog::shutdown();
    }

    // Exceptions will only be thrown upon failed logger or sink construction (not during logging).
    catch (const spdlog::spdlog_ex &ex)
    {
        std::printf("Log initialization failed: %s\n", ex.what());
        return 1;
    }
}

在这里插入图片描述
spdlog_logger.hpp 自调用

#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_WARN

#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/async.h"

namespace xxxx 
{
    enum class logger_type 
    {
        file,
        console
    };

    template<logger_type Type>
    inline static void create_logging(const std::string& dir) 
    {
        spdlog::init_thread_pool(8192 * 2, 1); // 16k
        std::shared_ptr<spdlog::logger> l;
        if (Type == logger_type::console)
        {
            l = spdlog::stdout_color_mt("some_unique_name");
        }
        else 
        {
            l = spdlog::create_async_nb<spdlog::sinks::rotating_file_sink_mt>
                ("async_file_logger", dir, 1024 * 1024 * 10, 5);
        }

        // 日志级别从低到高 trace, debug, info, warn, err, critical, off, n_levels
        l->flush_on(spdlog::level::warn);
        l->set_pattern("[%Y-%m-%d %T.%e][tid:%t  %s:%#] [%l] %v");
        spdlog::flush_every(std::chrono::seconds(3));
        spdlog::set_default_logger(l);
    }
}
3、线程安全

非线程安全函数

set_error_handler(log_err_handler);

// returns a reference to a non thread safe vector, 
// so don't modify it concurrently (e.g. logger->sinks().push_back(new_sink);)
logger::sinks()

创建 loggers

// To create thread safe loggers, use the _mt factory functions.
auto logger = spdlog::basic_logger_mt(...);

// To create single threaded loggers, use the _st factory functions.
auto logger = spdlog::basic_logger_st(...);

创建 sinks

// 线程安全的 sinks: sinks 以 _mt 结尾 (e.g daily_file_sink_mt)

//非线程安全的 sinks: sinks 以 _st 结尾 (e.g daily_file_sink_st)
4、创建 loggers

通过工厂函数创建logger:spdlog wiki

#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");
}

使用spdlog :: get 访问记录器【锚点:注册 loggers】

// Note: spdlog::get might slow your code down since it locks a mutex, so use with caution. 
// It is advisable to save the shared_ptr<spdlog::logger> returned and use it directly, at least in code hot paths.

class MyClass
{
private:
   std::shared_ptr<spdlog::logger> _logger;
public:
   MyClass()
   {
     //set _logger to some existing logger
     _logger = spdlog::get("some_logger");    //存下指针,后续利用避免get
     //or create directly
     //_logger = spdlog::rotating_file_logger_mt("my_logger", ...);
   }
};

创建基础 logger【不旋转】

#include "spdlog/sinks/basic_file_sink.h"
void basic_example()
{
    // Create basic file logger (not rotated).
    auto my_logger = spdlog::basic_logger_mt("file_logger", "logs/basic-log.txt");
}

创建滚动文件 logger【可设文件容量和滚动文件数】

#include "spdlog/sinks/rotating_file_sink.h"
void rotating_example()
{
    // Create a file rotating logger with 5mb size max and 3 rotated files.
    auto rotating_logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 
    	1024 * 1024 * 5, 3);
}

创建每日文件 logger【可设固定时间点来新建文件】

#include "spdlog/sinks/daily_file_sink.h"
void daily_example()
{
    // Create a daily logger - a new file is created every day on 2:30am.
    auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
}

工厂创建异步 logger【锚点:异步记录】

#include "spdlog/async.h"
void async_example()
{
    // Default thread pool settings can be modified *before* creating the async logger:
    // spdlog::init_thread_pool(32768, 1); // queue with max 32k items 1 backing thread.
    auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>(
    	"async_file_logger", "logs/async_log.txt");
    // alternatively:
    // auto async_file = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt");

    for (int i = 1; i < 101; ++i)
    {
        async_file->info("Async message #{}", i);
    }
}

手动创建 loggers 【sink 和 logger 关系为 n:n】

auto sink = std::make_shared<spdlog::sinks::stdout_sink_mt>();
auto my_logger= std::make_shared<spdlog::logger>("mylogger", sink);

创建 loggers 挂载 多个sink

// A logger with multiple sinks (stdout and file) - each with a different format and log level.
void multi_sink_example()
{
	// 日志级别从低到高 trace, debug, info, warn, err, critical, off, n_levels
    auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
    console_sink->set_level(spdlog::level::warn);
    console_sink->set_pattern("[multi_sink_example] [%^%l%$] %v");

    auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/multisink.txt", true);
    file_sink->set_level(spdlog::level::trace);

    spdlog::logger logger("multi_sink", {console_sink, file_sink});    // Logger with sinks init list
    logger.set_level(spdlog::level::debug);
    logger.warn("this should appear in both console and file");
    logger.info("this message should not appear in the console, only in the file");
}

在这里插入图片描述
在这里插入图片描述
创建多个文件loggers 可共享同一输出文件

auto shared_file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("fileName.txt");
auto first_logger = std::make_shared<spdlog::logger>("first_logger_name", shared_file_sink);
auto second_logger = std::make_unique<spdlog::logger>("second_logger_name", shared_file_sink);
5、自定义格式

自定义logger格式 spdlog wiki

// default logging format:[2014-10-31 23:46:59.678] [my_loggername] [info] Some message
// Set the pattern string (recommended)
set_pattern(pattern_string);

// Or implement custom formatter that implements the formatter interface and call
set_formatter(std::make_shared< my_custom_formatter >());

使用set_pattern(…)自定义格式

// Format can be applied globally to all registered loggers:
spdlog::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***");

// or to a specific logger object:
some_logger->set_pattern(">>>>>>>>> %H:%M:%S %z %v <<<<<<<<<");

// or to a specific sink object:
some_logger->sinks()[0]->set_pattern(">>>>>>>>> %H:%M:%S %z %v <<<<<<<<<");
some_logger->sinks()[1]->set_pattern("..");

自定义标志扩展 spdlog

// Log patterns can contain custom flags.
// this will add custom flag '%*' which will be bound to a <my_formatter_flag> instance
#include "spdlog/pattern_formatter.h"
class my_formatter_flag : public spdlog::custom_flag_formatter
{
public:
    void format(const spdlog::details::log_msg &, const std::tm &, spdlog::memory_buf_t &dest) override
    {
        std::string some_txt = "custom-flag";
        dest.append(some_txt.data(), some_txt.data() + some_txt.size());
    }

    std::unique_ptr<custom_flag_formatter> clone() const override
    {
        return spdlog::details::make_unique<my_formatter_flag>();
    }
};

void custom_flags_example()
{
    using spdlog::details::make_unique; // for pre c++14
    auto formatter = make_unique<spdlog::pattern_formatter>();
    formatter->add_flag<my_formatter_flag>('*').set_pattern("[%n] [%*] [%^%l%$] %v");
    spdlog::set_formatter(std::move(formatter));
}

在这里插入图片描述

6、创建 Sinks

sinks 是将日志实际写入其目标的对象,应仅负责单个目标【文件、控制台、数据库等】,且有各自的格式化程序对象专用实例。

每个logger都维护一组std :: shared_ptr < sink > , 在使用时将遍历该数组,逐个调sink(log_msg)

sink以_mt(多线程)或_st(单线程)为后缀,指示线程安全。
虽然不能同时从多线程中使用单线程sink,但是因无锁定,单线程sink更快。


rotating_file_sink【按文件大小和数量滚动文件】

// 滚动文件sink:当文件达设定内容大小时,则关闭并重命名,开新文件继续写; 当文件数达设定文件数,则删最旧文件并开新文件

#include "spdlog/sinks/rotating_file_sink.h"
...
// 设置滚动的最大文件大小 以及 最大文件数量, 例:文件大小最大为5MB,最多旋转3个文件
auto file_logger = spdlog::rotating_logger_mt("file_logger", "logs/mylogfile", 1048576 * 5, 3);

// 手动创建 sink 并传给 logger: 【方式二选一】
#include "spdlog/sinks/rotating_file_sink.h"
...
auto rotating = make_shared<spdlog::sinks::rotating_file_sink_mt> ("log_filename", 1024*1024, 5, false);
auto file_logger = make_shared<spdlog::logger>("my_logger", rotating);

daily_file_sink【每日定点新开文件】

// 每日文件sink: 每天在指定时间开新文件,并文件名后附一时间戳
#include "spdlog/sinks/daily_file_sink.h"
..
// 设置新开时间, 例:每天14:55
auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily", 14, 55);

simple_file_sink【简易写入文件】

// 简易文件sink: 无限制写入给定文件
#include "spdlog/sinks/basic_file_sink.h"
...
auto logger = spdlog::basic_logger_mt("mylogger", "log.txt");

stdout_sink/stderr_sink【标准 输出/错误输出】

#include "spdlog/sinks/stdout_sinks.h"
...
auto console = spdlog::stdout_logger_mt("console");
auto err_console = spdlog::stderr_logger_st("console");

stdout_sink/stderr_sink with colors【标准 输出/错误输出 附颜色】

#include "spdlog/sinks/stdout_color_sinks.h"
...
auto console = spdlog::stdout_color_mt("console");
auto err_console = spdlog::stderr_color_st("console");

// 或直接创建sink
auto sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();

ostream_sink【字节流输出】

#include "spdlog/sinks/ostream_sink.h "
...
std::ostringstream oss;
auto ostream_sink = std::make_shared<spdlog::sinks::ostream_sink_mt> (oss);
auto logger = std::make_shared<spdlog::logger>("my_logger", ostream_sink);

null_sink【调试】

// 空sink: 丢弃日志, 可用作调试或用作参考实现
#include "spdlog/sinks/null_sink.h"
...
auto logger = spdlog::create<spdlog::sinks::null_sink_st>("null_logger");

syslog_sink【待定】

// POSIX syslog(3) sink: 将其日志发送到syslog
#include "spdlog/sinks/syslog_sink.h"
...
spdlog::syslog_logger logger("logger_name", "my_ident");

systemd_sink【待定】

// systemd sink:sink:将其日志发送到systemd
#include "spdlog/sinks/systemd_sink.h"
...
auto systemd_sink = std::make_shared<spdlog::sinks::systemd_sink_st>();
spdlog::logger logger("logger_name", systemd_sink);

dist_sink【分发消息给各接收器】

// 分发sink: 将日志消息分发到其他接收器列表
#include "spdlog/sinks/dist_sink.h"
...
auto dist_sink = make_shared<spdlog::sinks::dist_sink_st>();
auto sink1 = make_shared<spdlog::sinks::stdout_sink_st>();
auto sink2 = make_shared<spdlog::sinks::simple_file_sink_st>("mylog.log");

dist_sink->add_sink(sink1);
dist_sink->add_sink(sink2);

msvc_sink【用OutputDebugStringA输出调试信息】

// msvc sink: Windows调试接收器(使用OutputDebugStringA记录)
#include "spdlog/sinks/msvc_sink.h"
auto sink = std::make_shared<spdlog::sinks::msvc_sink_mt>();
auto logger = std::make_shared<spdlog::logger>("msvc_logger", sink);

dup_filter_sink【重复信息删除】

// 若前一个相同并且小于 max_skip_duration, 则跳过该消息。
#include "spdlog/sinks/dup_filter_sink.h"

auto dup_filter = std::make_shared<dup_filter_sink_st>(std::chrono::seconds(5));
dup_filter->add_sink(std::make_shared<stdout_color_sink_mt>());
spdlog::logger l("logger", dup_filter);
l.info("Hello");
l.info("Hello");
l.info("Hello");
l.info("Different Hello");

// 输出结果:
[2019-06-25 17:50:56.511] [logger] [info] Hello
[2019-06-25 17:50:56.512] [logger] [info] Skipped 3 duplicate messages..
[2019-06-25 17:50:56.512] [logger] [info] Different Hello

实现自己的 sink

#include "spdlog/sinks/base_sink.h"

// 继承base_sink【已处理锁锁定】,仅需实现sink_it_ 和 flush_
template<typename Mutex>
class my_sink : public spdlog::sinks::base_sink <Mutex>
{
...
protected:
    void sink_it_(const spdlog::details::log_msg& msg) override
    {
    // log_msg is a struct containing the log entry info like level, timestamp, thread id etc.
    // msg.raw contains pre formatted log

    // If needed (very likely but not mandatory), 
    // the sink formats the message before sending it to its final destination:
    spdlog::memory_buf_t formatted;
    base_sink<Mutex>::formatter_->format(msg, formatted);    // 最好先格式化信息
    std::cout << fmt::to_string(formatted);
    }

    void flush_() override 
    {
       std::cout << std::flush;
    }
};

#include "spdlog/details/null_mutex.h"
#include <mutex>
using my_sink_mt = my_sink<std::mutex>;
using my_sink_st = my_sink<spdlog::details::null_mutex>;

可将自定义sinks推入logger的skins vector,但无锁保护,非线程安全

inline std::vector<spdlog::sink_ptr> &spdlog::logger::sinks()
{
    return sinks_;
}
7、注册 loggers

根据 logger name 获取全局 logger

spdlog::get("logger1")->info("hello");
.. 
.. 
some other source file..
..
auto l = spdlog::get("logger1");    // 查找失败返回空
l->info("hello again");

注册/删除 手动创建的logger【锚点:创建 loggers】

// 通常无需注册logger,因为它们可自动注册, 若要注册手动创建的logger,则调register_logger(...)
// 注册表中若存在的相同名称时, 注册将引发spdlog :: spdlog_ex异常
spdlog::register_logger(some_logger)

// 从注册表中删除 指定名字的logger
// 若不存在指向该logger的其他shared_ptr,则该logger将关闭并释放资源
pdlog::drop("logger_name");

// 从注册表中删除 所有logger
spdlog::drop_all()
8、异步记录

使用< spdlog :: async_factory >模板参数 【锚点:创建 loggers】

#include "spdlog/async.h"
void async_example()
{
    // default thread pool settings can be modified *before* creating the async logger:
    // spdlog::init_thread_pool(8192, 1); // queue with 8k items and 1 backing thread.
    auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>(
    	"async_file_logger", "logs/async_log.txt");
}

使用 spdlog::create_async< Sink > 创建 loggers【在队列上不会阻塞】

auto async_file = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>(
	"async_file_logger", "logs/async_log.txt"); 

使用 spdlog::create_async_nb< Sink > 创建 loggers

auto async_file = spdlog::create_async_nb<spdlog::sinks::basic_file_sink_mt>(
	"async_file_logger", "logs/async_log.txt");

直接构造并使用全局线程池

spdlog::init_thread_pool(queue_size, n_threads);
auto logger = std::make_shared<spdlog::async_logger>(
	"as", some_sink, spdlog::thread_pool(), async_overflow_policy::block);

直接构造并使用自定义线程池

// tp生命周期必须超过logger,因为logger获取了tp的weak_ptr
auto tp = std::make_shared<details::thread_pool>(queue_size, n_threads);
auto logger = std::make_shared<spdlog::async_logger>("as", some_sink, tp, async_overflow_policy::block);

满队列策略 选择设置

// 1、阻塞直至有更多空间(默认行为)

// 2、将队列中最旧消息换为新消息,而不是等待更多空间
auto logger = spdlog::create_async_nb<spdlog::sinks::basic_file_sink_mt>(
	"async_file_logger", "logs/async_log.txt");
// 或者直接:
 auto logger = std::make_shared<async_logger>("as", test_sink, 
 	spdlog::thread_pool(), spdlog::async_overflow_policy::overrun_oldest);

spdlog 线程池设置

// 默认情况下,spdlog创建一个 queue_size=8192,n_threads=1 的全局线程池,以服务所有异步logger
// init_thread_pool将删除旧全局tp以新建线程池, 意味着所有使用旧tp的logger都将停止, 因此建议在创任何异步logger前调用
spdlog::init_thread_pool(queue_size, n_threads);    //可配队列大小和线程数

// 如果不同的logger必须具有单独队列,则可创建池的不同实例并传递给logger
auto tp = std::make_shared<details::thread_pool>(128, 1);
auto logger = std::make_shared<async_logger>(
	"as", some_sink, tp, async_overflow_policy::overrun_oldest);

auto tp2 = std::make_shared<details::thread_pool>(1024, 4);  
auto logger2 = std::make_shared<async_logger>(
	"as2", some_sink, tp2, async_overflow_policy::block);

// 多线程可能会重新排序消息, 若要保持原顺序, 则线程池仅创建一个线程
// 若使用异步日志, main退出之前调用spdlog::shutdown()
9、刷新策略

缺省情况下,spdlog允许基础libc在合适时刷新,也选用以下选项:

手动刷新

// logger将依次在每个sink上调用flush
logger->flush()

// 当前, 无需在关闭前显式调logger->flush()或spdlog::shutdown(), 因其会在程序退出时自动销毁。
// 但是, 若要在“立即”退出函数(abort或exit)前手动刷新所有异步looger,则需此前调spdlog :: shutdown()

基于级别刷新

// 可设置触发自动刷新的最低日志级别, 例:每当记录错误或更严重的消息时刷新
my_logger->flush_on(spdlog::level::err); 

基于间隔刷新

// spdlg支持设置刷新间隔, 其由单个工作线程定期在每个logger上调用flush实现, 例:定期为所有注册的logger隔5秒刷新
spdlog::flush_every(std::chrono::seconds(5));
10、特殊操作

环境变量初始化日志等级

int main(int, char* [])
{
    // Log levels can be loaded from argv/env using "SPDLOG_LEVEL"
    spdlog::set_level(spdlog::level::trace);
    spdlog::level::level_enum pre_level = spdlog::get_level();     //trace
    load_levels_example();
    spdlog::level::level_enum last_level = spdlog::get_level();    //info
    
	// ...
}
    
#include "spdlog/cfg/env.h"
void load_levels_example()
{
    // Set the log level to "info" and mylogger to to "trace":
    // SPDLOG_LEVEL=info,mylogger=trace && ./example
    spdlog::cfg::load_env_levels();    // VS 属性—调试—环境 中设SPDLOG_LEVEL=info,mylogger=trace
    // or from command line:
    // ./example SPDLOG_LEVEL=info,mylogger=trace
    // #include "spdlog/cfg/argv.h" // for loading levels from argv
    // spdlog::cfg::load_argv_levels(args, argv);
}

在这里插入图片描述


长数据 二进制转十六进制

// Log binary data as hex.
// Many types of std::container<char> types can be used.
// Iterator ranges are supported too.
// Format flags:
// {:X} - print in uppercase.    // 用大写字母打印
// {:s} - don't separate each byte with space.    // 不用空格分隔每个字节
// {:p} - don't print the position on each line start.       // 不用在每行开始处打印位置信息
// {:n} - don't split the output to lines.        // 不用将输出拆分成几行
// {:a} - show ASCII if :n is not set             // 显示ASCII

#include "spdlog/fmt/bin_to_hex.h"
void binary_example()
{
    std::vector<char> buf(80);
    for (int i = 0; i < 80; i++)
    {
        buf.push_back(static_cast<char>(i & 0xff));
    }
    spdlog::info("Binary example: {}", spdlog::to_hex(buf));
    spdlog::info("Another binary example:{:n}", spdlog::to_hex(std::begin(buf), std::begin(buf) + 10));
    // more examples:
    spdlog::info("uppercase: {:X}", spdlog::to_hex(buf));    // 大写
    spdlog::info("uppercase, no delimiters: {:Xs}", spdlog::to_hex(buf));    // 大写 且 不留空格
    spdlog::info("uppercase, no delimiters, no position info: {:Xsp}", spdlog::to_hex(buf));    // 大写 且 不留空格 且 无位置信息
    spdlog::info("hexdump style: {:a}", spdlog::to_hex(buf));    // 显示ASCII
    spdlog::info("hexdump style, 20 chars per line {:a}", spdlog::to_hex(buf, 20));    // 显示ASCII, 20字符一行
}

在这里插入图片描述


调宏输出日志

// Compile time log levels.
// define SPDLOG_ACTIVE_LEVEL to required level (e.g. SPDLOG_LEVEL_TRACE)

// 定义在spdlog等头文件前,否则覆盖, 调SPDLOG_TRACE等宏失效
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE    

void trace_example()
{
	spdlog::set_level(spdlog::level::trace);     // 确保日志等级等于trace
	
    // trace from default logger
    SPDLOG_TRACE("Some trace message.. {} ,{}", 1, 3.23);
    // debug from default logger
    SPDLOG_DEBUG("Some debug message.. {} ,{}", 1, 3.23);

    // trace from logger object
    auto logger = spdlog::get("file_logger");    // 应注意get前需先register_logger, 因内含锁, 故建议存下返回值以利用
    SPDLOG_LOGGER_TRACE(logger, "another trace message");
}

在这里插入图片描述


查看运行时间

// stopwatch example
#include "spdlog/stopwatch.h"
#include <thread>
void stopwatch_example()
{
    spdlog::stopwatch sw;
    std::this_thread::sleep_for(std::chrono::milliseconds(123));
    spdlog::info("Stopwatch: {} seconds", sw);
}

在这里插入图片描述


自定义类型来输出日志

// User defined types logging by implementing operator<<
#include "spdlog/fmt/ostr.h" // must be included
struct my_type
{
    int i;
    template<typename OStream>
    friend OStream &operator<<(OStream &os, const my_type &c)
    {
        return os << "[my_type i=" << c.i << "]";
    }
};

void user_defined_example()
{
    spdlog::info("user defined type: {}", my_type{14});
}

在这里插入图片描述


自定义错误处理程序【将在日志失败时触发】

// 自定义错误处理程序, 将在日志失败时触发
void err_handler_example()
{
    // can be set globally or per logger(logger->set_error_handler(..))
    spdlog::set_error_handler([](const std::string &msg) { 
    	printf("*** Custom log error handler: %s ***\n", msg.c_str()); 
    });
}

Linux 系统应用 spdlog

// syslog example (linux/osx/freebsd)
#ifndef _WIN32
#include "spdlog/sinks/syslog_sink.h"
void syslog_example()
{
    std::string ident = "spdlog-example";
    auto syslog_logger = spdlog::syslog_logger_mt("syslog", ident, LOG_PID);
    syslog_logger->warn("This is warning that will end up in syslog.");
}
#endif

Android 系统应用 spdlog

// Android example.
#if defined(__ANDROID__)
#include "spdlog/sinks/android_sink.h"
void android_example()
{
    std::string tag = "spdlog-android";
    auto android_logger = spdlog::android_logger_mt("android", tag);
    android_logger->critical("Use \"adb shell logcat\" to view this message.");
}
#endif
  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值