power_play/src/log.c

197 lines
4.3 KiB
C

#include "log.h"
#include "scratch.h"
#include "string.h"
#include "app.h"
struct log_event_callback {
log_event_callback_func *func;
i32 level;
struct log_event_callback *next;
};
/* ========================== *
* Global state
* ========================== */
GLOBAL struct {
struct sys_mutex mutex;
struct arena arena;
log_event_callback_func *callbacks_head;
struct sys_file file;
b32 file_valid;
} L = { 0 }, DEBUG_LVAR(L_log);
GLOBAL READONLY const struct log_level_settings g_log_level_settings[LOG_LEVEL_COUNT] = {
[LOG_LEVEL_CRITICAL] = {
STR_NOCAST("CRITICAL"),
0xFFFF00FF
},
[LOG_LEVEL_ERROR] = {
STR_NOCAST("ERROR"),
0xFFFF0000
},
[LOG_LEVEL_WARNING] = {
STR_NOCAST("WARNING"),
0xFFFFFF00
},
[LOG_LEVEL_INFO] = {
STR_NOCAST("INFO"),
0xFFFFFFFF
},
[LOG_LEVEL_DEBUG] = {
STR_NOCAST("DEBUG"),
0xFF30D5C8
}
};
/* ========================== *
* Startup
* ========================== */
void log_startup(struct string logfile_path)
{
L.mutex = sys_mutex_alloc();
L.arena = arena_alloc(GIGABYTE(64));
if (logfile_path.len > 0) {
/* Create / wipe log file */
sys_file_close(sys_file_open_write(logfile_path));
/* Keep log file open for appending */
if (sys_is_file(logfile_path)) {
L.file = sys_file_open_append(logfile_path);
L.file_valid = true;
}
}
}
/* ========================== *
* Callback
* ========================== */
void log_register_callback(log_event_callback_func *func)
{
sys_mutex_lock(&L.mutex);
(UNUSED)func;
sys_mutex_unlock(&L.mutex);
}
/* ========================== *
* Log
* ========================== */
INTERNAL void append_to_logfile(struct string msg)
{
__prof;
if (L.file_valid) {
struct temp_arena scratch = scratch_begin_no_conflict();
struct string msg_line = string_cat(scratch.arena, msg, STR("\n"));
sys_file_write(L.file, BUFFER_FROM_STRING(msg_line));
scratch_end(scratch);
}
}
#if LOG_INCLUDE_SOURCE_LOCATION
void _log(i32 level, struct string file, u32 line, struct string msg)
#else
void _log(i32 level, struct string msg)
#endif
{
__prof;
if (level < 0 || level >= LOG_LEVEL_COUNT) {
sys_panic(STR("Invalid log level"));
}
struct temp_arena scratch = scratch_begin_no_conflict();
struct sys_local_time_info lt = sys_local_time();
u32 tid = sys_thread_id();
struct log_level_settings settings = g_log_level_settings[level];
struct string shorthand = settings.shorthand;
#if LOG_INCLUDE_SOURCE_LOCATION
struct string msg_formatted = string_format(
scratch.arena,
STR("%F:%F:%F |Thread %F| [%F] <%F:%F> %F"),
/* Time */
FMT_UINT(lt.hour),
FMT_UINT(lt.minute),
FMT_UINT(lt.second),
/* TID */
FMT_UINT(tid),
/* Level */
FMT_STR(shorthand),
/* Source location */
FMT_STR(file),
FMT_SINT(line),
/* Message */
FMT_STR(msg)
);
#else
struct string msg_formatted = string_format(
scratch.arena,
STR("%F:%F:%F |Thread %F| [%F] %F"),
/* Time */
FMT_UINT(lt.hour),
FMT_UINT(lt.minute),
FMT_UINT(lt.second),
/* TID */
FMT_UINT(tid),
/* Level */
FMT_STR(shorthand),
/* Message */
FMT_STR(msg)
);
#endif
__profmsg((char *)msg.text, msg.len, settings.color);
append_to_logfile(msg_formatted);
scratch_end(scratch);
}
#if LOG_INCLUDE_SOURCE_LOCATION
void _logfv(i32 level, struct string file, u32 line, struct string fmt, va_list args)
#else
void _logfv(i32 level, struct string fmt, va_list args)
#endif
{
struct temp_arena scratch = scratch_begin_no_conflict();
struct string msg = string_formatv(scratch.arena, fmt, args);
#if LOG_INCLUDE_SOURCE_LOCATION
_log(level, file, line, msg);
#else
_log(level, msg);
#endif
scratch_end(scratch);
}
#if LOG_INCLUDE_SOURCE_LOCATION
void _logf(i32 level, struct string file, u32 line, struct string fmt, ...)
#else
void _logf(i32 level, struct string fmt, ...)
#endif
{
va_list args;
va_start(args, fmt);
#if LOG_INCLUDE_SOURCE_LOCATION
_logfv(level, file, line, fmt, args);
#else
_logfv(level, fmt, args);
#endif
va_end(args);
}