前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >spdlog日志库的使用

spdlog日志库的使用

作者头像
CPP开发前沿
发布2021-12-16 17:22:05
2.7K0
发布2021-12-16 17:22:05
举报
文章被收录于专栏:CPP开发前沿CPP开发前沿

1 spdlog初识

今天介绍一个开源日志库,只需要将include下面的文件拷贝到自己的代码目录下,就可以在项目中使用。使用效果如下图所示:

值得注意的是,使用时编译器需要支持C++11。

上面日志输出的代码如下:

代码语言:javascript
复制
#include "spdlog/spdlog.h"
#include "spdlog/fmt/fmt.h"
int main()
{
  spdlog::info("Welcome to spdlog!");
  spdlog::error("Some error message with arg: {}", 1);
  spdlog::warn("Easy padding in numbers like {:08d}", 12);
  spdlog::critical("Support for int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}", 42);
  spdlog::info("Support for floats {:03.2f}", 1.23456);
  spdlog::info("Positional args are {1} {0}..", "too", "supported");
  spdlog::info("{:<30}", "left aligned");
  spdlog::set_level(spdlog::level::debug); // Set global log level to debug
  spdlog::debug("This message should be displayed..");
}

看到这里是不是对spdlog充满了好奇。spdlog不仅使用方便,日志输出多样,且功能非常强大。

总体来说具有以下特点:

1、性能快

2、使用简单,只需要包含头文件即可

3、丰富的格式化处理,采用开源库fmt,地址:https://github.com/fmtlib/fmt

4、异步模式,支持异步写文件

5、自定义日志输出格式

6、支持多线程日志输出

7、对日志进行设置,如:日志大小、生成日志频率、系统日志、日志颜色设置

8、日志输出级别即时生效

9、各种日志目标:可对日志文件进行循环输出;可每日生成日志文件;支持控制台日志输出(支持颜色);系统日志;Windows debugger;较容易扩展自定义日志目标;

10、可以通过程序函数入口或者环境变量加载日志级别

11、调试时根据需要对日志进行缓存,并在需要的时候进行输出

2 spdlog使用介绍

2.1 创建stdout/stderr记录器对象

代码语言:javascript
复制
#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h"
void stdout_example()
{
    // create color multi threaded logger
    auto console = spdlog::stdout_color_mt("console");    
    auto err_logger = spdlog::stderr_color_mt("stderr");    
    spdlog::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name)");
}

2.2 基本文件记录器

代码语言:javascript
复制
#include "spdlog/sinks/basic_file_sink.h"
void basic_logfile_example()
{
    try 
    {
        auto logger = spdlog::basic_logger_mt("basic_logger", "logs/basic-log.txt");
    }
    catch (const spdlog::spdlog_ex &ex)
    {
        std::cout << "Log init failed: " << ex.what() << std::endl;
    }
}

2.3 设置文件大小

代码语言:javascript
复制
#include "spdlog/sinks/rotating_file_sink.h"
void rotating_example()
{
    // Create a file rotating logger with 5mb size max and 3 rotated files
    auto max_size = 1048576 * 5;
    auto max_files = 3;
    auto logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", max_size, max_files);
}

2.4 设置文件生成频率,按日生成

代码语言:javascript
复制

#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 logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
}

2.5 日志回溯

调试日志可以暂时保存在内存中,需要的时候可以通过接口对缓存的日志进行输出,通过参数可以设置日志缓存和输出的日志记录数。下面的代码设置保存最近的32条日志消息。

代码语言:javascript
复制
spdlog::enable_backtrace(32); 
for(int i = 0; i < 100; i++)
{
  spdlog::debug("Backtrace message {}", i);
}
// e.g. if some error happened:
spdlog::dump_backtrace(); // log them now! show the last 32 messages
// or my_logger->dump_backtrace(32)..

2.6 按照周期输出日志

下面的代码实现了每3秒进行一次日志输出,但同时也要注意,使用时确保日志对象是线程安全的。

代码语言:javascript
复制
spdlog::flush_every(std::chrono::seconds(3));

2.7 按照周期输出日志

打印生命周期时间。

代码语言:javascript
复制
#include "spdlog/stopwatch.h"
void stopwatch_example()
{
    spdlog::stopwatch sw;    
    spdlog::debug("Elapsed {}", sw);
    spdlog::debug("Elapsed {:.3}", sw);       
}

2.8 用16进制保存二进制数据

代码语言:javascript
复制
#include "spdlog/fmt/bin_to_hex.h"
void binary_example()
{
    auto console = spdlog::get("console");
    std::array<char, 80> buf;
    console->info("Binary example: {}", spdlog::to_hex(buf));
    console->info("Another binary example:{:n}", spdlog::to_hex(std::begin(buf), std::begin(buf) + 10));
}

除此之外,还可以将字符串进行大小输出等。

功能如下:

{:X} - 转换为大写输出.

{:s} - 在十六进制中不要用空格分隔每个字节

{:p} - 不要在每行开始打印位置

{:n} - 不要将输出日志拆分为多行

{:a} - 如果没有设置:n,则显示ASCII码.

2.9 支持多种日志输出器

下面的代码支持两种,console日志将告警和错误输出到控制台,向文件中输出所有日志级别。

代码语言:javascript
复制
void multi_sink_example()
{
    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.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");
}

2.10 异步日志

代码语言:javascript
复制
#include "spdlog/async.h"
#include "spdlog/sinks/basic_file_sink.h"
void async_example()
{
    auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt");
}

2.11 支持多个日志记录器的异步日志

代码语言:javascript
复制
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/rotating_file_sink.h"

void multi_sink_example2()
{
    spdlog::init_thread_pool(8192, 1);
    auto stdout_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt >();
    auto rotating_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>("mylog.txt", 1024*1024*10, 3);
    std::vector<spdlog::sink_ptr> sinks {stdout_sink, rotating_sink};
    auto logger = std::make_shared<spdlog::async_logger>("loggername", sinks.begin(), sinks.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block);
    spdlog::register_logger(logger);
}

2.12 自定义类型

代码语言:javascript
复制
#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::get("console")->info("user defined type: {}", my_type{14});
}

2.13 用户在日志模式中定义标志

代码语言:javascript
复制
#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()
{    
    auto formatter = std::make_unique<spdlog::pattern_formatter>();
    formatter->add_flag<my_formatter_flag>('*').set_pattern("[%n] [%*] [%^%l%$] %v");
    spdlog::set_formatter(std::move(formatter));
}

上面的代码实现了一个用户自定义的类型:%*

2.14 自定义错误句柄

代码语言:javascript
复制
void err_handler_example()
{
    // can be set globally or per logger(logger->set_error_handler(..))
    spdlog::set_error_handler([](const std::string &msg) { spdlog::get("console")->error("*** LOGGER ERROR ***: {}", msg); });
    spdlog::get("console")->info("some invalid message to trigger an error {}{}{}{}", 3);
}

2.15 syslog

代码语言:javascript
复制
#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.");
}

2.16 从参数和环境变量中加载日志参数

代码语言:javascript
复制
#include "spdlog/cfg/env.h"
#include "spdlog/cfg/argv.h"
int main (int argc, char *argv[])
{
    spdlog::cfg::load_env_levels();
    spdlog::cfg::load_argv_levels(argc, argv);
}

程序执行时可以操作如下:

代码语言:javascript
复制
$ export SPDLOG_LEVEL=info,mylogger=trace
$ ./example

2.17 打开和关闭日志句柄

代码语言:javascript
复制
void file_events_example()
{
    handlers.before_open = [](spdlog::filename_t filename) { spdlog::info("Before opening {}", filename); };
    handlers.after_open = [](spdlog::filename_t filename, std::FILE *fstream) { fputs("After opening\n", fstream); };
    handlers.before_close = [](spdlog::filename_t filename, std::FILE *fstream) { fputs("Before closing\n", fstream); };
    handlers.after_close = [](spdlog::filename_t filename) { spdlog::info("After closing {}", filename); };
    auto my_logger = spdlog::basic_logger_st("some_logger", "logs/events-sample.txt", true, handlers);        
}

2.18 替换默认的日志记录器

代码语言:javascript
复制
void replace_default_logger_example()
{
    auto new_logger = spdlog::basic_logger_mt("new_default_logger", "logs/new-default-log.txt", true);
    spdlog::set_default_logger(new_logger);
    spdlog::info("new logger log message");
}

3 总结

目前,spdlog的版本为v1.x,可以通过下面链接获取:

https://github.com/gabime/spdlog

spdlog库支持已经系统:

  • 用户定义的Linux, FreeBSD, OpenBSD, Solaris, AIX
  • Windows (msvc 2013+, cygwin)
  • macOS(叮当声3.5 +)
  • 日志模式中的Androidflags

4 参考

链接:

1、https://github.com/gabime/spdlog

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

本文分享自 CPP开发前沿 微信公众号,前往查看

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

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

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