Skip to content

Instantly share code, notes, and snippets.

@lingxd
Forked from EvanLyu732/enableNetworkSinker.cmake
Last active October 17, 2022 08:32
Show Gist options
  • Save lingxd/bf752210edfb3dbe8f24c5e28114c0c0 to your computer and use it in GitHub Desktop.
Save lingxd/bf752210edfb3dbe8f24c5e28114c0c0 to your computer and use it in GitHub Desktop.
spdlog.hpp.in corresponding cmake macro
# Parameter:
# LOG MODULE: folder name
# BIND_PORT: network sinker register port
# SEND_PORT: network sinker publish port
macro(enable_logging LOG_MODULE BIND_PORT SEND_PORT)
if(NOT spdlog_FOUND)
find_package(spdlog REQUIRED)
endif()
if(NOT Boost_FOUND)
find_package(Boost REQUIRED COMPONENTS system)
endif()
set(LOG_MODULE LOG_MODULE)
set(BIND_PORT BIND_PORT)
set(SEND_PORT SEND_PORT)
# replace this line with your spdlog.hpp.in location. example
configure_file(${CMAKE_SOURCE_DIR}/include/spdlog.hpp.in ${CMAKE_SOURCE_DIR}/include/spdlog.hpp @ONLY)
endmacro()
#pragma once
/**
* Goal is to provided easy to use wrapping api, for user.
*
* Mode1: color sinker, auto rotate file location
* Mode2: web sinker injection
* Mode3: stacktrace mode
**/
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE
#include <spdlog/async.h>
#include <spdlog/common.h>
#include <spdlog/details/log_msg.h>
#include <spdlog/formatter.h>
#include <spdlog/pattern_formatter.h>
#include <spdlog/sinks/ansicolor_sink.h>
#include <spdlog/sinks/base_sink.h>
#include <spdlog/sinks/rotating_file_sink.h>
#include <spdlog/spdlog.h>
#include <array>
#include <boost/asio.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/udp.hpp>
#include <boost/system/error_code.hpp>
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <exception>
#include <iostream>
#include <memory>
#include <mutex>
#include <ostream>
#include <string>
#include <string_view>
#include <thread>
#include <utility>
#define LOG_MODULE "@LOG_MODULE@"
#define LOG_FILES_DIRS "logs/@LOG_MODULE@.log"
#define LOGGER_NAME "@LOG_MODULE@/_logger"
namespace ud::tools::log {
inline static bool is_init{false};
struct Color {
// YELLO FOR WARNING LEVEL
static inline constexpr std::string_view yellow = "\x1B[38;5;226m";
// RED FOR ERROR LEVEL
static inline constexpr std::string_view red = "\x1B[38;5;196m";
// GREEN FOR INFO LEVEL
static inline constexpr std::string_view green = "\x1B[38;5;118m";
// WHITE FOR DEBUG LEVEL
static inline constexpr std::string_view white = "\x1B[38;5;231m";
// RESET
static inline constexpr std::string_view reset = "\033[0m";
};
struct Attributes {
// spdlog pattern
static inline constexpr char* pattern = "%^|%Y/%D/%H:%M:%S|:|%l|:|%s:%#| %v %$";
// thread pool nums
static int inline thread_pool_nums = 2;
// thread pool size, 8192 by default
static int inline thread_pool_size = 8192;
// logger backtrace nums
static int inline backtrace_nums = 32;
};
template<typename Mutex>
struct networksink : public spdlog::sinks::base_sink<Mutex> {
networksink(int bind_port, int send_port = 6999) : send_ep_(::boost::asio::ip::udp::endpoint(::boost::asio::ip::udp::v4(), send_port)),
service_(::boost::asio::io_service()),
socket_(::boost::asio::ip::udp::socket(service_, ::boost::asio::ip::udp::endpoint(::boost::asio::ip::udp::v4(), bind_port))) {
std::lock_guard<std::mutex> lock(Mutex);
this->formatter_ = std::make_unique<spdlog::pattern_formatter>(Attributes::pattern);
initialColorLevel();
service_.run();
}
~networksink() {
socket_.close();
}
void initialColorLevel() {
colors_[spdlog::level::info] = Color::green;
colors_[spdlog::level::warn] = Color::yellow;
colors_[spdlog::level::err] = Color::red;
colors_[spdlog::level::debug] = Color::white;
colors_[spdlog::level::off] = Color::reset;
}
protected:
void sink_it_(const ::spdlog::details::log_msg& msg) override {
::spdlog::memory_buf_t formatted;
msg.color_range_start = 0;
msg.color_range_end = 0;
this->formatter_->format(msg, formatted);
auto sink_color = colors_[static_cast<size_t>(msg.level)];
if (msg.color_range_end > msg.color_range_start) {
print_range_(formatted, 0, msg.color_range_start);
print_ccode_(sink_color);
print_range_(formatted, msg.color_range_start, msg.color_range_end);
print_ccode_(Color::reset.data());
print_range_(formatted, msg.color_range_end, formatted.size());
} else// no color
{
print_range_(formatted, 0, formatted.size());
}
socket_.async_send_to(::boost::asio::buffer(sink_color.data(), sink_color.size()),
send_ep_,
[this](::boost::system::error_code ec, std::size_t length) {
if (ec) {
return;
}
});
socket_.async_send_to(::boost::asio::buffer(formatted.data(), formatted.size()),
send_ep_,
[this](::boost::system::error_code ec, std::size_t length) {
if (ec) {
return;
}
});
}
void flush_() override {
}
private:
void print_range_(const ::spdlog::memory_buf_t& formatted, size_t start, size_t end) {
fwrite(formatted.data() + start, sizeof(char), (end - start), stdout);
}
void print_ccode_(const std::string& color_code) {
fwrite(color_code.data(), sizeof(char), color_code.size(), stdout);
}
private:
std::array<std::string, spdlog::level::n_levels> colors_;
::boost::asio::io_service service_;
::boost::asio::ip::udp::socket socket_;
::boost::asio::ip::udp::endpoint send_ep_;
};
void initial_logger() {
if (!is_init) {
spdlog::init_thread_pool(Attributes::thread_pool_size, Attributes::thread_pool_nums);
using networksink_mt = networksink<std::mutex>;
auto network_sinks = std::make_shared<networksink_mt>(@BIND_PORT @, @SEND_PORT @);
auto rotating_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(LOG_FILES_DIRS, 1024 * 1024 * 10, 3);
std::vector<spdlog::sink_ptr> sinks{network_sinks, rotating_sink};
auto logger = std::make_shared<spdlog::async_logger>(LOGGER_NAME, sinks.begin(), sinks.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block);
spdlog::register_logger(logger);
is_init = true;
}
}
}// namespace ud::tools::log
#define LOG_INFO(...) \
if (ud::tools::log::is_init) { \
auto logger = spdlog::get(LOGGER_NAME); \
SPDLOG_LOGGER_INFO(logger, __VA_ARGS__); \
} else { \
initial_logger(); \
}
#define LOG_WARN(...) \
if (ud::tools::log::is_init) { \
auto logger = spdlog::get(LOGGER_NAME); \
SPDLOG_LOGGER_WARN(logger, __VA_ARGS__); \
} else { \
initial_logger(); \
}
#define LOG_ERR(...) \
if (ud::tools::log::is_init) { \
auto logger = spdlog::get(LOGGER_NAME); \
SPDLOG_LOGGER_ERROR(logger, __VA_ARGS__); \
} else { \
initial_logger(); \
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment