CPP-TOOLBOX
Loading...
Searching...
No Matches
logger.hpp
Go to the documentation of this file.
1#ifndef LOGGER_HPP
2#define LOGGER_HPP
3
4#include <fmt/core.h>
5
6#include <spdlog/spdlog.h>
7#include <spdlog/sinks/stdout_color_sinks.h>
8#include <spdlog/sinks/stdout_sinks.h>
9#include <spdlog/sinks/basic_file_sink.h>
10#include <spdlog/sinks/rotating_file_sink.h>
11
12#include <map>
13#include <string_view>
14#include <sstream>
15
16const std::map<spdlog::level::level_enum, std::string> level_to_string = {
17 {spdlog::level::trace, "trace"}, {spdlog::level::debug, "debug"}, {spdlog::level::info, "info"},
18 {spdlog::level::warn, "warn"}, {spdlog::level::err, "err"}, {spdlog::level::critical, "critical"},
19 {spdlog::level::off, "off"}};
20
21// NOTE: this is replacing everything else.
22class Logger {
23 public:
24 explicit Logger(std::string_view base_name = "section_logger")
25 : section_depth_(0), current_level_(spdlog::level::debug), current_pattern_("[%H:%M:%S.%f] [%^%l%$] %v") {
26 std::string logger_name = std::string(base_name);
27
28 // If logger exists, increment postfix until unique
29 int counter = 1;
30 while (spdlog::get(logger_name) != nullptr) {
31 logger_name = std::string(base_name) + "_" + std::to_string(counter++);
32 }
33
34 auto stdout_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
35 logger_ = std::make_shared<spdlog::logger>(logger_name, stdout_sink);
36 spdlog::register_logger(logger_);
37
38 configure(current_level_, current_pattern_);
39 }
40
41 void remove_all_sinks() { logger_->sinks().clear(); }
42
43 void add_sink(std::shared_ptr<spdlog::sinks::sink> sink) {
44 logger_->sinks().push_back(sink);
45 reapply_formatting(); // <-- ensure new sink matches
46 }
47
48 void add_file_sink(const std::string &file_path, bool truncate = false) {
49 auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(file_path, truncate);
50 add_sink(file_sink);
51 }
52
53 void add_rotating_file_sink(const std::string &file_path, size_t max_size, size_t max_files) {
54 auto rotating_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(file_path, max_size, max_files);
55 add_sink(rotating_sink);
56 }
57
58 void add_stdout_sink(bool color = true) {
59 if (color) {
60 add_sink(std::make_shared<spdlog::sinks::stdout_color_sink_mt>());
61 } else {
62 add_sink(std::make_shared<spdlog::sinks::stdout_sink_mt>());
63 }
64 }
65
66 void configure(spdlog::level::level_enum lvl, std::string_view pattern) {
67 current_level_ = lvl;
68 current_pattern_ = std::string(pattern);
69 reapply_formatting();
70 }
71
72 // ====== Logging core ======
73 // Format-string overload (compile-time checked)
74 template <typename... Args>
75 void log(spdlog::level::level_enum lvl, fmt::format_string<Args...> fmt_str, Args &&...args) {
76 format_and_log(lvl, fmt::format(fmt_str, std::forward<Args>(args)...));
77 }
78
79 // Direct runtime string overload
80 void log(spdlog::level::level_enum lvl, std::string_view msg) { format_and_log(lvl, std::string(msg)); }
81
82 // ====== Convenience wrappers ======
83 template <typename... Args> void trace(fmt::format_string<Args...> fmt_str, Args &&...args) {
84 log(spdlog::level::trace, fmt_str, std::forward<Args>(args)...);
85 }
86 void trace(std::string_view msg) { log(spdlog::level::trace, msg); }
87
88 template <typename... Args> void debug(fmt::format_string<Args...> fmt_str, Args &&...args) {
89 log(spdlog::level::debug, fmt_str, std::forward<Args>(args)...);
90 }
91 void debug(std::string_view msg) { log(spdlog::level::debug, msg); }
92
93 template <typename... Args> void info(fmt::format_string<Args...> fmt_str, Args &&...args) {
94 log(spdlog::level::info, fmt_str, std::forward<Args>(args)...);
95 }
96 void info(std::string_view msg) { log(spdlog::level::info, msg); }
97
98 template <typename... Args> void warn(fmt::format_string<Args...> fmt_str, Args &&...args) {
99 log(spdlog::level::warn, fmt_str, std::forward<Args>(args)...);
100 }
101 void warn(std::string_view msg) { log(spdlog::level::warn, msg); }
102
103 template <typename... Args> void error(fmt::format_string<Args...> fmt_str, Args &&...args) {
104 log(spdlog::level::err, fmt_str, std::forward<Args>(args)...);
105 }
106 void error(std::string_view msg) { log(spdlog::level::err, msg); }
107
108 template <typename... Args> void critical(fmt::format_string<Args...> fmt_str, Args &&...args) {
109 log(spdlog::level::critical, fmt_str, std::forward<Args>(args)...);
110 }
111 void critical(std::string_view msg) { log(spdlog::level::critical, msg); }
112
113 // Sections still require formatting, but you could add overloads too if you want.
114 template <typename... Args> void start_section(fmt::format_string<Args...> fmt_str, Args &&...args) {
115 start_section(spdlog::level::info, fmt_str, std::forward<Args>(args)...);
116 }
117 template <typename... Args>
118 void start_section(spdlog::level::level_enum lvl, fmt::format_string<Args...> fmt_str, Args &&...args) {
119 log(lvl, "=== start {} === {{", fmt::format(fmt_str, std::forward<Args>(args)...));
120 ++section_depth_;
121 }
122 template <typename... Args> void end_section(fmt::format_string<Args...> fmt_str, Args &&...args) {
123 end_section(spdlog::level::info, fmt_str, std::forward<Args>(args)...);
124 }
125 template <typename... Args>
126 void end_section(spdlog::level::level_enum lvl, fmt::format_string<Args...> fmt_str, Args &&...args) {
127 if (section_depth_ > 0)
128 --section_depth_;
129 log(lvl, "=== end {} === }}", fmt::format(fmt_str, std::forward<Args>(args)...));
130 }
131
133 current_level_ = spdlog::level::off;
134 logger_->set_level(current_level_);
135 }
136
137 private:
138 void format_and_log(spdlog::level::level_enum lvl, std::string msg) {
139 // Compute the maximum length of all level names
140 static size_t max_level_len = [] {
141 size_t max_len = 0;
142 for (const auto &p : level_to_string) {
143 if (p.second.size() > max_len) {
144 max_len = p.second.size();
145 }
146 }
147 return max_len;
148 }();
149
150 // Precompute the level padding
151 const std::string &level_str = level_to_string.at(lvl);
152 size_t padding = max_level_len - level_str.size();
153
154 // Prepend section bars
155 std::string prefix;
156 for (int i = 0; i < section_depth_; ++i) {
157 prefix += "| ";
158 }
159
160 // Now split on newlines
161 std::istringstream iss(msg);
162 std::string line;
163 while (std::getline(iss, line)) {
164 std::string full_msg = std::string(padding, ' ') + prefix + line;
165 logger_->log(lvl, full_msg);
166 }
167 }
168
169 void reapply_formatting() {
170 logger_->set_level(current_level_);
171 for (auto &sink : logger_->sinks()) {
172 sink->set_pattern(current_pattern_);
173 }
174 }
175
176 int section_depth_;
177 std::shared_ptr<spdlog::logger> logger_;
178 spdlog::level::level_enum current_level_;
179 std::string current_pattern_;
180};
181
183 public:
184 template <typename... Args>
185 LogSection(Logger &logger, fmt::format_string<Args...> fmt_str, Args &&...args)
186 : logger_(logger), section_name_(fmt::format(fmt_str, std::forward<Args>(args)...)) {
187 logger_.start_section("{}", section_name_);
188 }
189
190 ~LogSection() { logger_.end_section("{}", section_name_); }
191
192 LogSection(const LogSection &) = delete;
193 LogSection &operator=(const LogSection &) = delete;
194
195 private:
196 Logger &logger_;
197 std::string section_name_; // store formatted name here
198};
199
200extern Logger global_logger;
201
202#endif
LogSection(Logger &logger, fmt::format_string< Args... > fmt_str, Args &&...args)
Definition logger.hpp:185
LogSection(const LogSection &)=delete
LogSection & operator=(const LogSection &)=delete
~LogSection()
Definition logger.hpp:190
Definition logger.hpp:22
void disable_all_levels()
Definition logger.hpp:132
void critical(std::string_view msg)
Definition logger.hpp:111
Logger(std::string_view base_name="section_logger")
Definition logger.hpp:24
void add_stdout_sink(bool color=true)
Definition logger.hpp:58
void log(spdlog::level::level_enum lvl, std::string_view msg)
Definition logger.hpp:80
void critical(fmt::format_string< Args... > fmt_str, Args &&...args)
Definition logger.hpp:108
void log(spdlog::level::level_enum lvl, fmt::format_string< Args... > fmt_str, Args &&...args)
Definition logger.hpp:75
void info(std::string_view msg)
Definition logger.hpp:96
void debug(fmt::format_string< Args... > fmt_str, Args &&...args)
Definition logger.hpp:88
void warn(fmt::format_string< Args... > fmt_str, Args &&...args)
Definition logger.hpp:98
void add_file_sink(const std::string &file_path, bool truncate=false)
Definition logger.hpp:48
void add_rotating_file_sink(const std::string &file_path, size_t max_size, size_t max_files)
Definition logger.hpp:53
void start_section(fmt::format_string< Args... > fmt_str, Args &&...args)
Definition logger.hpp:114
void trace(std::string_view msg)
Definition logger.hpp:86
void error(std::string_view msg)
Definition logger.hpp:106
void start_section(spdlog::level::level_enum lvl, fmt::format_string< Args... > fmt_str, Args &&...args)
Definition logger.hpp:118
void trace(fmt::format_string< Args... > fmt_str, Args &&...args)
Definition logger.hpp:83
void warn(std::string_view msg)
Definition logger.hpp:101
void end_section(fmt::format_string< Args... > fmt_str, Args &&...args)
Definition logger.hpp:122
void end_section(spdlog::level::level_enum lvl, fmt::format_string< Args... > fmt_str, Args &&...args)
Definition logger.hpp:126
void error(fmt::format_string< Args... > fmt_str, Args &&...args)
Definition logger.hpp:103
void configure(spdlog::level::level_enum lvl, std::string_view pattern)
Definition logger.hpp:66
void remove_all_sinks()
Definition logger.hpp:41
void info(fmt::format_string< Args... > fmt_str, Args &&...args)
Definition logger.hpp:93
void debug(std::string_view msg)
Definition logger.hpp:91
void add_sink(std::shared_ptr< spdlog::sinks::sink > sink)
Definition logger.hpp:43
@ p
Definition input_state.hpp:42
@ i
Definition input_state.hpp:35
Logger global_logger
Definition logger.cpp:3
const std::map< spdlog::level::level_enum, std::string > level_to_string
Definition logger.hpp:16
Definition hashing.hpp:8