backtrace sink and refactoring
This commit is contained in:
		@@ -4,16 +4,18 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "spdlog/common.h"
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
namespace spdlog {
 | 
			
		||||
namespace details {
 | 
			
		||||
struct log_msg
 | 
			
		||||
{
 | 
			
		||||
    log_msg() = default;
 | 
			
		||||
    log_msg(source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg);
 | 
			
		||||
    log_msg(string_view_t logger_name, level::level_enum lvl, string_view_t msg);
 | 
			
		||||
    log_msg(const log_msg &other) = default;
 | 
			
		||||
 | 
			
		||||
    const string_view_t logger_name;
 | 
			
		||||
    string_view_t logger_name;
 | 
			
		||||
    level::level_enum level{level::off};
 | 
			
		||||
    log_clock::time_point time;
 | 
			
		||||
    size_t thread_id{0};
 | 
			
		||||
@@ -23,7 +25,7 @@ struct log_msg
 | 
			
		||||
    mutable size_t color_range_end{0};
 | 
			
		||||
 | 
			
		||||
    source_loc source;
 | 
			
		||||
    const string_view_t payload;
 | 
			
		||||
    string_view_t payload;
 | 
			
		||||
};
 | 
			
		||||
} // namespace details
 | 
			
		||||
} // namespace spdlog
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										62
									
								
								include/spdlog/details/log_msg_buffer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								include/spdlog/details/log_msg_buffer.h
									
									
									
									
									
										Normal file
									
								
							@@ -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()};
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
@@ -100,8 +100,7 @@ bool SPDLOG_INLINE thread_pool::process_next_msg_()
 | 
			
		||||
    {
 | 
			
		||||
    case async_msg_type::log:
 | 
			
		||||
    {
 | 
			
		||||
        auto msg = incoming_async_msg.to_log_msg();
 | 
			
		||||
        incoming_async_msg.worker_ptr->backend_log_(msg);
 | 
			
		||||
        incoming_async_msg.worker_ptr->backend_log_(incoming_async_msg);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    case async_msg_type::flush:
 | 
			
		||||
 
 | 
			
		||||
@@ -3,10 +3,11 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "spdlog/details/log_msg.h"
 | 
			
		||||
#include "spdlog/details/log_msg_buffer.h"
 | 
			
		||||
#include "spdlog/details/mpmc_blocking_q.h"
 | 
			
		||||
#include "spdlog/details/os.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <chrono>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <thread>
 | 
			
		||||
@@ -27,17 +28,12 @@ enum class async_msg_type
 | 
			
		||||
    terminate
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#include "spdlog/details/log_msg_buffer.h"
 | 
			
		||||
// Async msg to move to/from the queue
 | 
			
		||||
// Movable only. should never be copied
 | 
			
		||||
struct async_msg
 | 
			
		||||
struct async_msg:log_msg_buffer
 | 
			
		||||
{
 | 
			
		||||
    async_msg_type msg_type {async_msg_type::log};
 | 
			
		||||
    level::level_enum level {level::info};
 | 
			
		||||
    log_clock::time_point time;
 | 
			
		||||
    size_t thread_id {0};
 | 
			
		||||
    fmt::basic_memory_buffer<char, 176> raw;
 | 
			
		||||
 | 
			
		||||
    source_loc source;
 | 
			
		||||
    async_logger_ptr worker_ptr;
 | 
			
		||||
 | 
			
		||||
    async_msg() = default;
 | 
			
		||||
@@ -49,51 +45,35 @@ struct async_msg
 | 
			
		||||
// support for vs2013 move
 | 
			
		||||
#if defined(_MSC_VER) && _MSC_VER <= 1800
 | 
			
		||||
    async_msg(async_msg &&other)
 | 
			
		||||
        : msg_type(other.msg_type)
 | 
			
		||||
        , level(other.level)
 | 
			
		||||
        , time(other.time)
 | 
			
		||||
        , thread_id(other.thread_id)
 | 
			
		||||
        , raw(move(other.raw))
 | 
			
		||||
        , msg_id(other.msg_id)
 | 
			
		||||
        , source(other.source)
 | 
			
		||||
        : log_msg_buffer(std::move(other))
 | 
			
		||||
        , msg_type(other.msg_type)
 | 
			
		||||
        , worker_ptr(std::move(other.worker_ptr))
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    async_msg &operator=(async_msg &&other)
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        *static_cast<log_msg_buffer*>(this) = std::move(other);
 | 
			
		||||
        msg_type = other.msg_type;
 | 
			
		||||
        level = other.level;
 | 
			
		||||
        time = other.time;
 | 
			
		||||
        thread_id = other.thread_id;
 | 
			
		||||
        raw = std::move(other.raw);
 | 
			
		||||
        msg_id = other.msg_id;
 | 
			
		||||
        source = other.source;
 | 
			
		||||
        worker_ptr = std::move(other.worker_ptr);
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
#else // (_MSC_VER) && _MSC_VER <= 1800
 | 
			
		||||
    async_msg(async_msg &&) = default;
 | 
			
		||||
    async_msg &operator=(async_msg &&) = default;
 | 
			
		||||
    async_msg(async_msg &&) SPDLOG_NOEXCEPT = default;
 | 
			
		||||
    async_msg &operator=(async_msg &&) SPDLOG_NOEXCEPT = default;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    // construct from log_msg with given type
 | 
			
		||||
    async_msg(async_logger_ptr &&worker, async_msg_type the_type, details::log_msg &m)
 | 
			
		||||
        : msg_type(the_type)
 | 
			
		||||
        , level(m.level)
 | 
			
		||||
        , time(m.time)
 | 
			
		||||
        , thread_id(m.thread_id)
 | 
			
		||||
        , source(m.source)
 | 
			
		||||
        : log_msg_buffer(m)
 | 
			
		||||
        , msg_type(the_type)
 | 
			
		||||
        , worker_ptr(std::move(worker))
 | 
			
		||||
    {
 | 
			
		||||
        raw.append(m.payload.data(), m.payload.data() + m.payload.size());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async_msg(async_logger_ptr &&worker, async_msg_type the_type)
 | 
			
		||||
        : msg_type(the_type)
 | 
			
		||||
        , level(level::off)
 | 
			
		||||
        , time()
 | 
			
		||||
        , thread_id(0)
 | 
			
		||||
        , source()
 | 
			
		||||
        : log_msg_buffer()
 | 
			
		||||
        , msg_type(the_type)
 | 
			
		||||
        , worker_ptr(std::move(worker))
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
@@ -101,17 +81,6 @@ struct async_msg
 | 
			
		||||
        : async_msg(nullptr, the_type)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    // copy into log_msg
 | 
			
		||||
    log_msg to_log_msg()
 | 
			
		||||
    {
 | 
			
		||||
        log_msg msg(string_view_t(worker_ptr->name()), level, string_view_t(raw.data(), raw.size()));
 | 
			
		||||
        msg.time = time;
 | 
			
		||||
        msg.thread_id = thread_id;
 | 
			
		||||
        msg.source = source;
 | 
			
		||||
        msg.color_range_start = 0;
 | 
			
		||||
        msg.color_range_end = 0;
 | 
			
		||||
        return msg;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class thread_pool
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										98
									
								
								include/spdlog/sinks/backtrace-sink.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								include/spdlog/sinks/backtrace-sink.h
									
									
									
									
									
										Normal file
									
								
							@@ -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
 | 
			
		||||
		Reference in New Issue
	
	Block a user