每个Logger都包含一个数组,数组里是std::shared_ptr
//Create and return a shared_ptr to a multithreaded console logger.
#include "spdlog/sinks/stdout_color_sinks.h"
auto console = spdlog::stdout_color_mt("some_unique_name");
这里会创建console logger,并加入到spdlog的全局注册器里,使用some_unique_name作为id,并返回shared_ptr
通过spdlog::get()方法获取一个logger。注意这里是加锁实现的,最好不好频繁调用,比较好的方法是在构造时获取。手动创建的logger不会自动注册,需要主动调用register_logger()
spd::register_logger(my_logger)
//Create rotating file multi-threaded logger
#include "spdlog/sinks/rotating_file_sink.h"
auto file_logger = spdlog::rotating_logger_mt("file_logger", "logs/mylogfile", 1048576 * 5, 3);
...
auto same_logger= spdlog::get("file_logger");
#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");
// alternatively:
// auto async_file = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt");
}
spdlog使用共享的全局线程池和专用的消息队列实现异步logging。 创建可变数目的预先分配slots的消息队列,可以使用spdlog::init_thread_pool(queue_size, backing_threads_count)
来修改线程数目和队列大小。当尝试log一条消息时,如果队列满了,调用者会block直到有一个slot可以使用(默认行为)。当logger构造函数传参async_overflow_policy==overrun_oldest时,不会block,而是在队列里使用新的日志消息覆盖最早的日志消息
auto sink = std::make_shared<spdlog::sink::stdout_sink_mt>();
auto my_logger = std::make_shared<spdlog::logger>("mylogger", sink);
std::vector<spdlog::sink_ptr> sinks;
sinks.push_back(std::make_shared<spdlog::sinks::stdout_sink_st>());
sinks.push_back(std::make_shared<spdlog::sinks::daily_file_sink_st>("log_file", 23, 59));
auto logger = std::make_shared<spdlog::logger>("mylogger", begin(sinks), end(sinks));
spdlog::register_logger(logger);
auto sharedFileSink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("fileName.txt");
auto firstLogger = std::make_shared<spdlog::logger>("first", sharedFileSink);
auto secondLogger = std::make_unique<spdlog::logger>("second", sharedFileSink);
日志格式可以使用
(1) set_pattern(pattern_string)
(2) 实现formatter的接口,然后调用set_formatter(std::make_unique
spdlog::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***");
some_logger->set_pattern(">>>>>>>>> %H:%M:%S %z %v <<<<<<<<<");
some_logger->sinks()[0]->set_pattern(">>>>>>>>> %H:%M:%S %z %v <<<<<<<<<");
some_logger->sinks()[1]->set_pattern("..");
flag | meaning | example |
---|---|---|
%v |
The actual text to log | "some user text" |
%t |
Thread id | "1232" |
%P |
Process id | "3456" |
%n |
Logger‘s name | "some logger name" |
%l |
The log level of the message | "debug", "info", etc |
%L |
Short log level of the message | "D", "I", etc |
%a |
Abbreviated weekday name | "Thu" |
%A |
Full weekday name | "Thursday" |
%b |
Abbreviated month name | "Aug" |
%B |
Full month name | "August" |
%c |
Date and time representation | "Thu Aug 23 15:35:46 2014" |
%C |
Year in 2 digits | "14" |
%Y |
Year in 4 digits | "2014" |
%D or %x |
Short MM/DD/YY date | "08/23/14" |
%m |
Month 01-12 | "11" |
%d |
Day of month 01-31 | "29" |
%H |
Hours in 24 format 00-23 | "23" |
%I |
Hours in 12 format 01-12 | "11" |
%M |
Minutes 00-59 | "59" |
%S |
Seconds 00-59 | "58" |
%e |
Millisecond part of the current second 000-999 | "678" |
%f |
Microsecond part of the current second 000000-999999 | "056789" |
%F |
Nanosecond part of the current second 000000000-999999999 | "256789123" |
%p |
AM/PM | "AM" |
%r |
12 hour clock | "02:55:02 pm" |
%R |
24-hour HH:MM time, equivalent to %H:%M | "23:55" |
%T or %X |
ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S | "23:55:59" |
%z |
ISO 8601 offset from UTC in timezone ([+/-]HH:MM) | "+02:00" |
%E |
Seconds since the epoch | "1528834770" |
%% |
The % sign | "%" |
%+ |
spdlog‘s default format | "[2014-10-31 23:46:59.678] [mylogger] [info] Some message" |
%^ |
start color range (can be used only once) | "[mylogger] [info(green)] Some message" |
%$ |
end color range (for example %^[+++]%$ %v) (can be used only once) | [+++] Some message |
%@ |
Source file and line (use SPDLOG_TRACE(..), SPDLOG_INFO(...) etc. instead of spdlog::trace(...) | my_file.cpp:123 |
%s |
Basename of the source file (use SPDLOG_TRACE(..), SPDLOG_INFO(...) etc.) | my_file.cpp |
%g |
Full or relative path of the source file as appears in the __FILE__ macro (use SPDLOG_TRACE(..), SPDLOG_INFO(...) etc.) |
/some/dir/my_file.cpp |
%# |
Source line (use SPDLOG_TRACE(..), SPDLOG_INFO(...) etc.) | 123 |
%! |
Source function (use SPDLOG_TRACE(..), SPDLOG_INFO(...) etc. see tweakme for pretty-print) | my_func |
%o |
Elapsed time in milliseconds since previous message | 456 |
%i |
Elapsed time in microseconds since previous message | 456 |
%u |
Elapsed time in nanoseconds since previous message | 11456 |
%O |
Elapsed time in seconds since previous message | 4 |
#include "spdlog/sinks/base_sink.h"
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;
spdlog::sinks::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的引用,然后添加sink
inline std::vector<spdlog::sink_ptr> &spdlog::logger::sinks()
{
return sinks_;
}
spdlog::get("myExistingLogger")->sinks().push_back(myNewSink);
spdlog使用全局的注册器保存所有的logger.这是为了能够在工程的任何地方找到此log,而不需要传递这个logger
spdlog::get("logger1")->info("hello");
..
..
some other source file..
..
auto l = spdlog::get("logger1");
l->info("hello again");
正常情况下回自动注册,为了注册手动创建的logger,需要调用spdlog::register_logger(some_logger);
如果存在相同名字的logger,会抛出异常
使用drop()移除
spdlog::drop("logger_name");
//or remove them all
spdlog::drop_all()
创建异步日志方法
(1)spdlog::async_factory模版参数
#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");
}
(2) 使用spdlog::create_async
auto async_file = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt");
(3)使用spdlog::create_async_nb
auto async_file = spdlog::create_async_nb<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt");
(4)直接创建并使用全局线程池
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);
(5)直接创建并使用自定义的线程池
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);
auto logger = spdlog::create_async_nb<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt");
// or directly:
auto logger = std::make_shared<async_logger>("as", test_sink, spdlog::thread_pool(), spdlog::async_overflow_policy::overrun_oldest);
默认会创建全局的线程池,queue size为8192,1个工作线程用于服务所有的异步logger。这意味着创建和销毁异步日志器是很轻量级的,因为他们不会持有或创建任何后台线程或者队列,而是由共享的线程池对象。所有队列是提前申请好空间的,可以reset
spdlog::init_thread_pool(queue_size, n_threads);
注意到这会销毁原来的全局线程池而创建新的线程池,使用旧的线程池的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); // create pool with queue of 1024 slots and 4 backing threads
auto logger2 = std::make_shared<async_logger>("as2", some_sink, tp2, async_overflow_policy::block);
使用单个work线程的线程池可以保证顺序,如果是多个work线程,无法保证日志顺序
当在windows平台使用异步日志时,应该在main函数退出时调用spdlog::shutdown()
为了较好的性能,默认使用libc的BUFSIZ,可以使自定义的flush策略
my_logger->flush_on(spdlog::level::err);
spdlog::flush_every(std::chrono::seconds(5));
spdlog::set_default_logger(some_other_logger);
spdlog::info("Use the new default logger");
为了性能,log不会立即flush到文件里,等到BUFSIZ bytes的日志写到log里才一次性写入
为了能够强制flush,可以使用以下方法
my_logger->flush(); // flush now
my_logger->flush_on(spdlog::level::info); // auto flush when "info" or higher message is logged
spdlog::flush_on(spdlog::level::info); // auto flush when "info" or higher message is logged on all loggers
spdlog::flush_every(std::chrono::seconds(5)); // flush periodically every 5 seconds (caution: must be _mt logger)
通过在包含spdlog.h之前定义SPDLOG_ACTIVE_LEVEL可以移除所有编译时的debug语句
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO // All DEBUG/TRACE statements will be removed by the pre-processor
#include "spdlog/spdlog.h"
...
SPDLOG_DEBUG("debug message to default logger"); // removed at compile time
SPDLOG_LOGGER_TRACE(my_logger, "trace message"); // removed at compile time
SPDLOG_INFO("info message to default logger"); // included
在main函数的结尾处调用
spdlog::shutdown();
_mt后缀是线程安全的版本: auto logger = spdlog::basic_logger_mt(...);
_st是单线程的logger: auto logger = spdlog::basic_logger_st(...)
原文:https://www.cnblogs.com/yanke/p/3328402dd2e86456cd35cfcd8ec57198.html