13#define MAX_CALLBACKS 4
35static const char *
level_strings[] = {
"TRACE",
"DEBUG",
"INFO",
"WARN",
"ERROR",
"FATAL"};
38#define COLOR_TRACE "\x1b[94m"
39#define COLOR_DEBUG "\x1b[36m"
40#define COLOR_INFO "\x1b[32m"
41#define COLOR_WARN "\x1b[33m"
42#define COLOR_ERROR "\x1b[31m"
43#define COLOR_FATAL "\x1b[35m"
44#define COLOR_RESET "\x1b[0m"
52enable_vt_colors(HANDLE handle)
55 if (!GetConsoleMode(handle, &mode))
return 0;
56 return SetConsoleMode(handle, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
59static b32 vt_stdout_enabled = -1;
60static b32 vt_stderr_enabled = -1;
63color_for_stream(
b32 is_stderr,
const char *color)
66 if (vt_stderr_enabled < 0)
67 vt_stderr_enabled = enable_vt_colors(GetStdHandle(STD_ERROR_HANDLE));
68 return vt_stderr_enabled ? color :
"";
70 if (vt_stdout_enabled < 0)
71 vt_stdout_enabled = enable_vt_colors(GetStdHandle(STD_OUTPUT_HANDLE));
72 return vt_stdout_enabled ? color :
"";
77color_for_stream(
b32 is_stderr,
const char *color)
86 {COLOR_TRACE, COLOR_DEBUG, COLOR_INFO, COLOR_WARN, COLOR_ERROR, COLOR_FATAL};
95 L.lock_fn(
L.lock_data, 1);
104 L.lock_fn(
L.lock_data, 0);
115 time_t t = time(NULL);
116 buf[strftime(buf,
sizeof(buf),
"%H:%M:%S", localtime(&t))] =
'\0';
119 FILE *out = is_err ? stderr : stdout;
122 "%s %s%-5s%s \x1b[90m%s:%d:\x1b[0m ",
126 color_for_stream(is_err, COLOR_RESET),
130 vfprintf(out, ev->
fmt, ev->
ap);
141 FILE *fp = (FILE *)user_data;
143 time_t t = time(NULL);
144 buf[strftime(buf,
sizeof(buf),
"%Y-%m-%d %H:%M:%S", localtime(&t))] =
'\0';
147 vfprintf(fp, ev->
fmt, ev->
ap);
168 L.lock_data = user_data;
181 if (
L.callbacks[i].fn == NULL) {
182 L.callbacks[i].fn = fn;
183 L.callbacks[i].user_data = user_data;
184 L.callbacks[i].min_level = min_level;
195 if (
L.callbacks[i].fn == fn) {
196 L.callbacks[i].fn = NULL;
197 L.callbacks[i].user_data = NULL;
198 L.callbacks[i].min_level = 0;
208 if (level <
L.level) {
222 va_start(ev.
ap, fmt);
230 va_start(ev.
ap, fmt);
static BaseLogger L
The single global logger instance state.
static const char * level_strings[]
Human-readable string representations of the log levels.
static void log_stdout(BaseLogEvent *ev)
Formats and writes a log event to standard output or standard error.
static void file_callback(BaseLogEvent *ev, void *user_data)
Default callback used to write log events to a standard C FILE*.
static const char * level_colors[]
Array mapping log levels to their respective ANSI color codes.
static void lock(void)
Acquires the logger lock if a locking function is configured.
static void unlock(void)
Releases the logger lock if a locking function is configured.
#define MAX_CALLBACKS
Maximum number of custom log callbacks supported simultaneously.
Professional, thread-safe, leveled logging system.
b32 base_log_add_fp(FILE *fp, BaseLogLevel min_level)
Adds a standard C FILE* pointer as a logging destination.
void base_log_set_quiet(b32 enable)
Mutes or unmutes all console (stdout/stderr) output.
void base_log_message(BaseLogLevel level, const char *file, int line, const char *fmt,...)
Internal function that actually processes the log. DO NOT call directly.
b32 base_log_remove_callback(BaseLogFn fn)
Removes a previously registered callback from the logger.
void base_log_set_lock(BaseLogLockFn fn, void *user_data)
Configures thread-safety by providing a custom locking mechanism.
void(* BaseLogLockFn)(void *user_data, b32 lock)
Signature for the thread-synchronization callback.
void base_log_set_level(BaseLogLevel level)
Configures the active logging level. Messages below this level are ignored.
b32 base_log_add_callback(BaseLogFn fn, void *user_data, BaseLogLevel min_level)
Adds a custom callback function as a logging destination.
void(* BaseLogFn)(BaseLogEvent *ev, void *user_data)
Signature for custom logging destination callbacks.
BaseLogLevel
The severity level of a log message.
Internal structure to hold a logging callback and its configuration.
A structured event containing all metadata for a single log message.
Internal state structure for the global logger.
BaseLogCallback callbacks[4]