mirror of https://github.com/gabime/spdlog.git
backtrace sink and refactoring
parent
74df115fc1
commit
6b527a50dd
@ -0,0 +1,62 @@
|
||||
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "spdlog/details/log_msg.h"
|
||||
#include "spdlog/fmt/bundled/core.h"
|
||||
|
||||
namespace spdlog {
|
||||
namespace details {
|
||||
|
||||
// regular log_msgs only holds string_views to stack data - so the cannot be stored for later use.
|
||||
// this one can, since it contains and owns the payload buffer.
|
||||
struct log_msg_buffer : log_msg
|
||||
{
|
||||
fmt::basic_memory_buffer<char, 40> loggername_buf;
|
||||
fmt::basic_memory_buffer<char, 200> payload_buf;
|
||||
log_msg_buffer() = default;
|
||||
|
||||
log_msg_buffer(const log_msg &orig_msg): log_msg(orig_msg)
|
||||
{
|
||||
update_buffers();
|
||||
}
|
||||
|
||||
log_msg_buffer(const log_msg_buffer& other):log_msg(other)
|
||||
{
|
||||
update_buffers();
|
||||
}
|
||||
|
||||
log_msg_buffer(const log_msg_buffer&& other):log_msg(std::move(other))
|
||||
{
|
||||
update_buffers();
|
||||
}
|
||||
|
||||
log_msg_buffer& operator=(log_msg_buffer &other) SPDLOG_NOEXCEPT
|
||||
{
|
||||
*static_cast<log_msg*>(this) = other;
|
||||
update_buffers();
|
||||
return *this;
|
||||
}
|
||||
|
||||
log_msg_buffer& operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT
|
||||
{
|
||||
*static_cast<log_msg*>(this) = std::move(other);
|
||||
update_buffers();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void update_buffers() SPDLOG_NOEXCEPT
|
||||
{
|
||||
loggername_buf.clear();
|
||||
loggername_buf.append(logger_name.data(), logger_name.data() + logger_name.size());
|
||||
logger_name = string_view_t{loggername_buf.data(), loggername_buf.size()};
|
||||
|
||||
payload_buf.clear();
|
||||
payload_buf.append(payload.data(),payload.data() + payload.size());
|
||||
payload = string_view_t{payload_buf.data(), payload_buf.size()};
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "dist_sink.h"
|
||||
#include "spdlog/details/null_mutex.h"
|
||||
#include "spdlog/details/log_msg.h"
|
||||
#include "spdlog/details/log_msg_buffer.h"
|
||||
#include "spdlog/details/circular_q.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
|
||||
// Store log messages in circular buffer
|
||||
// If it encounters a message with high enough level, it will send all pervious message to its child sinks
|
||||
// Useful for storing debug data in case of error/warning happens
|
||||
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// #include "spdlog/spdlog.h"
|
||||
// #include "spdlog/sinks/backtrace_sink.h
|
||||
//
|
||||
// int main() {
|
||||
// auto backtrace_sink = std::make_shared<backtrace_sink>();
|
||||
// backtrace_sink ->add_sink(std::make_shared<stdout_color_sink_mt>());
|
||||
// spdlog::logger l("logger", backtrace_sink);
|
||||
// logger.set_level(spdlog::level::trace);
|
||||
// l.trace("Hello");
|
||||
// l.debug("Hello");
|
||||
// l.info("Hello");
|
||||
// l.warn("This will trigger the log of all prev messages in the queue");
|
||||
// }
|
||||
|
||||
|
||||
namespace spdlog {
|
||||
namespace sinks {
|
||||
template<typename Mutex>
|
||||
class backtrace_sink : public dist_sink<Mutex>
|
||||
{
|
||||
public:
|
||||
explicit backtrace_sink(level::level_enum trigger_level = spdlog::level::warn, size_t n_messages = 32)
|
||||
: trigger_level_{trigger_level}, traceback_msgs_{n_messages}
|
||||
{}
|
||||
|
||||
protected:
|
||||
level::level_enum trigger_level_;
|
||||
|
||||
details::circular_q<details::log_msg_buffer> traceback_msgs_;
|
||||
|
||||
// if current message is high enough, trigger a backtrace log,
|
||||
// otherwise save the message in the queue for future trigger.
|
||||
void sink_it_(const details::log_msg &msg) override
|
||||
{
|
||||
if(msg.level < trigger_level_)
|
||||
{
|
||||
traceback_msgs_.push_back(details::log_msg_buffer(msg));
|
||||
}
|
||||
if(msg.level > level::debug)
|
||||
{
|
||||
dist_sink<Mutex>::sink_it_(msg);
|
||||
}
|
||||
if(msg.level >= trigger_level_)
|
||||
{
|
||||
log_backtrace_(msg.logger_name);
|
||||
}
|
||||
}
|
||||
|
||||
void log_backtrace_(const string_view_t& logger_name)
|
||||
{
|
||||
if(traceback_msgs_.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
dist_sink<Mutex>::sink_it_(details::log_msg{
|
||||
logger_name,level::info,"********************* [Backtrace Start] *********************"});
|
||||
|
||||
do
|
||||
{
|
||||
details::log_msg_buffer popped;
|
||||
traceback_msgs_.pop_front(popped);
|
||||
dist_sink<Mutex>::sink_it_(popped);
|
||||
}
|
||||
while (!traceback_msgs_.empty());
|
||||
|
||||
dist_sink<Mutex>::sink_it_(details::log_msg{
|
||||
logger_name,level::info,"********************* [Backtrace End] ***********************"});
|
||||
}
|
||||
};
|
||||
|
||||
using backtrace_sink_mt = backtrace_sink<std::mutex>;
|
||||
using backtrace_sink_st = backtrace_sink<details::null_mutex>;
|
||||
|
||||
} // namespace sinks
|
||||
} // namespace spdlog
|
Loading…
Reference in New Issue