当前位置: 首页 > 工具软件 > spdlog > 使用案例 >

SPDLOG使用

尚景焕
2023-12-01

SPDLOG使用

因项目需要导入日志系统,所以需要对SPDLOG进行评测,具体的github地址:
https://github.com/gabime/spdlog


SPDLOG特性

提示:这里可以添加本文要记录的大概内容:
SPDLOG是一个快速的,并且只需要头文件编译的十分好用的日志系统,
具备以下特性

十分快速
仅仅需要头文件被编译
丰富的格式, 使用fmt库
异步模式 (可选)
定制化格式
单/多线程日志
多种日志功能:
   	日志分割;
    	每日日志文件
    	控制台日志输出(支持不同颜色)
    	系统日志
    	Windows事件记录
    	Windows调试器
    	容易扩展至自定义的log系统
日志筛选 - 日志级别可以在运行中和编译中进行更改
支持Backtrace - 可以将消息存储在环形缓冲中,并后续根据需要显示

一、SPDLOG评测

同步模式

[info] **************************************************************
[info] Single thread, 1,000,000 iterations
[info] **************************************************************
[info] basic_st Elapsed: 0.17 secs 5,777,626/sec
[info] rotating_st Elapsed: 0.18 secs 5,475,894/sec
[info] daily_st Elapsed: 0.20 secs 5,062,659/sec
[info] empty_logger Elapsed: 0.07 secs 14,127,300/sec
[info] **************************************************************
[info] C-string (400 bytes). Single thread, 1,000,000 iterations
[info] **************************************************************
[info] basic_st Elapsed: 0.41 secs 2,412,483/sec
[info] rotating_st Elapsed: 0.72 secs 1,389,196/sec
[info] daily_st Elapsed: 0.42 secs 2,393,298/sec
[info] null_st Elapsed: 0.04 secs 27,446,957/sec
[info] **************************************************************
[info] 10 threads, competing over the same logger object, 1,000,000 iterations
[info] **************************************************************
[info] basic_mt Elapsed: 0.60 secs 1,659,613/sec
[info] rotating_mt Elapsed: 0.62 secs 1,612,493/sec
[info] daily_mt Elapsed: 0.61 secs 1,638,305/sec
[info] null_mt Elapsed: 0.16 secs 6,272,758/sec

异步模式

[info] -------------------------------------------------
[info] Messages : 1,000,000
[info] Threads : 10
[info] Queue : 8,192 slots
[info] Queue memory : 8,192 x 272 = 2,176 KB
[info] -------------------------------------------------
[info]
[info] *********************************
[info] Queue Overflow Policy: block
[info] *********************************
[info] Elapsed: 1.70784 secs 585,535/sec
[info] Elapsed: 1.69805 secs 588,910/sec
[info] Elapsed: 1.7026 secs 587,337/sec
[info]
[info] *********************************
[info] Queue Overflow Policy: overrun
[info] *********************************
[info] Elapsed: 0.372816 secs 2,682,285/sec
[info] Elapsed: 0.379758 secs 2,633,255/sec
[info] Elapsed: 0.373532 secs 2,677,147/sec

二、快速上手

1.如何集成进项目中

spdlog集成进自己的项目十分方便,具体如下:

#include "spdlog/spdlog.h"
int main()
{
    //Use the default logger (stdout, multi-threaded, colored)
    spdlog::info("Hello, {}!", "World");
}

spdlog是一个头文件库,如果想使用,需要将include文件下的文件复制到项目中,并使用C++11编译器
库提供了一个类似phython形式的API,API使用fmt库

logger->info("Hello {} {} !!", "param1", 123.4);

spdlog使用了类似于"需要什么就include什么"的方式,工程代码中只需要include那些你需要的功能
例如:
如果你需要日志分割功能,只需要include"spdlog/sinks/rotating_file_sink.h"
如果你需要异步记录功能,需要include"spdlog/async.h"

2.基本例子

提供一个基本范例,使用方法

#include <iostream>
#include "spdlog/spdlog.h"
#include "spdlog/sinks/basic_file_sink.h" // support for basic file logging
#include "spdlog/sinks/rotating_file_sink.h" // support for rotating file logging

int main(int, char* [])
{
    try 
    {
        // Create basic file logger (not rotated)
        auto my_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic.txt");
        
        // create a file rotating logger with 5mb size max and 3 rotated files
        auto file_logger = spdlog::rotating_logger_mt("file_logger", "myfilename", 1024 * 1024 * 5, 3);
    }
    catch (const spdlog::spdlog_ex& ex)
    {
        std::cout << "Log initialization failed: " << ex.what() << std::endl;
    }
}

使用工厂模式-生成异步记录

#include <iostream>
#include "spdlog/spdlog.h"
#include "spdlog/async.h" //support for async logging.
#include "spdlog/sinks/basic_file_sink.h"

int main(int, char* [])
{
    try
    {        
        auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt");
        for (int i = 1; i < 101; ++i)
        {
            async_file->info("Async message #{}", i);
        }
        // Under VisualStudio, this must be called before main finishes to workaround a known VS issue
        spdlog::drop_all(); 
    }
    catch (const spdlog::spdlog_ex& ex)
    {
        std::cout << "Log initialization failed: " << ex.what() << std::endl;
    }
}

生成异步日志文件并改变线程池设置

#include "spdlog/async.h" //support for async logging
#include "spdlog/sinks/daily_file_sink.h"
int main(int, char* [])
{
    try
    {                                        
        auto daily_sink = std::make_shared<spdlog::sinks::daily_file_sink_mt>("logfile", 23, 59);
        // default thread pool settings can be modified *before* creating the async logger:
        spdlog::init_thread_pool(10000, 1); // queue with 10K items and 1 backing thread.
        auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt");       
        spdlog::drop_all(); 
    }
    catch (const spdlog::spdlog_ex& ex)
    {
        std::cout << "Log initialization failed: " << ex.what() << std::endl;
    }
}

3.具体项目方便调用

在include"spdlog.h"q前,可通过配置SPDLOG_ACTIVE_LEVEL到相应的日志级别
这可以在编译时打开/关闭日志,例如

#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG
spdlog::set_level(spdlog::level::debug); // or spdlog::set_level(spdlog::level::trace); 
SPDLOG_LOGGER_TRACE(file_logger , "Some trace message that will not be evaluated.{} ,{}", 1, 3.23);
SPDLOG_LOGGER_DEBUG(file_logger , "Some Debug message that will be evaluated.. {} ,{}", 1, 3.23);
SPDLOG_DEBUG("Some debug message to default logger that will be evaluated");

自定义日志(重要,用于自定义)

#include "spdlog/spdlog.h"
#include "spdlog/fmt/ostr.h" // must be included
#include "spdlog/sinks/stdout_sinks.h"

class some_class {};
std::ostream& operator<<(std::ostream& os, const some_class& c)
{ 
    return os << "some_class"; 
}

void custom_class_example()
{
    some_class c;
    auto console = spdlog::stdout_logger_mt("console");
    console->info("custom class with operator<<: {}..", c);
}

或者使用fmt库来使用高级格式

#include <iterator>

#include "spdlog/spdlog.h"
#include "spdlog/fmt/ostr.h" // must be included
#include "spdlog/sinks/stdout_sinks.h"

class some_class {
    int code;
};

template<typename OStream>
friend OStream &operator<<(OStream &os, const some_class& to_log)
{
    fmt::format_to(std::ostream_iterator<char>(os), "{:04X}", to_log.code);
    return os;
}

void custom_class_example()
{
    some_class c; c.code = 17;
    auto console = spdlog::stdout_logger_mt("console");
    console->info("custom class with operator<< using fmt: {}..", c);
}

4.自定义格式

spdlog默认格式:
[2014-10-31 23:46:59.678] [my_loggername] [info] Some message
2种方式来设置log模式,建议设置
1.建议:

set_pattern(pattern_string);

2.或使用以下:

set_formatter(std::make_unique<my_custom_formatter>());

3.格式如下:
见下地址

总结

根据介绍,目前在项目中这样使用,用来显示级别,等以后再更改

Log.h

class Log
{
	public:
		static void Init();
		inline static std::shared_ptr<spdlog::logger>& GetCoreLogger() { return s_CoreLogger; }
		inline static std::shared_ptr<spdlog::logger>& GetClientLogger() { return s_ClientLogger; }
	private:
		static std::shared_ptr<spdlog::logger> s_CoreLogger;
		static std::shared_ptr<spdlog::logger> s_ClientLogger;
	};

// Core log macros
#define LOG_TRACE(...)    ::AutoSimulate::Log::GetCoreLogger()->trace(__VA_ARGS__)
#define LOG_INFO(...)     ::AutoSimulate::Log::GetCoreLogger()->info(__VA_ARGS__)
#define LOG_WARN(...)     ::AutoSimulate::Log::GetCoreLogger()->warn(__VA_ARGS__)
#define LOG_ERROR(...)    ::AutoSimulate::Log::GetCoreLogger()->error(__VA_ARGS__)
#define LOG_FATAL(...)    ::AutoSimulate::Log::GetCoreLogger()->fatal(__VA_ARGS__)

Log.cpp(用来自定义日志)

std::shared_ptr<spdlog::logger> Log::s_CoreLogger;
	std::shared_ptr<spdlog::logger> Log::s_ClientLogger;

	void Log::Init()
	{
		spdlog::set_pattern("%^[%T] %n: %v%$");
		s_CoreLogger = spdlog::stdout_color_mt("HAZEL");
		s_CoreLogger->set_level(spdlog::level::trace);

		s_ClientLogger = spdlog::stdout_color_mt("APP");
		s_ClientLogger->set_level(spdlog::level::trace);
	}
 类似资料: