ASW Lib
A.D.S. Games SDL Wrapper Library. A library targeted at Allegro4 users who want to switch to SDL3 and use modern c++.
Loading...
Searching...
No Matches
log.cpp
Go to the documentation of this file.
1#include "./asw/modules/log.h"
2
3#include <array>
4#include <chrono>
5#include <ctime>
6
7#ifdef __EMSCRIPTEN__
8#include <emscripten.h>
9#endif
10
11namespace {
13std::ostream* output = &std::cerr;
14
16{
17 using enum asw::log::Level;
18
19 switch (level) {
20 case Debug:
21 return "DEBUG";
22 case Info:
23 return "INFO ";
24 case Warn:
25 return "WARN ";
26 case Error:
27 return "ERROR";
28 }
29 return "?????";
30}
31
33enum class AnsiCode : int {
34 Reset = 0,
35 BoldOn = 1,
36 Faint = 2,
37 ItalicOn = 3,
38 UnderlineOn = 4,
39 SlowBlinkOn = 5,
40 RapidBlinkOn = 6,
42 ConcealOn = 8,
43 CrossedOutOn = 9,
44 BoldOff = 22,
45 ItalicOff = 23,
46 UnderlineOff = 24,
47 BlinkOff = 25,
48 ReverseVideoOff = 27,
49 ConcealOff = 28,
50 CrossedOutOff = 29,
51
52 // Standard text colors
53 TextBlack = 30,
54 TextRed = 31,
55 TextGreen = 32,
56 TextYellow = 33,
57 TextBlue = 34,
58 TextMagenta = 35,
59 TextCyan = 36,
60 TextWhite = 37,
61 TextDefault = 39,
62
63 // Background color
64 BgBlack = 40,
65 BgRed = 41,
66 BgGreen = 42,
67 BgYellow = 43,
68 BgBlue = 44,
69 BgMagenta = 45,
70 BgCyan = 46,
71 BgWhite = 47,
72 BgDefault = 49,
73
74 // Bright (high-intensity) text colors
75 TextBrightBlack = 90,
76 TextBrightRed = 91,
77 TextBrightGreen = 92,
79 TextBrightBlue = 94,
81 TextBrightCyan = 96,
82 TextBrightWhite = 97,
83};
84
85inline std::string ansi_to_string(AnsiCode code)
86{
87 return "\033[" + std::to_string(static_cast<int>(code)) + "m";
88}
89
91{
92 using enum asw::log::Level;
93
94 switch (level) {
95 case Debug:
97 case Info:
99 case Warn:
101 case Error:
103 }
104 return AnsiCode::Reset;
105}
106
107// Local wall clock time with milliseconds. Formatting a system_clock time
108// point directly prints UTC.
109std::string get_timestamp()
110{
111 const auto now = std::chrono::system_clock::now();
112 const std::time_t seconds = std::chrono::system_clock::to_time_t(now);
113 const auto millis
114 = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count()
115 % 1000;
116
117 std::tm local {};
118#ifdef _WIN32
119 localtime_s(&local, &seconds);
120#else
121 localtime_r(&seconds, &local);
122#endif
123
124 std::array<char, 16> clock {};
125 std::strftime(clock.data(), clock.size(), "%H:%M:%S", &local);
126 return std::format("{}.{:03}", clock.data(), millis);
127}
128} // namespace
129
130void asw::log::log_message(asw::log::Level level, const std::string& message)
131{
132 if (level < current_level) {
133 return;
134 }
135
136#ifdef __EMSCRIPTEN__
137 int emLevel = EM_LOG_CONSOLE;
138 switch (level) {
140 emLevel = EM_LOG_CONSOLE;
141 break;
143 emLevel = EM_LOG_CONSOLE;
144 break;
146 emLevel = EM_LOG_WARN;
147 break;
149 emLevel = EM_LOG_ERROR;
150 break;
151 }
152 emscripten_log(
153 emLevel, "[%s] [%s] %s", level_to_string(level), get_timestamp().c_str(), message.c_str());
154#else
155 const std::string reset = ansi_to_string(AnsiCode::Reset);
156 const std::string color = ansi_to_string(level_to_ansi(level));
157 const std::string bold = ansi_to_string(AnsiCode::BoldOn);
158 const std::string faint = ansi_to_string(AnsiCode::Faint);
159
160 // Dim timestamp
161 *output << faint << "[" << get_timestamp() << "]" << reset << " ";
162
163 // Bold + bright colored level badge
164 *output << bold << color << "[" << level_to_string(level) << "]" << reset << " ";
165
166 // Level-colored message
167 *output << color << message << reset << "\n";
168#endif
169}
170
172{
173 current_level = level;
174}
175
176void asw::log::set_output(std::ostream& stream)
177{
178 output = &stream;
179}
180
181void asw::log::debug(const std::string& message)
182{
183 log_message(Level::Debug, message);
184}
185
186void asw::log::info(const std::string& message)
187{
188 log_message(Level::Info, message);
189}
190
191void asw::log::warn(const std::string& message)
192{
193 log_message(Level::Warn, message);
194}
195
196void asw::log::error(const std::string& message)
197{
198 log_message(Level::Error, message);
199}
200
201void asw::log::progress(float progress, std::string message)
202{
203 constexpr int bar_width = 20;
204 const int filled = static_cast<int>(progress * static_cast<float>(bar_width));
205
206 // Build Unicode block bar: █ filled, ░ empty
207 std::string bar;
208 bar.reserve(bar_width * 3);
209 for (int i = 0; i < bar_width; ++i) {
210 bar += (i < filled) ? "█" : "░";
211 }
212
213 const std::string progress_message
214 = std::format("[{}] {:>3}% {}", bar, static_cast<int>(progress * 100.0f), message);
215 log_message(Level::Info, progress_message);
216}
Structured logging system.
const char * level_to_string(asw::log::Level level)
Definition log.cpp:15
AnsiCode level_to_ansi(asw::log::Level level)
Definition log.cpp:90
AnsiCode
ANSI escape codes for terminal formatting.
Definition log.cpp:33
asw::log::Level current_level
Definition log.cpp:12
std::string get_timestamp()
Definition log.cpp:109
std::ostream * output
Definition log.cpp:13
std::string ansi_to_string(AnsiCode code)
Definition log.cpp:85
void set_output(std::ostream &stream)
Set the output stream (default: std::cerr).
Definition log.cpp:176
void info(const std::string &message)
Log an info message.
Definition log.cpp:186
void debug(const std::string &message)
Log a debug message.
Definition log.cpp:181
void log_message(Level level, const std::string &message)
Log a message at the specified level. Messages below the current log level are ignored.
Definition log.cpp:130
void error(const std::string &message)
Log an error message.
Definition log.cpp:196
void warn(const std::string &message)
Log a warning message.
Definition log.cpp:191
Level
Log severity levels.
Definition log.h:19
void progress(float progress, std::string message)
Log a progress message with a percentage.
Definition log.cpp:201
void set_level(Level level)
Set the minimum log level (messages below this are ignored).
Definition log.cpp:171