2#ifndef LIBSBX_UTILITY_LOGGER_HPP_
3#define LIBSBX_UTILITY_LOGGER_HPP_
11#include <fmt/format.h>
13#include <spdlog/logger.h>
14#include <spdlog/sinks/stdout_color_sinks.h>
15#include <spdlog/sinks/basic_file_sink.h>
16#include <spdlog/sinks/base_sink.h>
18#include <libsbx/utility/target.hpp>
19#include <libsbx/utility/string_literal.hpp>
21namespace sbx::utility {
25template<
typename Mutex>
28 using base = spdlog::sinks::base_sink<Mutex>;
34 spdlog::level::level_enum level;
38 : _max_lines{max_lines} {}
40 [[nodiscard]]
auto lines() -> std::vector<log_line> {
41 auto lock = std::lock_guard<Mutex>{base::mutex_};
43 return {_lines.begin(), _lines.end()};
47 std::lock_guard<Mutex> lock(base::mutex_);
54 void sink_it_(
const spdlog::details::log_msg& msg)
override {
55 auto formatted = spdlog::memory_buf_t{};
56 base::formatter_->format(msg, formatted);
58 auto lock = std::lock_guard<Mutex>{base::mutex_};
59 _lines.emplace_back(fmt::to_string(formatted), msg.level);
61 if (_lines.size() > _max_lines) {
66 void flush_()
override {
72 std::size_t _max_lines;
73 std::deque<log_line> _lines;
77using ring_buffer_sink_mt = ring_buffer_sink<std::mutex>;
78using ring_buffer_sink_st = ring_buffer_sink<spdlog::details::null_mutex>;
82 static auto create_logger() -> spdlog::logger {
83 auto sinks = std::vector<std::shared_ptr<spdlog::sinks::sink>>{};
85 sinks.push_back(std::make_shared<spdlog::sinks::basic_file_sink_st>(
"./demo/logs/sbx.log",
true));
87 if constexpr (utility::build_configuration_v == utility::build_configuration::debug) {
88 sinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_st>());
91 sink = std::make_shared<ring_buffer_sink_st>();
93 sinks.push_back(sink);
95 auto logger = spdlog::logger{
"logger", std::begin(sinks), std::end(sinks)};
97 logger.set_pattern(
"[%Y-%m-%d %H:%M:%S] [%^%l%$] %v");
99 if constexpr (build_configuration_v == build_configuration::debug) {
100 logger.set_level(spdlog::level::trace);
102 logger.set_level(spdlog::level::info);
108 inline static auto sink = std::shared_ptr<ring_buffer_sink_st>{};
109 inline static auto logger = create_logger();
113inline auto instance() -> spdlog::logger& {
114 return logger_instance::logger;
117inline auto sink() -> std::shared_ptr<ring_buffer_sink_st>& {
118 return logger_instance::sink;
123template<
string_literal Tag>
128 template<
typename... Args>
129 using format_string_type = spdlog::format_string_t<Args...>;
135 template<
typename... Args>
136 static auto trace(format_string_type<Args...> format, Args&&... args) ->
void {
137 detail::instance().trace(
"[{}] : {}", Tag, fmt::format(format, std::forward<Args>(args)...));
140 template<
typename Type>
141 static auto trace(
const Type& value) ->
void {
142 detail::instance().trace(
"[{}] : {}", Tag, value);
145 template<
typename... Args>
146 static auto debug(format_string_type<Args...> format, Args&&... args) ->
void {
147 detail::instance().debug(
"[{}] : {}", Tag, fmt::format(format, std::forward<Args>(args)...));
150 template<
typename Type>
151 static auto debug(
const Type& value) ->
void {
152 detail::instance().debug(
"[{}] : {}", Tag, value);
155 template<
typename... Args>
156 static auto info(format_string_type<Args...> format, Args&&... args) ->
void {
157 detail::instance().info(
"[{}] : {}", Tag, fmt::format(format, std::forward<Args>(args)...));
160 template<
typename Type>
161 static auto info(
const Type& value) ->
void {
162 detail::instance().info(
"[{}] : {}", Tag, value);
165 template<
typename... Args>
166 static auto warn(format_string_type<Args...> format, Args&&... args) ->
void {
167 detail::instance().warn(
"[{}] : {}", Tag, fmt::format(format, std::forward<Args>(args)...));
170 template<
typename Type>
171 static auto warn(
const Type& value) ->
void {
172 detail::instance().warn(
"[{}] : {}", Tag, value);
175 template<
typename... Args>
176 static auto error(format_string_type<Args...> format, Args&&... args) ->
void {
177 detail::instance().error(
"[{}] : {}", Tag, fmt::format(format, std::forward<Args>(args)...));
180 template<
typename Type>
181 static auto error(
const Type& value) ->
void {
182 detail::instance().error(
"[{}] : {}", Tag, value);
185 template<
typename... Args>
186 static auto critical(format_string_type<Args...> format, Args&&... args) ->
void {
187 detail::instance().critical(
"[{}] : {}", Tag, fmt::format(format, std::forward<Args>(args)...));
190 template<
typename Type>
191 static auto critical(
const Type& value) ->
void {
192 detail::instance().critical(
"[{}] : {}", Tag, value);
200template<
typename Type>
201requires (std::is_enum_v<Type>)
202struct fmt::formatter<Type> :
public fmt::formatter<std::underlying_type_t<Type>> {
204 using base_type = fmt::formatter<std::underlying_type_t<Type>>;
206 template<
typename FormatContext>
207 auto format(
const Type& value, FormatContext& context)
const ->
decltype(
auto) {
208 return base_type::format(
static_cast<std::underlying_type_t<Type>
>(value), context);
214template<
typename Type>
215struct fmt::formatter<std::optional<Type>> :
public fmt::formatter<Type> {
219 template<
typename FormatContext>
220 auto format(
const std::optional<Type>& value, FormatContext& context) ->
decltype(
auto) {
222 return base_type::format(*value, context);
225 return fmt::format_to(context.out(),
"[empty optional]");
231struct fmt::formatter<std::filesystem::path> :
public fmt::formatter<std::filesystem::path::string_type> {
233 using base_type = fmt::formatter<std::filesystem::path::string_type>;
235 template<
typename FormatContext>
236 auto format(
const std::filesystem::path& value, FormatContext& context) ->
decltype(
auto) {
237 return fmt::format_to(context.out(),
"{}", value.string());
Definition: logger.hpp:26
Definition: logger.hpp:124
Definition: logger.hpp:80
Definition: logger.hpp:32